put in ignore file
This commit is contained in:
+28
@@ -1,5 +1,33 @@
|
||||
# See https://docs.github.com/get-started/getting-started-with-git/ignoring-files for more about ignoring files.
|
||||
# User-specific files
|
||||
*.rsuser
|
||||
*.suo
|
||||
*.user
|
||||
*.userosscache
|
||||
*.sln.docstates
|
||||
|
||||
# User-specific files (MonoDevelop/Xamarin Studio)
|
||||
*.userprefs
|
||||
|
||||
# Mono auto generated files
|
||||
mono_crash.*
|
||||
|
||||
# Build results
|
||||
[Dd]ebug/
|
||||
[Dd]ebugPublic/
|
||||
[Rr]elease/
|
||||
[Rr]eleases/
|
||||
x64/
|
||||
x86/
|
||||
[Ww][Ii][Nn]32/
|
||||
[Aa][Rr][Mm]/
|
||||
[Aa][Rr][Mm]64/
|
||||
bld/
|
||||
[Bb]in/
|
||||
[Oo]bj/
|
||||
[Oo]ut/
|
||||
[Ll]og/
|
||||
[Ll]ogs/
|
||||
# Compiled output
|
||||
dist/
|
||||
bin/
|
||||
|
||||
@@ -0,0 +1,30 @@
|
||||
**/.classpath
|
||||
**/.dockerignore
|
||||
**/.env
|
||||
**/.git
|
||||
**/.gitignore
|
||||
**/.project
|
||||
**/.settings
|
||||
**/.toolstarget
|
||||
**/.vs
|
||||
**/.vscode
|
||||
**/*.*proj.user
|
||||
**/*.dbmdl
|
||||
**/*.jfm
|
||||
**/azds.yaml
|
||||
**/bin
|
||||
**/charts
|
||||
**/docker-compose*
|
||||
**/Dockerfile*
|
||||
**/node_modules
|
||||
**/npm-debug.log
|
||||
**/obj
|
||||
**/secrets.dev.yaml
|
||||
**/values.dev.yaml
|
||||
LICENSE
|
||||
README.md
|
||||
!**/.gitignore
|
||||
!.git/HEAD
|
||||
!.git/config
|
||||
!.git/packed-refs
|
||||
!.git/refs/heads/**
|
||||
@@ -0,0 +1,63 @@
|
||||
###############################################################################
|
||||
# Set default behavior to automatically normalize line endings.
|
||||
###############################################################################
|
||||
* text=auto
|
||||
|
||||
###############################################################################
|
||||
# Set default behavior for command prompt diff.
|
||||
#
|
||||
# This is need for earlier builds of msysgit that does not have it on by
|
||||
# default for csharp files.
|
||||
# Note: This is only used by command line
|
||||
###############################################################################
|
||||
#*.cs diff=csharp
|
||||
|
||||
###############################################################################
|
||||
# Set the merge driver for project and solution files
|
||||
#
|
||||
# Merging from the command prompt will add diff markers to the files if there
|
||||
# are conflicts (Merging from VS is not affected by the settings below, in VS
|
||||
# the diff markers are never inserted). Diff markers may cause the following
|
||||
# file extensions to fail to load in VS. An alternative would be to treat
|
||||
# these files as binary and thus will always conflict and require user
|
||||
# intervention with every merge. To do so, just uncomment the entries below
|
||||
###############################################################################
|
||||
#*.sln merge=binary
|
||||
#*.csproj merge=binary
|
||||
#*.vbproj merge=binary
|
||||
#*.vcxproj merge=binary
|
||||
#*.vcproj merge=binary
|
||||
#*.dbproj merge=binary
|
||||
#*.fsproj merge=binary
|
||||
#*.lsproj merge=binary
|
||||
#*.wixproj merge=binary
|
||||
#*.modelproj merge=binary
|
||||
#*.sqlproj merge=binary
|
||||
#*.wwaproj merge=binary
|
||||
|
||||
###############################################################################
|
||||
# behavior for image files
|
||||
#
|
||||
# image files are treated as binary by default.
|
||||
###############################################################################
|
||||
#*.jpg binary
|
||||
#*.png binary
|
||||
#*.gif binary
|
||||
|
||||
###############################################################################
|
||||
# diff behavior for common document formats
|
||||
#
|
||||
# Convert binary document formats to text before diffing them. This feature
|
||||
# is only available from the command line. Turn it on by uncommenting the
|
||||
# entries below.
|
||||
###############################################################################
|
||||
#*.doc diff=astextplain
|
||||
#*.DOC diff=astextplain
|
||||
#*.docx diff=astextplain
|
||||
#*.DOCX diff=astextplain
|
||||
#*.dot diff=astextplain
|
||||
#*.DOT diff=astextplain
|
||||
#*.pdf diff=astextplain
|
||||
#*.PDF diff=astextplain
|
||||
#*.rtf diff=astextplain
|
||||
#*.RTF diff=astextplain
|
||||
+363
@@ -0,0 +1,363 @@
|
||||
## Ignore Visual Studio temporary files, build results, and
|
||||
## files generated by popular Visual Studio add-ons.
|
||||
##
|
||||
## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore
|
||||
|
||||
# User-specific files
|
||||
*.rsuser
|
||||
*.suo
|
||||
*.user
|
||||
*.userosscache
|
||||
*.sln.docstates
|
||||
|
||||
# User-specific files (MonoDevelop/Xamarin Studio)
|
||||
*.userprefs
|
||||
|
||||
# Mono auto generated files
|
||||
mono_crash.*
|
||||
|
||||
# Build results
|
||||
[Dd]ebug/
|
||||
[Dd]ebugPublic/
|
||||
[Rr]elease/
|
||||
[Rr]eleases/
|
||||
x64/
|
||||
x86/
|
||||
[Ww][Ii][Nn]32/
|
||||
[Aa][Rr][Mm]/
|
||||
[Aa][Rr][Mm]64/
|
||||
bld/
|
||||
[Bb]in/
|
||||
[Oo]bj/
|
||||
[Oo]ut/
|
||||
[Ll]og/
|
||||
[Ll]ogs/
|
||||
|
||||
# Visual Studio 2015/2017 cache/options directory
|
||||
.vs/
|
||||
# Uncomment if you have tasks that create the project's static files in wwwroot
|
||||
#wwwroot/
|
||||
|
||||
# Visual Studio 2017 auto generated files
|
||||
Generated\ Files/
|
||||
|
||||
# MSTest test Results
|
||||
[Tt]est[Rr]esult*/
|
||||
[Bb]uild[Ll]og.*
|
||||
|
||||
# NUnit
|
||||
*.VisualState.xml
|
||||
TestResult.xml
|
||||
nunit-*.xml
|
||||
|
||||
# Build Results of an ATL Project
|
||||
[Dd]ebugPS/
|
||||
[Rr]eleasePS/
|
||||
dlldata.c
|
||||
|
||||
# Benchmark Results
|
||||
BenchmarkDotNet.Artifacts/
|
||||
|
||||
# .NET Core
|
||||
project.lock.json
|
||||
project.fragment.lock.json
|
||||
artifacts/
|
||||
|
||||
# ASP.NET Scaffolding
|
||||
ScaffoldingReadMe.txt
|
||||
|
||||
# StyleCop
|
||||
StyleCopReport.xml
|
||||
|
||||
# Files built by Visual Studio
|
||||
*_i.c
|
||||
*_p.c
|
||||
*_h.h
|
||||
*.ilk
|
||||
*.meta
|
||||
*.obj
|
||||
*.iobj
|
||||
*.pch
|
||||
*.pdb
|
||||
*.ipdb
|
||||
*.pgc
|
||||
*.pgd
|
||||
*.rsp
|
||||
*.sbr
|
||||
*.tlb
|
||||
*.tli
|
||||
*.tlh
|
||||
*.tmp
|
||||
*.tmp_proj
|
||||
*_wpftmp.csproj
|
||||
*.log
|
||||
*.vspscc
|
||||
*.vssscc
|
||||
.builds
|
||||
*.pidb
|
||||
*.svclog
|
||||
*.scc
|
||||
|
||||
# Chutzpah Test files
|
||||
_Chutzpah*
|
||||
|
||||
# Visual C++ cache files
|
||||
ipch/
|
||||
*.aps
|
||||
*.ncb
|
||||
*.opendb
|
||||
*.opensdf
|
||||
*.sdf
|
||||
*.cachefile
|
||||
*.VC.db
|
||||
*.VC.VC.opendb
|
||||
|
||||
# Visual Studio profiler
|
||||
*.psess
|
||||
*.vsp
|
||||
*.vspx
|
||||
*.sap
|
||||
|
||||
# Visual Studio Trace Files
|
||||
*.e2e
|
||||
|
||||
# TFS 2012 Local Workspace
|
||||
$tf/
|
||||
|
||||
# Guidance Automation Toolkit
|
||||
*.gpState
|
||||
|
||||
# ReSharper is a .NET coding add-in
|
||||
_ReSharper*/
|
||||
*.[Rr]e[Ss]harper
|
||||
*.DotSettings.user
|
||||
|
||||
# TeamCity is a build add-in
|
||||
_TeamCity*
|
||||
|
||||
# DotCover is a Code Coverage Tool
|
||||
*.dotCover
|
||||
|
||||
# AxoCover is a Code Coverage Tool
|
||||
.axoCover/*
|
||||
!.axoCover/settings.json
|
||||
|
||||
# Coverlet is a free, cross platform Code Coverage Tool
|
||||
coverage*.json
|
||||
coverage*.xml
|
||||
coverage*.info
|
||||
|
||||
# Visual Studio code coverage results
|
||||
*.coverage
|
||||
*.coveragexml
|
||||
|
||||
# NCrunch
|
||||
_NCrunch_*
|
||||
.*crunch*.local.xml
|
||||
nCrunchTemp_*
|
||||
|
||||
# MightyMoose
|
||||
*.mm.*
|
||||
AutoTest.Net/
|
||||
|
||||
# Web workbench (sass)
|
||||
.sass-cache/
|
||||
|
||||
# Installshield output folder
|
||||
[Ee]xpress/
|
||||
|
||||
# DocProject is a documentation generator add-in
|
||||
DocProject/buildhelp/
|
||||
DocProject/Help/*.HxT
|
||||
DocProject/Help/*.HxC
|
||||
DocProject/Help/*.hhc
|
||||
DocProject/Help/*.hhk
|
||||
DocProject/Help/*.hhp
|
||||
DocProject/Help/Html2
|
||||
DocProject/Help/html
|
||||
|
||||
# Click-Once directory
|
||||
publish/
|
||||
|
||||
# Publish Web Output
|
||||
*.[Pp]ublish.xml
|
||||
*.azurePubxml
|
||||
# Note: Comment the next line if you want to checkin your web deploy settings,
|
||||
# but database connection strings (with potential passwords) will be unencrypted
|
||||
*.pubxml
|
||||
*.publishproj
|
||||
|
||||
# Microsoft Azure Web App publish settings. Comment the next line if you want to
|
||||
# checkin your Azure Web App publish settings, but sensitive information contained
|
||||
# in these scripts will be unencrypted
|
||||
PublishScripts/
|
||||
|
||||
# NuGet Packages
|
||||
*.nupkg
|
||||
# NuGet Symbol Packages
|
||||
*.snupkg
|
||||
# The packages folder can be ignored because of Package Restore
|
||||
**/[Pp]ackages/*
|
||||
# except build/, which is used as an MSBuild target.
|
||||
!**/[Pp]ackages/build/
|
||||
# Uncomment if necessary however generally it will be regenerated when needed
|
||||
#!**/[Pp]ackages/repositories.config
|
||||
# NuGet v3's project.json files produces more ignorable files
|
||||
*.nuget.props
|
||||
*.nuget.targets
|
||||
|
||||
# Microsoft Azure Build Output
|
||||
csx/
|
||||
*.build.csdef
|
||||
|
||||
# Microsoft Azure Emulator
|
||||
ecf/
|
||||
rcf/
|
||||
|
||||
# Windows Store app package directories and files
|
||||
AppPackages/
|
||||
BundleArtifacts/
|
||||
Package.StoreAssociation.xml
|
||||
_pkginfo.txt
|
||||
*.appx
|
||||
*.appxbundle
|
||||
*.appxupload
|
||||
|
||||
# Visual Studio cache files
|
||||
# files ending in .cache can be ignored
|
||||
*.[Cc]ache
|
||||
# but keep track of directories ending in .cache
|
||||
!?*.[Cc]ache/
|
||||
|
||||
# Others
|
||||
ClientBin/
|
||||
~$*
|
||||
*~
|
||||
*.dbmdl
|
||||
*.dbproj.schemaview
|
||||
*.jfm
|
||||
*.pfx
|
||||
*.publishsettings
|
||||
orleans.codegen.cs
|
||||
|
||||
# Including strong name files can present a security risk
|
||||
# (https://github.com/github/gitignore/pull/2483#issue-259490424)
|
||||
#*.snk
|
||||
|
||||
# Since there are multiple workflows, uncomment next line to ignore bower_components
|
||||
# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)
|
||||
#bower_components/
|
||||
|
||||
# RIA/Silverlight projects
|
||||
Generated_Code/
|
||||
|
||||
# Backup & report files from converting an old project file
|
||||
# to a newer Visual Studio version. Backup files are not needed,
|
||||
# because we have git ;-)
|
||||
_UpgradeReport_Files/
|
||||
Backup*/
|
||||
UpgradeLog*.XML
|
||||
UpgradeLog*.htm
|
||||
ServiceFabricBackup/
|
||||
*.rptproj.bak
|
||||
|
||||
# SQL Server files
|
||||
*.mdf
|
||||
*.ldf
|
||||
*.ndf
|
||||
|
||||
# Business Intelligence projects
|
||||
*.rdl.data
|
||||
*.bim.layout
|
||||
*.bim_*.settings
|
||||
*.rptproj.rsuser
|
||||
*- [Bb]ackup.rdl
|
||||
*- [Bb]ackup ([0-9]).rdl
|
||||
*- [Bb]ackup ([0-9][0-9]).rdl
|
||||
|
||||
# Microsoft Fakes
|
||||
FakesAssemblies/
|
||||
|
||||
# GhostDoc plugin setting file
|
||||
*.GhostDoc.xml
|
||||
|
||||
# Node.js Tools for Visual Studio
|
||||
.ntvs_analysis.dat
|
||||
node_modules/
|
||||
|
||||
# Visual Studio 6 build log
|
||||
*.plg
|
||||
|
||||
# Visual Studio 6 workspace options file
|
||||
*.opt
|
||||
|
||||
# Visual Studio 6 auto-generated workspace file (contains which files were open etc.)
|
||||
*.vbw
|
||||
|
||||
# Visual Studio LightSwitch build output
|
||||
**/*.HTMLClient/GeneratedArtifacts
|
||||
**/*.DesktopClient/GeneratedArtifacts
|
||||
**/*.DesktopClient/ModelManifest.xml
|
||||
**/*.Server/GeneratedArtifacts
|
||||
**/*.Server/ModelManifest.xml
|
||||
_Pvt_Extensions
|
||||
|
||||
# Paket dependency manager
|
||||
.paket/paket.exe
|
||||
paket-files/
|
||||
|
||||
# FAKE - F# Make
|
||||
.fake/
|
||||
|
||||
# CodeRush personal settings
|
||||
.cr/personal
|
||||
|
||||
# Python Tools for Visual Studio (PTVS)
|
||||
__pycache__/
|
||||
*.pyc
|
||||
|
||||
# Cake - Uncomment if you are using it
|
||||
# tools/**
|
||||
# !tools/packages.config
|
||||
|
||||
# Tabs Studio
|
||||
*.tss
|
||||
|
||||
# Telerik's JustMock configuration file
|
||||
*.jmconfig
|
||||
|
||||
# BizTalk build output
|
||||
*.btp.cs
|
||||
*.btm.cs
|
||||
*.odx.cs
|
||||
*.xsd.cs
|
||||
|
||||
# OpenCover UI analysis results
|
||||
OpenCover/
|
||||
|
||||
# Azure Stream Analytics local run output
|
||||
ASALocalRun/
|
||||
|
||||
# MSBuild Binary and Structured Log
|
||||
*.binlog
|
||||
|
||||
# NVidia Nsight GPU debugger configuration file
|
||||
*.nvuser
|
||||
|
||||
# MFractors (Xamarin productivity tool) working folder
|
||||
.mfractor/
|
||||
|
||||
# Local History for Visual Studio
|
||||
.localhistory/
|
||||
|
||||
# BeatPulse healthcheck temp database
|
||||
healthchecksdb
|
||||
|
||||
# Backup folder for Package Reference Convert tool in Visual Studio 2017
|
||||
MigrationBackup/
|
||||
|
||||
# Ionide (cross platform F# VS Code tools) working folder
|
||||
.ionide/
|
||||
|
||||
# Fody - auto-generated XML schema
|
||||
FodyWeavers.xsd
|
||||
@@ -0,0 +1,31 @@
|
||||
|
||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
# Visual Studio Version 17
|
||||
VisualStudioVersion = 17.7.34202.233
|
||||
MinimumVisualStudioVersion = 10.0.40219.1
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "FamilyTreeAPI", "FamilyTreeAPI\FamilyTreeAPI.csproj", "{9B95839F-8AE3-4725-BCC1-DC73D1899CC6}"
|
||||
EndProject
|
||||
Project("{E53339B2-1760-4266-BCC7-CA923CBCF16C}") = "docker-compose", "docker-compose.dcproj", "{81DDED9D-158B-E303-5F62-77A2896D2A5A}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
Release|Any CPU = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{9B95839F-8AE3-4725-BCC1-DC73D1899CC6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{9B95839F-8AE3-4725-BCC1-DC73D1899CC6}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{9B95839F-8AE3-4725-BCC1-DC73D1899CC6}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{9B95839F-8AE3-4725-BCC1-DC73D1899CC6}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{81DDED9D-158B-E303-5F62-77A2896D2A5A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{81DDED9D-158B-E303-5F62-77A2896D2A5A}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{81DDED9D-158B-E303-5F62-77A2896D2A5A}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{81DDED9D-158B-E303-5F62-77A2896D2A5A}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
EndGlobalSection
|
||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||
SolutionGuid = {C7DF2338-DFC8-47CE-9AA7-C05C3C2ABEF7}
|
||||
EndGlobalSection
|
||||
EndGlobal
|
||||
@@ -0,0 +1,7 @@
|
||||
using System;
|
||||
|
||||
namespace FamilyTreeAPI.Authorization;
|
||||
|
||||
[AttributeUsage(AttributeTargets.Method)]
|
||||
public class AllowAnonymousAttribute : Attribute
|
||||
{ }
|
||||
@@ -0,0 +1,36 @@
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.AspNetCore.Mvc.Filters;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
|
||||
namespace FamilyTreeAPI.Authorization;
|
||||
|
||||
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method)]
|
||||
public class AuthorizeAttribute : Attribute, IAuthorizationFilter
|
||||
{
|
||||
// private readonly IList<AdminRole> _roles;
|
||||
/*
|
||||
public AuthorizeAttribute(params AdminRole[] roles)
|
||||
{
|
||||
_roles = roles ?? new AdminRole[] { };
|
||||
}
|
||||
*/
|
||||
public void OnAuthorization(AuthorizationFilterContext context)
|
||||
{
|
||||
// skip authorization if action is decorated with [AllowAnonymous] attribute
|
||||
var allowAnonymous = context.ActionDescriptor.EndpointMetadata.OfType<AllowAnonymousAttribute>().Any();
|
||||
if (allowAnonymous)
|
||||
return;
|
||||
|
||||
// authorization
|
||||
// var user = (User)context.HttpContext.Items["User"];
|
||||
// if (user == null || (_roles.Any() && !_roles.Contains(user.Role)))
|
||||
// {
|
||||
// not logged in or role not authorized
|
||||
// context.Result = new JsonResult(new { message = "Unauthorized" }) { StatusCode = StatusCodes.Status401Unauthorized };
|
||||
//}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.Extensions.Options;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
using FamilyTreeAPI.Interface;
|
||||
using FamilyTreeAPI.Entities;
|
||||
|
||||
namespace FamilyTreeAPI.Authorization;
|
||||
|
||||
public class JwtMiddleware
|
||||
{
|
||||
private readonly RequestDelegate _next;
|
||||
private readonly AppSettings _appSettings;
|
||||
|
||||
public JwtMiddleware(RequestDelegate next, IOptions<AppSettings> appSettings)
|
||||
{
|
||||
_next = next;
|
||||
_appSettings = appSettings.Value;
|
||||
}
|
||||
|
||||
public async Task Invoke(HttpContext context, IJwtUtils jwtUtils)
|
||||
{
|
||||
var token = context.Request.Headers["Authorization"].FirstOrDefault()?.Split(" ").Last();
|
||||
if (token != null)
|
||||
{
|
||||
var user = jwtUtils.ValidateJwtToken(token);
|
||||
if (user != null)
|
||||
{
|
||||
// attach user to context on successful jwt validation
|
||||
//here to put in the real user
|
||||
//TODO if you want to add information for User
|
||||
context.Items["User"] = user;
|
||||
}
|
||||
}
|
||||
await _next(context);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,111 @@
|
||||
using Microsoft.Extensions.Options;
|
||||
using Microsoft.IdentityModel.Tokens;
|
||||
using System;
|
||||
using System.IdentityModel.Tokens.Jwt;
|
||||
using System.Linq;
|
||||
using System.Security.Claims;
|
||||
using System.Text;
|
||||
using FamilyTreeAPI.Entities;
|
||||
using FamilyTreeAPI.Interface;
|
||||
|
||||
namespace FamilyTreeAPI.Authorization;
|
||||
|
||||
|
||||
public class JwtUtils : IJwtUtils
|
||||
{
|
||||
private readonly AppSettings _appSettings;
|
||||
|
||||
public JwtUtils(IOptions<AppSettings> appSettings)
|
||||
{
|
||||
_appSettings = appSettings.Value;
|
||||
}
|
||||
|
||||
public string GenerateJwtToken(UserDto user)
|
||||
{
|
||||
// generate token that is valid for 2 days
|
||||
var tokenHandler = new JwtSecurityTokenHandler();
|
||||
var key = Encoding.ASCII.GetBytes(_appSettings.Secret);
|
||||
var tokenDescriptor = new SecurityTokenDescriptor
|
||||
{
|
||||
Subject = new ClaimsIdentity(new[] {
|
||||
new Claim("id", user.Id.ToString()),
|
||||
new Claim("subject", user.Username),
|
||||
new Claim("firstName", user.FirstName + " " + user.LastName)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
//add more if we need it
|
||||
}
|
||||
),
|
||||
Expires = DateTime.UtcNow.AddDays(2),
|
||||
SigningCredentials = new SigningCredentials(new SymmetricSecurityKey(key), SecurityAlgorithms.HmacSha256Signature)
|
||||
};
|
||||
var token = tokenHandler.CreateToken(tokenDescriptor);
|
||||
return tokenHandler.WriteToken(token);
|
||||
}
|
||||
// get back id and username. in subject
|
||||
public UserDto? ValidateJwtToken(string token)
|
||||
{
|
||||
if (token == null)
|
||||
return null;
|
||||
|
||||
var tokenHandler = new JwtSecurityTokenHandler();
|
||||
var key = Encoding.ASCII.GetBytes(_appSettings.Secret);
|
||||
try
|
||||
{
|
||||
tokenHandler.ValidateToken(token, new TokenValidationParameters
|
||||
{
|
||||
ValidateIssuerSigningKey = true,
|
||||
IssuerSigningKey = new SymmetricSecurityKey(key),
|
||||
ValidateIssuer = false,
|
||||
ValidateAudience = false,
|
||||
// set clockskew to zero so tokens expire exactly at token expiration time (instead of 5 minutes later)
|
||||
ClockSkew = TimeSpan.Zero
|
||||
}, out SecurityToken validatedToken);
|
||||
|
||||
var jwtToken = (JwtSecurityToken)validatedToken;
|
||||
// var userId = int.Parse(jwtToken.Claims.First(x => x.Type == "id").Value); //old
|
||||
int userId = 0;
|
||||
string username = "";
|
||||
string firstName = "";
|
||||
Claim claim;
|
||||
for (int i = 0; i< jwtToken.Claims.Count(); i++)
|
||||
{
|
||||
claim = jwtToken.Claims.ElementAt(i);
|
||||
if (claim.Type == "id")
|
||||
{
|
||||
userId = int.Parse(claim.Value);
|
||||
}
|
||||
else if (claim.Type == "subject")
|
||||
{
|
||||
username = claim.Value;
|
||||
}
|
||||
else if (claim.Type == "firstName")
|
||||
{
|
||||
firstName = claim.Value;
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(username)
|
||||
&& !string.IsNullOrEmpty(firstName)
|
||||
&& userId > 0)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
UserDto user = new UserDto();
|
||||
user.Id = userId;
|
||||
user.Username = username;
|
||||
user.FirstName = firstName;
|
||||
|
||||
// return user id from JWT token if validation successful
|
||||
return user;
|
||||
}
|
||||
catch
|
||||
{
|
||||
// return null if validation fails
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,68 @@
|
||||
using FamilyTreeAPI.Entities;
|
||||
using FamilyTreeAPI.Interface;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
|
||||
namespace FamilyTreeAPI.Controllers
|
||||
{
|
||||
[Route("api/[controller]")]
|
||||
[ApiController]
|
||||
public class LookupController : ControllerBase
|
||||
{
|
||||
private readonly ILookup _repo;
|
||||
public LookupController(ILookup repo)
|
||||
{
|
||||
_repo = repo;
|
||||
}
|
||||
[HttpGet("[action]")]
|
||||
public async Task<IActionResult> LoadLookup(string type)
|
||||
{
|
||||
var list = await _repo.GetLookupAsync(type);
|
||||
|
||||
return Ok(list);
|
||||
}
|
||||
[HttpGet("[action]")]
|
||||
public async Task<IActionResult> LoadLookupEdit(string type)
|
||||
{
|
||||
var list = await _repo.GetLookupEditAsync(type);
|
||||
return Ok(list);
|
||||
}
|
||||
[HttpGet("[action]")]
|
||||
public async Task<IActionResult> GetPersons()
|
||||
{
|
||||
var list = await _repo.GetPersonsAsync();
|
||||
return Ok(list);
|
||||
}
|
||||
[HttpGet("[action]")]
|
||||
public async Task<IActionResult> GetStaffs()
|
||||
{
|
||||
var list = await _repo.GetStaffAsync();
|
||||
return Ok(list);
|
||||
}
|
||||
|
||||
[HttpPost]
|
||||
public async Task<IActionResult> Lookup([FromBody] LookupEditDto model)
|
||||
{
|
||||
//var currentUser = (User?)(HttpContext.Items["User"]);
|
||||
//if (null == currentUser)
|
||||
// return Unauthorized(new { message = "Unauthorized" });
|
||||
|
||||
var response = await _repo.SaveLookupAsync(model);
|
||||
|
||||
return Ok(response);
|
||||
}
|
||||
|
||||
[HttpGet]
|
||||
public async Task<IActionResult> Lookup(int id, string type)
|
||||
{
|
||||
//lookup/id?type='abc'
|
||||
/*
|
||||
// only admins can access other user records
|
||||
var currentUser = (User)HttpContext.Items["User"];
|
||||
if (id != currentUser.Id && currentUser.Role != Role.Admin)
|
||||
return Unauthorized(new { message = "Unauthorized" });
|
||||
*/
|
||||
var retval = await _repo.GetLookupEditByIdAsync(id, type);
|
||||
return Ok(retval);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,110 @@
|
||||
using FamilyTreeAPI.Entities;
|
||||
using FamilyTreeAPI.Interface;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.Extensions.Primitives;
|
||||
|
||||
namespace FamilyTreeAPI.Controllers
|
||||
{
|
||||
[Route("api/[controller]")]
|
||||
[ApiController]
|
||||
public class PersonController : ControllerBase
|
||||
{
|
||||
private readonly IPerson _repo;
|
||||
public PersonController(IPerson repo)
|
||||
{
|
||||
_repo = repo;
|
||||
}
|
||||
[HttpPost("[action]")]
|
||||
public async Task<IActionResult> UploadImage(IFormFile file)
|
||||
{
|
||||
var keys = Request.Form;
|
||||
var files = Request.Form.Files;
|
||||
ResultModel<string> ret = new();
|
||||
if (files.Count > 0)
|
||||
{
|
||||
StringValues familyId = "";
|
||||
|
||||
keys.TryGetValue("familyId", out familyId);
|
||||
|
||||
UploadCriteria criteria = new();
|
||||
criteria.File = file;
|
||||
criteria.FamilyId = familyId;
|
||||
|
||||
criteria.FileName = file.FileName;
|
||||
|
||||
ret = await _repo.UploadImage(criteria);
|
||||
}
|
||||
return Ok(ret);
|
||||
|
||||
|
||||
}
|
||||
//DeleteUploadFile
|
||||
[HttpPost("[action]")]
|
||||
public ActionResult DeleteUploadFile(DeleteFileCriteria criteria)
|
||||
{
|
||||
|
||||
ResultModel<int> ret = new();
|
||||
if (!string.IsNullOrEmpty(criteria.Filename))
|
||||
{
|
||||
|
||||
ret = _repo.DeleteUploadFile(criteria);
|
||||
}
|
||||
return Ok(ret);
|
||||
}
|
||||
|
||||
[HttpPost("[action]")]
|
||||
public async Task<IActionResult> SearchPerson(PersonCriteria criteria)
|
||||
{
|
||||
var list = await _repo.GetPerson(criteria);
|
||||
|
||||
return Ok(list);
|
||||
}
|
||||
|
||||
[HttpPost("[action]")]
|
||||
public async Task<IActionResult> GetChildress(ChildCriteria criteria)
|
||||
{
|
||||
var list = await _repo.GetChildren(criteria);
|
||||
|
||||
return Ok(list);
|
||||
}
|
||||
[HttpPost("[action]")]
|
||||
public async Task<IActionResult> GetFamilyTreeBy(FamilyCriteria criteria)
|
||||
{
|
||||
var list = await _repo.GetFamilyTreeBy(criteria);
|
||||
return Ok(list);
|
||||
}
|
||||
[HttpGet("[action]/{id}")]
|
||||
public async Task<IActionResult> GetByPersonFamily(int id)
|
||||
{
|
||||
var list = await _repo.GetByFamilyAsync(id);
|
||||
return Ok(list);
|
||||
}
|
||||
[HttpGet("[action]/{id}")]
|
||||
public async Task<IActionResult> GetById(int id)
|
||||
{
|
||||
var list = await _repo.GetByIdAsync(id);
|
||||
return Ok(list);
|
||||
}
|
||||
|
||||
[HttpPost("[action]")]
|
||||
public async Task<IActionResult> DeleteById(DeleteCriteria<int> criteria)
|
||||
{
|
||||
var list = await _repo.DeleteAsync(criteria.Id);
|
||||
return Ok(list);
|
||||
}
|
||||
|
||||
[HttpPost("[action]")]
|
||||
public async Task<IActionResult> SavePerson([FromBody] PersonForSave model)
|
||||
{
|
||||
//var currentUser = (User?)(HttpContext.Items["User"]);
|
||||
//if (null == currentUser)
|
||||
// return Unauthorized(new { message = "Unauthorized" });
|
||||
|
||||
var response = await _repo.SaveAsync(model);
|
||||
|
||||
return Ok(response);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
using FamilyTreeAPI.Entities;
|
||||
using FamilyTreeAPI.Interface;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.Extensions.Primitives;
|
||||
|
||||
namespace FamilyTreeAPI.Controllers;
|
||||
|
||||
[Route("api/[controller]")]
|
||||
[ApiController]
|
||||
public class RelationShipController : ControllerBase
|
||||
{
|
||||
private readonly IRelationShipd _repo;
|
||||
public RelationShipController(IRelationShipd repo)
|
||||
{
|
||||
_repo = repo;
|
||||
}
|
||||
[HttpGet("[action]/{id}")]
|
||||
public async Task<IActionResult> GetById(int id)
|
||||
{
|
||||
var list = await _repo.GetByIdAsync(id);
|
||||
return Ok(list);
|
||||
}
|
||||
[HttpGet("[action]/{id}")]
|
||||
public async Task<IActionResult> GetByPersonId(int id)
|
||||
{
|
||||
var list = await _repo.GetByPersonIdAsync(id);
|
||||
return Ok(list);
|
||||
}
|
||||
|
||||
[HttpPost("[action]/{id}")]
|
||||
public async Task<IActionResult> DeleteById(int id)
|
||||
{
|
||||
var list = await _repo.GetByIdAsync(id);
|
||||
return Ok(list);
|
||||
}
|
||||
[HttpPost("[action]")]
|
||||
public async Task<IActionResult> SaveRelationShip([FromBody] RelationShiftContainer list)
|
||||
{
|
||||
//var currentUser = (User?)(HttpContext.Items["User"]);
|
||||
//if (null == currentUser)
|
||||
// return Unauthorized(new { message = "Unauthorized" });
|
||||
|
||||
var response = await _repo.SaveAsync(list.relationShips);
|
||||
|
||||
return Ok(response);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,71 @@
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using FamilyTreeAPI.Entities;
|
||||
using FamilyTreeAPI.Interface;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace FamilyTreeAPI.Controllers;
|
||||
|
||||
// [Authorize]
|
||||
[ApiController]
|
||||
[Route("api/[controller]")]
|
||||
public class StaffController : ControllerBase
|
||||
{
|
||||
private readonly IStaff _staff;
|
||||
public StaffController(IStaff staff)
|
||||
{
|
||||
_staff = staff;
|
||||
}
|
||||
|
||||
[HttpPost("[action]")]
|
||||
public async Task<IActionResult> SaveStaff([FromBody] StaffDto model)
|
||||
{
|
||||
//var currentUser = (User?)HttpContext.Items["User"];
|
||||
//if (null == currentUser)
|
||||
// return Unauthorized(new { message = "Unauthorized" });
|
||||
|
||||
var response = await _staff.SaveStaff(model);
|
||||
return Ok(response);
|
||||
}
|
||||
|
||||
[HttpPost("[action]")]
|
||||
public async Task<IActionResult> ResetPassStaff([FromBody] ResetPassDto model)
|
||||
{
|
||||
//var currentUser = (User?)HttpContext.Items["User"];
|
||||
//if (null == currentUser)
|
||||
// return Unauthorized(new { message = "Unauthorized" });
|
||||
|
||||
var response = await _staff.ResetPassword(model);
|
||||
return Ok(response);
|
||||
}
|
||||
|
||||
[HttpPost("[action]")]
|
||||
public async Task<IActionResult> SearchStaff([FromBody] StaffCriteria criteria)
|
||||
{
|
||||
|
||||
var retval = await _staff.GetStaff(criteria);
|
||||
return Ok(retval);
|
||||
}
|
||||
|
||||
[HttpGet("{id}")]
|
||||
public async Task<IActionResult> Staff( int id)
|
||||
{
|
||||
/*
|
||||
// only admins can access other user records
|
||||
var currentUser = (User)HttpContext.Items["User"];
|
||||
if (id != currentUser.Id && currentUser.Role != Role.Admin)
|
||||
return Unauthorized(new { message = "Unauthorized" });
|
||||
*/
|
||||
var retval = await _staff.GetStaffById(id);
|
||||
return Ok(retval);
|
||||
}
|
||||
[HttpPost("[action]")]
|
||||
public async Task<IActionResult> DeleteStaff(DeleteCriteria<int> criteria)
|
||||
{
|
||||
var currentUser = (UserDto?)HttpContext.Items["User"];
|
||||
if (null == currentUser)
|
||||
return Unauthorized(new { message = "Unauthorized" });
|
||||
|
||||
var retval = await _staff.Delete(criteria.Id);
|
||||
return Ok(retval);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,73 @@
|
||||
using FamilyTreeAPI.Interface;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using FamilyTreeAPI.Entities;
|
||||
namespace FamilyTreeAPI.Controllers;
|
||||
|
||||
[Authorize]
|
||||
[ApiController]
|
||||
[Route("api/[controller]")]
|
||||
public class UsersController : ControllerBase
|
||||
{
|
||||
private readonly IUserService _userService;
|
||||
|
||||
public UsersController(IUserService userService)
|
||||
{
|
||||
_userService = userService;
|
||||
}
|
||||
|
||||
[AllowAnonymous]
|
||||
[HttpPost("[action]")]
|
||||
public async Task<IActionResult> Login([FromBody] AuthenticateRequest model)
|
||||
{
|
||||
string remoteIpAddress = HttpContext.Connection.RemoteIpAddress?.ToString();
|
||||
var response = await _userService.Login(model);
|
||||
return Ok(response);
|
||||
}
|
||||
|
||||
//[AllowAnonymous]
|
||||
//[HttpPost("[action]")]
|
||||
//public async Task<IActionResult> LoginAD(AuthenticateRequest model)
|
||||
//{
|
||||
// var response = await _userService.LoginAD(model);
|
||||
// return Ok(response);
|
||||
//}
|
||||
[AllowAnonymous]
|
||||
[HttpPost("[action]")]
|
||||
public async Task<IActionResult> LoginApiAD([FromBody] AuthenticateRequest model)
|
||||
{
|
||||
string remoteIpAddress = HttpContext.Connection.RemoteIpAddress?.ToString();
|
||||
var response = await _userService.LoginApiAD(model, remoteIpAddress);
|
||||
return Ok(response);
|
||||
}
|
||||
|
||||
[HttpPost("[action]")]
|
||||
public async Task<IActionResult> Logout()
|
||||
{
|
||||
var currentUser = (UserDto)HttpContext.Items["User"];
|
||||
if (null == currentUser)
|
||||
return Unauthorized(new { message = "Unauthorized" });
|
||||
|
||||
string token = Request.Headers["Authorization"].FirstOrDefault()?.Split(" ").Last();
|
||||
string remoteIpAddress = Request.HttpContext.Connection.RemoteIpAddress.ToString();
|
||||
var response = await _userService.Logout(token, currentUser, remoteIpAddress);
|
||||
return Ok(response);
|
||||
}
|
||||
|
||||
//[AllowAnonymous]
|
||||
//[HttpGet("[action]")]
|
||||
//public async Task<IActionResult> SearchADStaff(string stafflinkNo)
|
||||
//{
|
||||
// var user = await _userService.SearchADStaff(stafflinkNo);
|
||||
// return Ok(user);
|
||||
//}
|
||||
/*
|
||||
[AllowAnonymous]
|
||||
[HttpGet("[action]")]
|
||||
public async Task<ResultModel<User>> SearchADStaff(string stafflinkNo)
|
||||
{
|
||||
var user = await _userService.SearchADStaff(stafflinkNo);
|
||||
return user;
|
||||
}
|
||||
*/
|
||||
}
|
||||
@@ -0,0 +1,105 @@
|
||||
using Microsoft.AspNetCore.Mvc.Infrastructure;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using System.Data.Common;
|
||||
using FamilyTreeAPI.Entities;
|
||||
using FamilyTreeAPI.Interface;
|
||||
|
||||
namespace FamilyTreeAPI.Models
|
||||
{
|
||||
public partial class FamilyTreeDBContext
|
||||
{
|
||||
private enum EnumStaff
|
||||
{
|
||||
Id =0,
|
||||
Firstname,
|
||||
Lastname,
|
||||
Email,
|
||||
Stype,
|
||||
Active,
|
||||
Role,
|
||||
Password
|
||||
};
|
||||
private enum EnumStaffWork
|
||||
{
|
||||
id =0,
|
||||
staffid,
|
||||
description,
|
||||
startdate,
|
||||
sactive,
|
||||
did,
|
||||
starttime,
|
||||
stoptime,
|
||||
task
|
||||
}
|
||||
private enum EnumServiceTask
|
||||
{
|
||||
id = 0,
|
||||
staffid,
|
||||
sdate,
|
||||
description,
|
||||
code,
|
||||
status,
|
||||
assignTo,
|
||||
clientid,
|
||||
serviceno
|
||||
}
|
||||
|
||||
public async Task<List<StaffDto>> LoadStaffAsync(StaffCriteria criteria)
|
||||
{
|
||||
List<StaffDto> list = new();
|
||||
using (DbConnection connect = this.Database.GetDbConnection())
|
||||
{
|
||||
DbCommand command = connect.CreateCommand();
|
||||
command.CommandType = System.Data.CommandType.Text;
|
||||
command.CommandText = "SELECT * From usp_search_user(:iemail,:ifirstname,:ilastname)";
|
||||
|
||||
var loginParam = command.CreateParameter();
|
||||
|
||||
loginParam.ParameterName = "iemail";
|
||||
loginParam.Value = string.IsNullOrEmpty(criteria.Email) ? "" : criteria.Email;
|
||||
|
||||
var fistnameParam = command.CreateParameter();
|
||||
|
||||
fistnameParam.ParameterName = "ifirstname";
|
||||
fistnameParam.Value = string.IsNullOrEmpty(criteria.FirstName) ? "" : criteria.FirstName;
|
||||
|
||||
var surnameParam = command.CreateParameter() ;
|
||||
|
||||
surnameParam.ParameterName = "ilastname";
|
||||
surnameParam.Value = string.IsNullOrEmpty(criteria.LastName) ? "" : criteria.LastName;
|
||||
|
||||
command.Parameters.Add(loginParam);
|
||||
command.Parameters.Add(fistnameParam);
|
||||
command.Parameters.Add(surnameParam);
|
||||
await connect.OpenAsync();
|
||||
DbDataReader reader = await command.ExecuteReaderAsync();
|
||||
StaffDto staff;
|
||||
int idx = 0;
|
||||
while (reader.Read())
|
||||
{
|
||||
staff = new();
|
||||
idx = (int)EnumStaff.Id;
|
||||
staff.Id = reader.GetFieldValue<int>(idx);
|
||||
idx = (int)EnumStaff.Firstname;
|
||||
staff.Firstname = reader.GetFieldValue<string?>(idx);
|
||||
idx = (int) EnumStaff.Lastname;
|
||||
staff.Lastname = reader.GetFieldValue<string?>(idx);
|
||||
idx = (int)EnumStaff.Email;
|
||||
staff.Email = reader.GetFieldValue<string?>(idx);
|
||||
idx = (int)EnumStaff.Active;
|
||||
staff.Active = reader.GetFieldValue<bool?>(idx);
|
||||
idx = (int)EnumStaff.Role;
|
||||
staff.RoleType = reader.GetFieldValue<int?>(idx);
|
||||
idx = (int)EnumStaff.Password;
|
||||
if (!reader.IsDBNull(idx))
|
||||
staff.Password = reader.GetFieldValue<string?>(idx);
|
||||
|
||||
list.Add(staff);
|
||||
}
|
||||
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
# See https://aka.ms/customizecontainer to learn how to customize your debug container and how Visual Studio uses this Dockerfile to build your images for faster debugging.
|
||||
|
||||
# This stage is used when running from VS in fast mode (Default for Debug configuration)
|
||||
#FROM mcr.microsoft.com/dotnet/aspnet:8.0 AS base
|
||||
ARG BUILD_CONFIGURATION=Release
|
||||
FROM mcr.microsoft.com/dotnet/sdk:8.0 AS build
|
||||
WORKDIR /src
|
||||
COPY ["FamilyTreeAPI/FamilyTreeAPI.csproj", "FamilyTreeAPI/"]
|
||||
COPY ["CommonAD/CommonAD.csproj", "CommonAD/"]
|
||||
RUN dotnet restore "./FamilyTreeAPI/FamilyTreeAPI.csproj"
|
||||
COPY . .
|
||||
WORKDIR "/src/FamilyTreeAPI"
|
||||
RUN dotnet build "./FamilyTreeAPI.csproj" -c Release -o /app/build
|
||||
|
||||
# This stage is used to publish the service project to be copied to the final stage
|
||||
FROM build AS publish
|
||||
|
||||
RUN dotnet publish "./FamilyTreeAPI.csproj" -c Release -o /app/publish /p:UseAppHost=false
|
||||
|
||||
# This stage is used in production or when running from VS in regular mode (Default when not using the Debug configuration)
|
||||
FROM mcr.microsoft.com/dotnet/aspnet:8.0 AS base
|
||||
WORKDIR /app
|
||||
ENV ASPNETCORE_HTTP_PORTS=80
|
||||
EXPOSE 80
|
||||
COPY --from=publish /app/publish .
|
||||
ENTRYPOINT ["dotnet", "FamilyTreeAPI.dll"]
|
||||
@@ -0,0 +1,18 @@
|
||||
namespace FamilyTreeAPI.Entities;
|
||||
|
||||
public class AppSettings
|
||||
{
|
||||
public string Secret { get; set; }
|
||||
public string SQLConnectionString { get; set; }
|
||||
public string LoginWebAPI { get; set; }
|
||||
|
||||
public string ClientURL { get; set; }
|
||||
}
|
||||
|
||||
/*
|
||||
entity.HasOne(d => d.Staff)
|
||||
.WithMany(p => p.Staffworks)
|
||||
.HasForeignKey(d => d.Staffid)
|
||||
.HasConstraintName("staffwork_staffid_fkey")
|
||||
.OnDelete(DeleteBehavior.ClientCascade);
|
||||
*/
|
||||
@@ -0,0 +1,15 @@
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
|
||||
namespace FamilyTreeAPI.Entities;
|
||||
|
||||
public class AuthenticateRequest
|
||||
{
|
||||
[Required]
|
||||
public string Username { get; set; }
|
||||
|
||||
[Required]
|
||||
public string Password { get; set; }
|
||||
|
||||
|
||||
// public string Lhd { get; set; }
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
|
||||
namespace FamilyTreeAPI.Entities;
|
||||
|
||||
public class AuthenticateResponse
|
||||
{
|
||||
public int Id { get; set; }
|
||||
public string FirstName { get; set; }
|
||||
public string LastName { get; set; }
|
||||
public string Username { get; set; }
|
||||
public string Token { get; set; }
|
||||
public string Email { get; set; }
|
||||
public string? Department { get; set; }
|
||||
public string? Phone { get; set; }
|
||||
public string? Position { get; set; }
|
||||
public string? ManagerEmail { get; set; }
|
||||
public int Role { get; set; }
|
||||
|
||||
public AuthenticateResponse(UserDto user, string token, int role)
|
||||
{
|
||||
Id = user.Id;
|
||||
FirstName = user.FirstName;
|
||||
LastName = user.LastName;
|
||||
Username = user.Username;
|
||||
Email = user.Email;
|
||||
Department = user.Department;
|
||||
Position = user.Position;
|
||||
ManagerEmail = user.ManagerEmail;
|
||||
Role = role;
|
||||
Token = token;
|
||||
Phone = user.Phone;
|
||||
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace FamilyTreeAPI.Entities;
|
||||
|
||||
public class FileContent
|
||||
{
|
||||
public byte[] Content { get; set; }
|
||||
public string FileName { get; set; }
|
||||
}
|
||||
public class UploadCriteria
|
||||
{
|
||||
public string FileName { get; set; }
|
||||
public string FamilyId { get; set; }
|
||||
|
||||
public IFormFile File { get; set; }
|
||||
}
|
||||
public class DeleteFileCriteria
|
||||
{
|
||||
public int FamilyId { get; set; }
|
||||
public string Filename { get; set; }
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
namespace FamilyTreeAPI.Entities;
|
||||
|
||||
public class LookupDto
|
||||
{
|
||||
public int Id { get; set; } = 0;
|
||||
public string CodeId { get; set; }
|
||||
public string Description { get; set; }
|
||||
}
|
||||
public class LookupEditDto
|
||||
{
|
||||
public int Id { get; set; } = 0;
|
||||
public string CodeId { get; set; }
|
||||
public string Description { get; set; }
|
||||
public bool Active { get; set; }
|
||||
public string Type { get; set; }
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
|
||||
|
||||
namespace FamilyTreeAPI.Entities;
|
||||
|
||||
public class ChildCriteria
|
||||
{
|
||||
public int FatherId { get; set; }
|
||||
public int MotherId { get; set; }
|
||||
|
||||
}
|
||||
public class FamilyCriteria
|
||||
{
|
||||
public bool UseFather { get; set; }
|
||||
public bool UseMother { get; set; }
|
||||
|
||||
}
|
||||
public class PersonCriteria
|
||||
{
|
||||
public int Id { get; set; }
|
||||
public string FirstName { get; set; }
|
||||
public string LastName { get; set; }
|
||||
}
|
||||
|
||||
public class PersonForSave
|
||||
{
|
||||
public PersonDto Person { get; set; }
|
||||
public string? FormData { get; set; }
|
||||
public string? FileName { get; set; }
|
||||
|
||||
}
|
||||
public partial class PersonDto
|
||||
{
|
||||
public PersonDto()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public int Id { get; set; }
|
||||
public string? FirstName { get; set; }
|
||||
public string? LastName { get; set; }
|
||||
public string? Email { get; set; }
|
||||
public string? Phone { get; set; }
|
||||
public string? Image { get; set; }
|
||||
public string? Sex { get; set; }
|
||||
public string? Address { get; set; }
|
||||
public bool? Alive { get; set; }
|
||||
public string? dob { get; set; }
|
||||
public int? FatherId { get; set; }
|
||||
public int? MotherId { get; set; }
|
||||
|
||||
public List<RelationShipDto>? RelationShips { get; set; }
|
||||
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
namespace FamilyTreeAPI.Entities;
|
||||
|
||||
public class RelationShiftContainer
|
||||
{
|
||||
public int familyId {get; set;}
|
||||
public List<RelationShipDto> relationShips {get; set;}
|
||||
}
|
||||
public class RelationShipDto
|
||||
{
|
||||
public enumState State { get; set; }
|
||||
public int Id { get; set; }
|
||||
|
||||
public int PersonId { get; set; }
|
||||
public int RelatePersonId { get; set; }
|
||||
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace FamilyTreeAPI.Entities;
|
||||
|
||||
public enum enumState
|
||||
{
|
||||
Delete = -1,
|
||||
NoChange = 0,
|
||||
New = 1,
|
||||
Modify = 2,
|
||||
|
||||
}
|
||||
public class ResultModel<T>
|
||||
{
|
||||
public T Data { get; set; }
|
||||
public int StatusCode { get; set; }
|
||||
public string Message { get; set; }
|
||||
}
|
||||
|
||||
public class DeleteCriteria<T>
|
||||
{
|
||||
public T Id { get; set; }
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
|
||||
|
||||
namespace FamilyTreeAPI.Entities;
|
||||
|
||||
public partial class StaffCriteria
|
||||
{
|
||||
|
||||
public string Email { get; set; } = null!;
|
||||
public string? FirstName { get; set; }
|
||||
public string? LastName { get; set; }
|
||||
|
||||
}
|
||||
public partial class StaffDto
|
||||
{
|
||||
public int Id { get; set; }
|
||||
public string? Phone { get; set; } = null!;
|
||||
public string? Firstname { get; set; }
|
||||
public string? Lastname { get; set; }
|
||||
public string? Password { get; set; }
|
||||
public string? Email { get; set; }
|
||||
|
||||
public int? Type { get; set; }
|
||||
|
||||
public bool? Active { get; set; }
|
||||
public int? RoleType { get; set; }
|
||||
}
|
||||
|
||||
|
||||
public partial class ResetPassDto
|
||||
{
|
||||
public int Id { get; set; }
|
||||
public string Password { get; set; } = null!;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
namespace FamilyTreeAPI.Entities;
|
||||
|
||||
public class TreeNode<T>
|
||||
{
|
||||
public string? Label { get; set; }
|
||||
public T? Data { get; set; }
|
||||
public List<TreeNode<T>>? Children { get; set; }
|
||||
public string? Icon { get; set; }
|
||||
public bool? Checked { get; set; }
|
||||
public bool? Leaf { get; set; }
|
||||
public bool? Expanded { get; set; }
|
||||
public string? Type { get; set; }
|
||||
public string? Key { get; set; }
|
||||
public bool? Loading { get; set; }
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace FamilyTreeAPI.Entities;
|
||||
|
||||
/*
|
||||
* ROLE ID
|
||||
* Normal = 1,
|
||||
Admin = 2,
|
||||
Manager =3,
|
||||
*/
|
||||
|
||||
public class UserDto
|
||||
{
|
||||
public int Id { get; set; }
|
||||
public string? FirstName { get; set; }
|
||||
public string? LastName { get; set; }
|
||||
public string? Email { get; set; }
|
||||
public string? Username { get; set; }
|
||||
public string? Department { get; set; }
|
||||
public string? Phone { get; set; }
|
||||
public string? Position { get; set; }
|
||||
public string? ManagerEmail { get; set; }
|
||||
public int Role { get; set; }
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,38 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk.Web">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net9.0</TargetFramework>
|
||||
<Nullable>enable</Nullable>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<DockerDefaultTargetOS>Linux</DockerDefaultTargetOS>
|
||||
<DockerComposeProjectPath>..\docker-compose.dcproj</DockerComposeProjectPath>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Compile Remove="Models_old\**" />
|
||||
<Content Remove="Models_old\**" />
|
||||
<EmbeddedResource Remove="Models_old\**" />
|
||||
<None Remove="Models_old\**" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="HotChocolate.AspNetCore" Version="15.1.6" />
|
||||
<PackageReference Include="HotChocolate.Data.EntityFramework" Version="15.1.6" />
|
||||
<PackageReference Include="HotChocolate.Pagination.EntityFramework" Version="14.3.0" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="9.0.4" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="9.0.4" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="9.0.4">
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
</PackageReference>
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="9.0.4">
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
</PackageReference>
|
||||
<PackageReference Include="Microsoft.VisualStudio.Azure.Containers.Tools.Targets" Version="1.21.2" />
|
||||
<PackageReference Include="Npgsql.EntityFrameworkCore.PostgreSQL" Version="9.0.4" />
|
||||
<PackageReference Include="SpreadsheetLight" Version="3.5.0" />
|
||||
<PackageReference Include="Swashbuckle.AspNetCore" Version="8.1.1" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
@@ -0,0 +1,19 @@
|
||||
using FamilyTreeAPI.Models;
|
||||
|
||||
namespace FamilyTreeAPI.GraphQL.Query
|
||||
{
|
||||
public class QueryFamilyTree
|
||||
{
|
||||
[UsePaging]
|
||||
[UseProjection]
|
||||
[UseFiltering]
|
||||
[UseSorting]
|
||||
public IQueryable<Person> GetPersons([Service] FamilyTreeDBContext dBContext) => dBContext.Persons;
|
||||
[UsePaging]
|
||||
[UseProjection]
|
||||
[UseFiltering]
|
||||
[UseSorting]
|
||||
public IQueryable<staff> GetStaffs([Service] FamilyTreeDBContext dBContext) => dBContext.staff;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
namespace FamilyTreeAPI.Helper
|
||||
{
|
||||
public class Helpers
|
||||
{
|
||||
public static string? DateToStr(DateTime? date)
|
||||
{
|
||||
string? result = null;
|
||||
if (date.HasValue)
|
||||
{
|
||||
result = date.Value.ToString("yyyy-MM-dd");
|
||||
}
|
||||
return result;
|
||||
}
|
||||
public static DateTime? DateToDateTime(string? date)
|
||||
{
|
||||
DateTime? result = null;
|
||||
if (!string.IsNullOrEmpty(date))
|
||||
{
|
||||
DateTime dt;
|
||||
if (DateTime.TryParse(date, out dt))
|
||||
{
|
||||
result = dt;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using FamilyTreeAPI.Entities;
|
||||
|
||||
namespace FamilyTreeAPI.Interface;
|
||||
|
||||
public interface IJwtUtils
|
||||
{
|
||||
public string GenerateJwtToken(UserDto user);
|
||||
public UserDto? ValidateJwtToken(string token);
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
using FamilyTreeAPI.Entities;
|
||||
|
||||
namespace FamilyTreeAPI.Interface;
|
||||
|
||||
public interface ILookup
|
||||
{
|
||||
Task<ResultModel<int>> SaveLookupAsync(LookupEditDto lookup);
|
||||
Task<ResultModel<List<LookupDto>>> GetLookupAsync(string type);
|
||||
Task<ResultModel<Dictionary<string, LookupDto>>> GetLookupDicAsync(string type);
|
||||
Task<ResultModel<List<LookupEditDto>>> GetLookupEditAsync(string type);
|
||||
Task<ResultModel<LookupEditDto>> GetLookupEditByIdAsync(int codeId, string type);
|
||||
Task<ResultModel<List<LookupDto>>> GetPersonsAsync();
|
||||
Task<ResultModel<List<LookupDto>>> GetStaffAsync();
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
using FamilyTreeAPI.Entities;
|
||||
|
||||
namespace FamilyTreeAPI.Interface;
|
||||
|
||||
public interface IPerson
|
||||
{
|
||||
Task<ResultModel<TreeNode<string>>> GetByFamilyAsync(int id);
|
||||
Task<ResultModel<List<TreeNode<string>>>> GetFamilyTreeBy(FamilyCriteria criteria);
|
||||
Task<ResultModel<List<PersonDto>>> GetChildren(ChildCriteria criteria);
|
||||
Task<ResultModel<List<PersonDto>>> GetPerson(PersonCriteria criteria);
|
||||
Task<ResultModel<Dictionary<int,PersonDto>>> GetDicFamily();
|
||||
Task<ResultModel<PersonDto>> GetByIdAsync(int id);
|
||||
Task<ResultModel<int>> DeleteAsync(int id);
|
||||
|
||||
Task<ResultModel<string>> UploadImage(UploadCriteria criteria);
|
||||
ResultModel<int> DeleteUploadFile(DeleteFileCriteria criteria);
|
||||
Task<ResultModel<int>> SaveAsync(PersonForSave dto);
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
using FamilyTreeAPI.Entities;
|
||||
|
||||
namespace FamilyTreeAPI.Interface;
|
||||
|
||||
public interface IRelationShipd
|
||||
{
|
||||
Task<ResultModel<int>> SaveAsync(List<RelationShipDto> dto);
|
||||
//load by personId
|
||||
Task<ResultModel<List<RelationShipDto>>> GetByPersonIdAsync(int personId);
|
||||
Task<ResultModel<RelationShipDto>> GetByIdAsync(int Id);
|
||||
|
||||
Task<ResultModel<int>> DeleteAsync(int personId);
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
using FamilyTreeAPI.Entities;
|
||||
|
||||
namespace FamilyTreeAPI.Interface;
|
||||
public interface IReport
|
||||
{
|
||||
// Task<ResultModel<FileContent>> GetMotorVehicleReportAsync(MotorVehicleCriteria criteria);
|
||||
// Task<ResultModel<FileContent>> GetStaffWorkReportAsync(StaffWorkCriteria criteria);
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using FamilyTreeAPI.Entities;
|
||||
|
||||
namespace FamilyTreeAPI.Interface;
|
||||
|
||||
public interface IStaff
|
||||
{
|
||||
|
||||
Task<ResultModel<Dictionary<int,StaffDto>>> GetDicStaffs();
|
||||
Task<ResultModel<List<StaffDto>>> GetStaff(StaffCriteria criteria);
|
||||
Task<ResultModel<StaffDto>> GetStaffById(int id);
|
||||
Task<ResultModel<int>> SaveStaff(StaffDto code);
|
||||
Task<ResultModel<int>> ResetPassword(ResetPassDto code);
|
||||
Task<ResultModel<int>> SaveStaffNew(StaffDto adminUser);
|
||||
|
||||
Task<ResultModel<int>> Delete(int id);
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
using FamilyTreeAPI.Entities;
|
||||
|
||||
namespace FamilyTreeAPI.Interface;
|
||||
public interface IUserService
|
||||
{
|
||||
|
||||
Task<ResultModel<AuthenticateResponse>> LoginApiAD(AuthenticateRequest model, string remoteIpAddress);
|
||||
Task<ResultModel<AuthenticateResponse>> Login(AuthenticateRequest model);
|
||||
Task<ResultModel<int>> Logout(string token, UserDto user, string remoteIpAddress);
|
||||
|
||||
// Task<ResultModel<User>> SearchApiStaff(string staffLinkNo);
|
||||
// Task<ResultModel<User>> SearchADStaff(string staffLinkNo);
|
||||
}
|
||||
@@ -0,0 +1,136 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.EntityFrameworkCore.Metadata;
|
||||
|
||||
namespace FamilyTreeAPI.Models
|
||||
{
|
||||
public partial class FamilyTreeDBContext : DbContext
|
||||
{
|
||||
public FamilyTreeDBContext()
|
||||
{
|
||||
}
|
||||
|
||||
public FamilyTreeDBContext(DbContextOptions<FamilyTreeDBContext> options)
|
||||
: base(options)
|
||||
{
|
||||
AppContext.SetSwitch("Npgsql.EnableLegacyTimestampBehavior", true);
|
||||
}
|
||||
|
||||
public virtual DbSet<Person> Persons { get; set; } = null!;
|
||||
public virtual DbSet<RelationShip> RelationShips { get; set; } = null!;
|
||||
public virtual DbSet<Lookup> Lookups { get; set; } = null!;
|
||||
public virtual DbSet<staff> staff { get; set; } = null!;
|
||||
|
||||
|
||||
|
||||
protected override void OnModelCreating(ModelBuilder modelBuilder)
|
||||
{
|
||||
modelBuilder.Entity<Person>(entity =>
|
||||
{
|
||||
entity.ToTable("person");
|
||||
|
||||
entity.Property(e => e.Id).HasColumnName("id");
|
||||
|
||||
entity.Property(e => e.Address)
|
||||
.HasMaxLength(120)
|
||||
.HasColumnName("address");
|
||||
|
||||
entity.Property(e => e.Alive).HasColumnName("alive");
|
||||
entity.Property(e => e.dob).HasColumnName("dob");
|
||||
entity.Property(e => e.MotherId).HasColumnName("motherid");
|
||||
entity.Property(e => e.FatherId).HasColumnName("fatherid");
|
||||
|
||||
entity.Property(e => e.FirstName)
|
||||
.HasMaxLength(70)
|
||||
.HasColumnName("firstname");
|
||||
entity.Property(e => e.Sex)
|
||||
.HasMaxLength(10)
|
||||
.HasColumnName("sex");
|
||||
entity.Property(e => e.Image)
|
||||
.HasMaxLength(300)
|
||||
.HasColumnName("image");
|
||||
|
||||
entity.Property(e => e.LastName)
|
||||
.HasMaxLength(70)
|
||||
.HasColumnName("lastname");
|
||||
|
||||
entity.Property(e => e.Email)
|
||||
.HasMaxLength(80)
|
||||
.HasColumnName("email");
|
||||
|
||||
entity.Property(e => e.Phone)
|
||||
.HasMaxLength(30)
|
||||
.HasColumnName("phone");
|
||||
});
|
||||
|
||||
modelBuilder.Entity<RelationShip>(entity =>
|
||||
{
|
||||
entity.ToTable("relationship");
|
||||
|
||||
entity.Property(e => e.Id).HasColumnName("id");
|
||||
entity.Property(e => e.RelatePersonId).HasColumnName("relatepersonid");
|
||||
entity.Property(e => e.PersonId).HasColumnName("personid");
|
||||
|
||||
});
|
||||
|
||||
modelBuilder.Entity<Lookup>(entity =>
|
||||
{
|
||||
entity.ToTable("lookup");
|
||||
|
||||
entity.Property(e => e.Id).HasColumnName("id");
|
||||
|
||||
entity.Property(e => e.Code)
|
||||
.HasMaxLength(10)
|
||||
.HasColumnName("code");
|
||||
|
||||
entity.Property(e => e.Description)
|
||||
.HasMaxLength(80)
|
||||
.HasColumnName("description");
|
||||
|
||||
entity.Property(e => e.Lactive).HasColumnName("lactive");
|
||||
|
||||
entity.Property(e => e.Type).HasMaxLength(20)
|
||||
.HasColumnName("ltype");
|
||||
});
|
||||
|
||||
modelBuilder.Entity<staff>(entity =>
|
||||
{
|
||||
entity.ToTable("staff");
|
||||
entity.Property(e => e.Id).HasColumnName("id");
|
||||
|
||||
entity.Property(e => e.Email)
|
||||
.HasMaxLength(80)
|
||||
.HasColumnName("email");
|
||||
|
||||
entity.Property(e => e.Firstname)
|
||||
.HasMaxLength(70)
|
||||
.HasColumnName("firstname");
|
||||
|
||||
entity.Property(e => e.Lastname)
|
||||
.HasMaxLength(70)
|
||||
.HasColumnName("lastname");
|
||||
|
||||
entity.Property(e => e.Phone)
|
||||
.HasMaxLength(30)
|
||||
.HasColumnName("phone");
|
||||
|
||||
entity.Property(e => e.Sactive).HasColumnName("sactive");
|
||||
|
||||
entity.Property(e => e.Spassword)
|
||||
.HasMaxLength(200)
|
||||
.HasColumnName("spassword");
|
||||
|
||||
entity.Property(e => e.Srole).HasColumnName("srole");
|
||||
|
||||
entity.Property(e => e.Stype).HasColumnName("stype");
|
||||
});
|
||||
|
||||
|
||||
|
||||
OnModelCreatingPartial(modelBuilder);
|
||||
}
|
||||
|
||||
partial void OnModelCreatingPartial(ModelBuilder modelBuilder);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace FamilyTreeAPI.Models
|
||||
{
|
||||
public partial class Lookup
|
||||
{
|
||||
public int Id { get; set; }
|
||||
public string? Code { get; set; }
|
||||
public string? Description { get; set; }
|
||||
public string? Type { get; set; }
|
||||
public bool? Lactive { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace FamilyTreeAPI.Models
|
||||
{
|
||||
public partial class Person
|
||||
{
|
||||
public Person()
|
||||
{
|
||||
// Servicetasks = new HashSet<Servicetask>();
|
||||
}
|
||||
|
||||
public int Id { get; set; }
|
||||
public string? FirstName { get; set; }
|
||||
public string? LastName { get; set; }
|
||||
public string? Email { get; set; }
|
||||
public string? Phone { get; set; }
|
||||
public string? Address { get; set; }
|
||||
public string? Sex { get; set; }
|
||||
|
||||
public string? Image { get; set; }
|
||||
public bool? Alive { get; set; }
|
||||
public int? MotherId { get; set; }
|
||||
public int? FatherId { get; set; }
|
||||
|
||||
public DateTime? dob { get; set; }
|
||||
|
||||
//public virtual ICollection<Staffwork> Staffworks { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
namespace FamilyTreeAPI.Models;
|
||||
|
||||
public class RelationShip
|
||||
{
|
||||
public int Id { get; set; }
|
||||
public int RelatePersonId { get; set; }
|
||||
public int PersonId { get; set; }
|
||||
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace FamilyTreeAPI.Models
|
||||
{
|
||||
public partial class staff
|
||||
{
|
||||
public staff()
|
||||
{
|
||||
// ServicetaskAssigntoNavigations = new HashSet<Servicetask>();
|
||||
// ServicetaskStaffs = new HashSet<Servicetask>();
|
||||
// Staffworks = new HashSet<Staffwork>();
|
||||
}
|
||||
|
||||
public int Id { get; set; }
|
||||
public string? Firstname { get; set; }
|
||||
public string? Lastname { get; set; }
|
||||
public string? Email { get; set; }
|
||||
public string? Phone { get; set; }
|
||||
public int? Stype { get; set; }
|
||||
public int? Srole { get; set; }
|
||||
public string? Spassword { get; set; }
|
||||
public bool? Sactive { get; set; }
|
||||
|
||||
// public virtual ICollection<Servicetask> ServicetaskAssigntoNavigations { get; set; }
|
||||
// public virtual ICollection<Servicetask> ServicetaskStaffs { get; set; }
|
||||
//public virtual ICollection<Staffwork> Staffworks { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,184 @@
|
||||
using Microsoft.AspNetCore.Authentication.JwtBearer;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||
using Microsoft.EntityFrameworkCore.Storage;
|
||||
using Microsoft.IdentityModel.Tokens;
|
||||
using System.Text;
|
||||
using DocumentFormat.OpenXml.Office2010.Drawing.Charts;
|
||||
using FamilyTreeAPI.Authorization;
|
||||
using FamilyTreeAPI.Entities;
|
||||
using FamilyTreeAPI.GraphQL.Query;
|
||||
using FamilyTreeAPI.Interface;
|
||||
using FamilyTreeAPI.Models;
|
||||
using FamilyTreeAPI.Repository;
|
||||
|
||||
var builder = WebApplication.CreateBuilder(args);
|
||||
|
||||
// Add services to the container.
|
||||
#region Services
|
||||
var services = builder.Services;
|
||||
services.AddCors();
|
||||
services.AddControllers();
|
||||
// Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle
|
||||
services.AddEndpointsApiExplorer();
|
||||
services.AddSwaggerGen();
|
||||
|
||||
var appSettingsSection = builder.Configuration.GetSection("AppSettings");
|
||||
services.Configure<AppSettings>(appSettingsSection);
|
||||
var appSettings = appSettingsSection.Get<AppSettings>();
|
||||
var key = Encoding.ASCII.GetBytes(appSettings.Secret);
|
||||
|
||||
services.AddAuthentication(x =>
|
||||
{
|
||||
|
||||
x.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
|
||||
x.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
|
||||
})
|
||||
.AddJwtBearer(x =>
|
||||
{
|
||||
x.RequireHttpsMetadata = false;
|
||||
x.SaveToken = true;
|
||||
x.TokenValidationParameters = new TokenValidationParameters
|
||||
{
|
||||
ValidateIssuerSigningKey = true,
|
||||
IssuerSigningKey = new SymmetricSecurityKey(key),
|
||||
ValidateIssuer = false,
|
||||
ValidateAudience = false
|
||||
};
|
||||
});
|
||||
services.AddHttpContextAccessor();
|
||||
services.AddScoped<IJwtUtils, JwtUtils>();
|
||||
|
||||
services.AddDbContext<FamilyTreeDBContext>(options =>
|
||||
{
|
||||
|
||||
// options.LogTo(s => Console.WriteLine(s));
|
||||
//options.UseNpgsql(appSettings.SQLConnectionString);
|
||||
string? conn = builder.Configuration.GetValue<string>("AppSettings:SQLConnectionString");
|
||||
// options.LogTo(s => Console.WriteLine(s));
|
||||
if (conn != null)
|
||||
options.UseNpgsql(conn);
|
||||
});
|
||||
|
||||
services.AddGraphQLServer()
|
||||
.AddFiltering()
|
||||
.AddSorting()
|
||||
.AddProjections()
|
||||
.RegisterDbContextFactory<FamilyTreeDBContext>()
|
||||
|
||||
.AddQueryType<QueryFamilyTree>();
|
||||
|
||||
|
||||
services.AddScoped<ILookup, LookupRepository>();
|
||||
services.AddScoped<IStaff, StaffRepository>();
|
||||
|
||||
services.AddScoped<IRelationShipd,RelationShipRepository>();
|
||||
services.AddScoped<IPerson, PersonRepository>();
|
||||
services.AddScoped<IUserService, UserServiceRepository>();
|
||||
services.AddScoped<IReport, ReportRepository>();
|
||||
services.AddScoped<Seed>();
|
||||
/*
|
||||
|
||||
public FamilyTreeDBContext(DbContextOptions<FamilyTreeDBContext> options)
|
||||
: base(options)
|
||||
{
|
||||
AppContext.SetSwitch("Npgsql.EnableLegacyTimestampBehavior", true);
|
||||
}
|
||||
services.AddScoped<IAdminUser, AdminUserRepository>();
|
||||
|
||||
services.AddScoped<IMotorVehicles, MotorVehiclesRepository>();
|
||||
*/
|
||||
|
||||
#endregion
|
||||
|
||||
#region app
|
||||
var app = builder.Build();
|
||||
|
||||
|
||||
using (var scope = app.Services.CreateScope())
|
||||
{
|
||||
try
|
||||
{
|
||||
var context = scope.ServiceProvider.GetRequiredService<FamilyTreeDBContext>();
|
||||
var db = context.Database;
|
||||
if (db != null)
|
||||
{
|
||||
|
||||
db.Migrate();
|
||||
db.EnsureCreated();
|
||||
var staff = context.GetService<Seed>();
|
||||
int id = staff.InsertOneUser();
|
||||
if (id < 0)
|
||||
{
|
||||
var databaseCreator = (context.GetService<IDatabaseCreator>() as RelationalDatabaseCreator);
|
||||
if (databaseCreator != null)
|
||||
{
|
||||
//if (!databaseCreator.Exists())
|
||||
databaseCreator.CreateTables();
|
||||
}
|
||||
id = staff.InsertOneUser();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Console.WriteLine(e.ToString());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
app.UseMiddleware<JwtMiddleware>();
|
||||
// Configure the HTTP request pipeline.
|
||||
//if (app.Environment.IsDevelopment())//
|
||||
//{
|
||||
app.UseSwagger();
|
||||
app.UseSwaggerUI();
|
||||
//}
|
||||
// global cors policy
|
||||
app.UseCors(x => x
|
||||
.SetIsOriginAllowed(origin => true)
|
||||
.AllowAnyMethod()
|
||||
.AllowAnyHeader()
|
||||
.WithExposedHeaders("Content-Disposition")
|
||||
.AllowCredentials());
|
||||
|
||||
app.UseRouting();
|
||||
app.UseAuthentication();
|
||||
app.UseAuthorization();
|
||||
app.MapGraphQL();
|
||||
app.MapControllers();
|
||||
app.Run();
|
||||
|
||||
#endregion
|
||||
|
||||
/*
|
||||
https://www.youtube.com/watch?v=WQFx2m5Ub9M
|
||||
|
||||
|
||||
https://csharptotypescript.azurewebsites.net/
|
||||
\ services.AddDbContext<BloggingContext>(options =>
|
||||
options.UseNpgsql(Configuration.GetConnectionString("BloggingContext")));
|
||||
dotnet ef dbcontext scaffold "host=postgresdb;port=5432;Database=FamilyTreeDB;Username=postgres;password=Positive~1" Npgsql.EntityFrameworkCore.PostgreSQL -Schemas schema1 --output-dir Models
|
||||
PM> Scaffold-DbContext "Host=postgresdb;Port=5432;database=FamilyTreeDB;user id=postgres;Password=Positive~1" Npgsql.EntityFrameworkCore.PostgreSQL -OutputDir Models
|
||||
*/
|
||||
|
||||
/*
|
||||
graphql
|
||||
https://www.youtube.com/watch?v=HnXA8RI7Tvc
|
||||
|
||||
query {
|
||||
family {
|
||||
nodes{
|
||||
id
|
||||
firstname
|
||||
lastname
|
||||
email
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
*/
|
||||
@@ -0,0 +1,41 @@
|
||||
{
|
||||
"profiles": {
|
||||
"FamilyTreeAPI": {
|
||||
"commandName": "Project",
|
||||
"launchBrowser": true,
|
||||
"launchUrl": "swagger",
|
||||
"environmentVariables": {
|
||||
"ASPNETCORE_ENVIRONMENT": "Development"
|
||||
},
|
||||
"dotnetRunMessages": true,
|
||||
"applicationUrl": "http://localhost:5015"
|
||||
},
|
||||
"IIS Express": {
|
||||
"commandName": "IISExpress",
|
||||
"launchBrowser": true,
|
||||
"launchUrl": "swagger",
|
||||
"environmentVariables": {
|
||||
"ASPNETCORE_ENVIRONMENT": "Development"
|
||||
}
|
||||
},
|
||||
"Container (Dockerfile)": {
|
||||
"commandName": "Docker",
|
||||
"launchBrowser": true,
|
||||
"launchUrl": "{Scheme}://{ServiceHost}:{ServicePort}/swagger",
|
||||
"environmentVariables": {
|
||||
"ASPNETCORE_HTTP_PORTS": "8080"
|
||||
},
|
||||
"publishAllPorts": true,
|
||||
"useSSL": false
|
||||
}
|
||||
},
|
||||
"$schema": "https://json.schemastore.org/launchsettings.json",
|
||||
"iisSettings": {
|
||||
"windowsAuthentication": false,
|
||||
"anonymousAuthentication": true,
|
||||
"iisExpress": {
|
||||
"applicationUrl": "http://localhost:4559",
|
||||
"sslPort": 0
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
using System.Net.Mail;
|
||||
|
||||
namespace FamilyTreeAPI.Repository
|
||||
{
|
||||
public class Email
|
||||
{
|
||||
public static void SendMail(string smtpServer, string sender, string sendTo,
|
||||
string header, string message, bool mailPriority = false)
|
||||
{
|
||||
if (string.IsNullOrEmpty(smtpServer) && string.IsNullOrEmpty(sender) && string.IsNullOrEmpty(sendTo))
|
||||
return;
|
||||
System.Net.Mail.SmtpClient client = new SmtpClient(smtpServer);
|
||||
MailMessage mailMessage = new MailMessage();
|
||||
mailMessage.From = new MailAddress(sender);
|
||||
|
||||
var splitEmails = sendTo.Split(';');
|
||||
foreach (string item in splitEmails)
|
||||
{
|
||||
mailMessage.To.Add(item);
|
||||
}
|
||||
if (mailPriority)
|
||||
mailMessage.Priority = MailPriority.High;
|
||||
|
||||
// mailMessage.To.Add(sendTo);
|
||||
mailMessage.Subject = header;
|
||||
string text = message;
|
||||
string signature = "";
|
||||
try
|
||||
{
|
||||
text += "<br/>" + signature;
|
||||
mailMessage.Body = text;
|
||||
mailMessage.IsBodyHtml = true;
|
||||
|
||||
}
|
||||
catch //(Exception ex)
|
||||
{
|
||||
// ErrorLogger.logError(ex, "CPA");
|
||||
throw;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
string userState = "send to fleet manager";
|
||||
client.SendAsync(mailMessage, userState);
|
||||
|
||||
}
|
||||
catch //(Exception ex)
|
||||
{
|
||||
throw;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,278 @@
|
||||
using FamilyTreeAPI.Entities;
|
||||
using FamilyTreeAPI.Interface;
|
||||
using FamilyTreeAPI.Models;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
|
||||
namespace FamilyTreeAPI.Repository
|
||||
{
|
||||
public class LookupRepository: ILookup
|
||||
{
|
||||
private readonly FamilyTreeDBContext _context;
|
||||
public LookupRepository(FamilyTreeDBContext context)
|
||||
{
|
||||
_context = context;
|
||||
}
|
||||
|
||||
private bool checkDescription(string desc, string type, int id)
|
||||
{
|
||||
bool result = false;
|
||||
if (!string.IsNullOrEmpty(desc))
|
||||
{
|
||||
string ldesc = desc.ToLower();
|
||||
int count = _context.Lookups.Where(x => (x.Code ?? "").ToLower() == ldesc
|
||||
&& id != x.Id
|
||||
).ToList().Count();
|
||||
result = count > 0;
|
||||
|
||||
}
|
||||
return result;
|
||||
}
|
||||
public async Task<ResultModel<int>> SaveLookupAsync(LookupEditDto lookup)
|
||||
{
|
||||
int result = -1;
|
||||
int statusCode = 0;
|
||||
string desc = lookup.Description.Trim();
|
||||
string error = "";
|
||||
try
|
||||
{
|
||||
Lookup model = null!;
|
||||
bool ok = !checkDescription(desc, lookup.Type, lookup.Id);
|
||||
if (ok)
|
||||
{
|
||||
if (lookup.Id < 1)
|
||||
{
|
||||
model = new();
|
||||
model.Code = lookup.CodeId;
|
||||
model.Description = desc;
|
||||
model.Type = lookup.Type;
|
||||
model.Lactive = lookup.Active;
|
||||
|
||||
_context.Lookups.Add(model);
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
Lookup? model1 = await _context.Lookups.FindAsync(lookup.Id);
|
||||
if (model1 != null)
|
||||
{
|
||||
model1.Description = desc;
|
||||
model1.Code = lookup.CodeId;
|
||||
model1.Lactive = lookup.Active;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
await _context.SaveChangesAsync();
|
||||
if (model != null)
|
||||
result = model.Id;
|
||||
|
||||
statusCode = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
statusCode = 0;
|
||||
error = "description is already in database";
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
error = ex.ToString();
|
||||
statusCode = -1;
|
||||
|
||||
}
|
||||
return new ResultModel<int>()
|
||||
{
|
||||
Data = result,
|
||||
StatusCode = statusCode,
|
||||
Message = error
|
||||
};
|
||||
}
|
||||
public async Task<ResultModel<LookupEditDto>> GetLookupEditByIdAsync(int id, string type)
|
||||
{
|
||||
List<LookupEditDto> resultList;
|
||||
LookupEditDto item = null!;
|
||||
int statusCode = 0;
|
||||
string error = "";
|
||||
try
|
||||
{
|
||||
resultList = await _context.Lookups.Where(x => x.Type == type
|
||||
&& (x.Id == id))
|
||||
.Select(item => new LookupEditDto
|
||||
{
|
||||
CodeId = string.IsNullOrEmpty(item.Code) ? "0": item.Code,
|
||||
Active = item.Lactive ?? false,
|
||||
Id = item.Id,
|
||||
Description = item.Description ?? ""
|
||||
})
|
||||
.ToListAsync();
|
||||
|
||||
if (resultList.Count > 0)
|
||||
item = resultList[0];
|
||||
statusCode = 1;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
error = ex.ToString();
|
||||
statusCode = -1;
|
||||
|
||||
}
|
||||
return new ResultModel<LookupEditDto>()
|
||||
{
|
||||
Data = item,
|
||||
StatusCode = statusCode,
|
||||
Message = error
|
||||
};
|
||||
}
|
||||
public async Task<ResultModel<List<LookupDto>>> GetLookupAsync(string type)
|
||||
{
|
||||
List<LookupDto> resultList = new();
|
||||
int statusCode = 0;
|
||||
string error = "";
|
||||
try
|
||||
{
|
||||
resultList = await _context.Lookups.Where(x => x.Type == type && ((x.Lactive ?? false) == true))
|
||||
.Select(item => new LookupDto { Id = item.Id, CodeId = item.Code ?? "", Description = item.Description ?? "" })
|
||||
.ToListAsync();
|
||||
|
||||
resultList.Sort((x, y) => x.Description.CompareTo(y.Description));
|
||||
|
||||
statusCode = 1;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
error = ex.ToString();
|
||||
statusCode = -1;
|
||||
|
||||
}
|
||||
return new ResultModel<List<LookupDto>>()
|
||||
{
|
||||
Data = resultList,
|
||||
StatusCode = statusCode,
|
||||
Message = error
|
||||
};
|
||||
}
|
||||
|
||||
public async Task<ResultModel<Dictionary<string, LookupDto>>> GetLookupDicAsync(string type)
|
||||
{
|
||||
Dictionary<string, LookupDto> resultList = new();
|
||||
|
||||
int statusCode = 0;
|
||||
string error = "";
|
||||
try
|
||||
{
|
||||
resultList = await _context.Lookups.Where(x => x.Type == type && ((x.Lactive ?? false) == true))
|
||||
.Select(item => new LookupDto { Id = item.Id, CodeId = item.Code ?? "", Description = item.Description ?? "" })
|
||||
.ToDictionaryAsync(x => x.CodeId);
|
||||
|
||||
|
||||
statusCode = 1;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
error = ex.ToString();
|
||||
statusCode = -1;
|
||||
|
||||
}
|
||||
return new ResultModel<Dictionary<string, LookupDto>>()
|
||||
{
|
||||
Data = resultList,
|
||||
StatusCode = statusCode,
|
||||
Message = error
|
||||
};
|
||||
}
|
||||
public async Task<ResultModel<List<LookupEditDto>>> GetLookupEditAsync(string type)
|
||||
{
|
||||
List<LookupEditDto> resultList = new();
|
||||
int statusCode = 0;
|
||||
string error = "";
|
||||
try
|
||||
{
|
||||
resultList = await _context.Lookups.Where(x => x.Type == type)
|
||||
.Select(item => new LookupEditDto
|
||||
{
|
||||
Id = item.Id,
|
||||
Active = item.Lactive ?? false,
|
||||
CodeId = item.Code ?? "",
|
||||
Type = item.Type ?? "",
|
||||
Description = item.Description ?? ""
|
||||
})
|
||||
.ToListAsync();
|
||||
|
||||
resultList.Sort((x, y) => x.Description.CompareTo(y.Description));
|
||||
|
||||
statusCode = 1;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
error = ex.ToString();
|
||||
statusCode = -1;
|
||||
|
||||
}
|
||||
return new ResultModel<List<LookupEditDto>>()
|
||||
{
|
||||
Data = resultList,
|
||||
StatusCode = statusCode,
|
||||
Message = error
|
||||
};
|
||||
}
|
||||
public async Task<ResultModel<List<LookupDto>>> GetPersonsAsync()
|
||||
{
|
||||
List<LookupDto> resultList = new();
|
||||
int statusCode = 0;
|
||||
string error = "";
|
||||
try
|
||||
{
|
||||
resultList = await _context.Persons.Where(x => x.Alive == true)
|
||||
.Select(item => new LookupDto { Id = item.Id, CodeId = item.Id.ToString(), Description = item.FirstName ?? "" })
|
||||
.ToListAsync();
|
||||
|
||||
resultList.Sort((x, y) => x.Description.CompareTo(y.Description));
|
||||
|
||||
statusCode = 1;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
error = ex.ToString();
|
||||
statusCode = -1;
|
||||
|
||||
}
|
||||
return new ResultModel<List<LookupDto>>()
|
||||
{
|
||||
Data = resultList,
|
||||
StatusCode = statusCode,
|
||||
Message = error
|
||||
};
|
||||
}
|
||||
|
||||
public async Task<ResultModel<List<LookupDto>>> GetStaffAsync()
|
||||
{
|
||||
List<LookupDto> resultList = new();
|
||||
int statusCode = 0;
|
||||
string error = "";
|
||||
try
|
||||
{
|
||||
resultList = await _context.staff.Where(x => x.Sactive == true)
|
||||
.Select(item => new LookupDto { Id = item.Id, CodeId = item.Firstname ?? "", Description = item.Lastname ?? "" })
|
||||
.ToListAsync();
|
||||
|
||||
resultList.Sort((x, y) => x.Description.CompareTo(y.Description));
|
||||
|
||||
statusCode = 1;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
error = ex.ToString();
|
||||
statusCode = -1;
|
||||
|
||||
}
|
||||
return new ResultModel<List<LookupDto>>()
|
||||
{
|
||||
Data = resultList,
|
||||
StatusCode = statusCode,
|
||||
Message = error
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,657 @@
|
||||
using DocumentFormat.OpenXml.EMMA;
|
||||
using DocumentFormat.OpenXml.Office.CustomUI;
|
||||
using DocumentFormat.OpenXml.Office2010.Excel;
|
||||
using FamilyTreeAPI.Entities;
|
||||
using FamilyTreeAPI.Helper;
|
||||
using FamilyTreeAPI.Interface;
|
||||
using FamilyTreeAPI.Models;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Drawing;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace FamilyTreeAPI.Repository;
|
||||
|
||||
public partial class PersonRepository : IPerson
|
||||
{
|
||||
private readonly FamilyTreeDBContext _context;
|
||||
private readonly IRelationShipd _relationship;
|
||||
private readonly IHttpContextAccessor _httpContext;
|
||||
private readonly IConfiguration _config;
|
||||
const string dateFormat = "yyyy-MM-dd";
|
||||
public PersonRepository(IConfiguration config, FamilyTreeDBContext context,
|
||||
IRelationShipd relationship,
|
||||
IHttpContextAccessor httpContext)
|
||||
{
|
||||
_context = context;
|
||||
_relationship = relationship;
|
||||
_config = config;
|
||||
_httpContext = httpContext;
|
||||
}
|
||||
|
||||
private PersonDto FillDto(Person model)
|
||||
{
|
||||
PersonDto dto = new();
|
||||
dto.Id = model.Id;
|
||||
dto.FirstName = model.FirstName;
|
||||
dto.LastName = model.LastName;
|
||||
dto.Email = model.Email;
|
||||
dto.Address = model.Address;
|
||||
dto.Phone = model.Phone;
|
||||
dto.Alive = model.Alive;
|
||||
dto.Image = model.Image;
|
||||
dto.FatherId = model.FatherId;
|
||||
dto.MotherId = model.MotherId;
|
||||
dto.Sex = model.Sex;
|
||||
dto.dob = Helpers.DateToStr(model.dob);
|
||||
/*
|
||||
dto.AddedOn = model.AddedOn;
|
||||
|
||||
dto.RoleType = model.RoleType;
|
||||
|
||||
*/
|
||||
|
||||
return dto;
|
||||
}
|
||||
private Person FillModel(Person model, PersonDto dto)
|
||||
{
|
||||
|
||||
model.FirstName = dto.FirstName;
|
||||
model.LastName = dto.LastName;
|
||||
model.Email = dto.Email;
|
||||
model.Address = dto.Address;
|
||||
model.Phone = dto.Phone;
|
||||
model.Alive = dto.Alive;
|
||||
model.Image = dto.Image;
|
||||
model.FatherId = dto.FatherId;
|
||||
model.MotherId = dto.MotherId;
|
||||
model.Sex = dto.Sex;
|
||||
model.dob = Helpers.DateToDateTime(dto.dob);
|
||||
|
||||
return model;
|
||||
}
|
||||
|
||||
public async Task<ResultModel<Dictionary<int, PersonDto>>> GetDicFamily()
|
||||
{
|
||||
|
||||
Dictionary<int, PersonDto> list = new();
|
||||
int statuscode = 0;
|
||||
string error = "";
|
||||
PersonDto item;
|
||||
Person jitem;
|
||||
try
|
||||
{
|
||||
//list = await _context.LoadStaffAsync(criteria);
|
||||
var jlist = await _context.Persons.ToListAsync();
|
||||
for (int i = 0; i < jlist.Count; i++)
|
||||
{
|
||||
jitem = jlist[i];
|
||||
item = FillDto(jitem);
|
||||
list.Add(item.Id,item);
|
||||
}
|
||||
statuscode = 1;
|
||||
//list.Sort((x, y) => x.Code.CompareTo(y.Code));
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
|
||||
error = ex.ToString();
|
||||
statuscode = -1;
|
||||
|
||||
}
|
||||
return new ResultModel< Dictionary<int, PersonDto> > ()
|
||||
{
|
||||
Data = list,
|
||||
StatusCode = statuscode,
|
||||
Message = error
|
||||
};
|
||||
}
|
||||
|
||||
private async Task<List<PersonDto>> GetChildrens(int FatherId, int MotherId)
|
||||
{
|
||||
List<PersonDto> list = new();
|
||||
PersonDto item;
|
||||
Person jitem;
|
||||
var jlist = await _context.Persons.Where(x =>
|
||||
(x.MotherId == FatherId && x.FatherId == MotherId) ||
|
||||
(x.FatherId == FatherId && x.MotherId == MotherId)).ToListAsync();
|
||||
for (int i = 0; i < jlist.Count; i++)
|
||||
{
|
||||
jitem = jlist[i];
|
||||
item = FillDto(jitem);
|
||||
list.Add(item);
|
||||
}
|
||||
return list;
|
||||
}
|
||||
public async Task<ResultModel<List<PersonDto>>> GetChildren(ChildCriteria criteria)
|
||||
{
|
||||
List<PersonDto> list = new();
|
||||
int statuscode = 0;
|
||||
string error = "";
|
||||
PersonDto item;
|
||||
Person jitem;
|
||||
try
|
||||
{
|
||||
//list = await _context.LoadStaffAsync(criteria);
|
||||
list = await GetChildrens(criteria.FatherId, criteria.MotherId);
|
||||
statuscode = 1;
|
||||
//list.Sort((x, y) => x.Code.CompareTo(y.Code));
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
|
||||
error = ex.ToString();
|
||||
statuscode = -1;
|
||||
|
||||
}
|
||||
return new ResultModel<List<PersonDto>>()
|
||||
{
|
||||
Data = list,
|
||||
StatusCode = statuscode,
|
||||
Message = error
|
||||
};
|
||||
}
|
||||
|
||||
public async Task<ResultModel<List<PersonDto>>> GetPerson(PersonCriteria criteria)
|
||||
{
|
||||
|
||||
List<PersonDto> list = new();
|
||||
List<Person>? jlist;
|
||||
int statuscode = 0;
|
||||
string error = "";
|
||||
PersonDto item;
|
||||
Person jitem;
|
||||
string firstName = criteria.FirstName;
|
||||
string lastName = criteria.LastName;
|
||||
int Id = criteria.Id;
|
||||
try
|
||||
{
|
||||
//list = await _context.LoadStaffAsync(criteria);
|
||||
if (!string.IsNullOrEmpty(firstName))
|
||||
{
|
||||
firstName = firstName.ToLower();
|
||||
jlist = await _context.Persons.Where(x =>
|
||||
EF.Functions.Like(x.FirstName.ToLower(),firstName + "%")).ToListAsync();
|
||||
}
|
||||
else if (!string.IsNullOrEmpty(firstName) && !string.IsNullOrEmpty(lastName))
|
||||
{
|
||||
firstName = firstName.ToLower();
|
||||
lastName = lastName.ToLower();
|
||||
jlist = await _context.Persons.Where(x => EF.Functions.Like(x.FirstName.ToLower(),firstName + "%")
|
||||
&& EF.Functions.Like(x.LastName.ToLower(),lastName + "%")).ToListAsync();
|
||||
}
|
||||
else
|
||||
jlist = await _context.Persons.ToListAsync();
|
||||
|
||||
for (int i = 0; i < jlist.Count; i++)
|
||||
{
|
||||
jitem = jlist[i];
|
||||
item = FillDto(jitem);
|
||||
list.Add(item);
|
||||
}
|
||||
statuscode = 1;
|
||||
//list.Sort((x, y) => x.Code.CompareTo(y.Code));
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
|
||||
error = ex.ToString();
|
||||
statuscode = -1;
|
||||
|
||||
}
|
||||
return new ResultModel<List<PersonDto>>()
|
||||
{
|
||||
Data = list,
|
||||
StatusCode = statuscode,
|
||||
Message = error
|
||||
};
|
||||
}
|
||||
|
||||
private async Task<Person> GetPerson(int id)
|
||||
{
|
||||
Person rval = await _context.Persons.FindAsync(id);
|
||||
return rval;
|
||||
}
|
||||
public async Task<ResultModel<TreeNode<string>>> GetByFamilyAsync(int id)
|
||||
{
|
||||
int statuscode = 0;
|
||||
string error = "";
|
||||
string key = "";
|
||||
string data = "";
|
||||
string type = "default";
|
||||
string pName = "";
|
||||
Person person;
|
||||
TreeNode<string> citem;
|
||||
TreeNode<string> child;
|
||||
TreeNode<string> node = new();
|
||||
node.Children = new();
|
||||
PersonDto dto = new();
|
||||
try
|
||||
{
|
||||
var item = await _context.Persons.FindAsync(id);
|
||||
if (item == null)
|
||||
{
|
||||
statuscode = -1;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
node.Label = item.FirstName;
|
||||
node.Key = item.Id.ToString();
|
||||
node.Type = type;
|
||||
node.Expanded = true;
|
||||
node.Data = item.Sex;
|
||||
statuscode = 1;
|
||||
dto = FillDto(item);
|
||||
await GetPartnerChildrens(dto, node);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
error = ex.ToString();
|
||||
statuscode = -1;
|
||||
|
||||
}
|
||||
return new ResultModel<TreeNode<string>> ()
|
||||
{
|
||||
Data = node,
|
||||
StatusCode = statuscode,
|
||||
Message = error
|
||||
};
|
||||
}
|
||||
|
||||
private async Task GetPartnerChildrens(PersonDto person, TreeNode<string> node)
|
||||
{
|
||||
/*****************************/
|
||||
ResultModel<List<RelationShipDto>> rlist = await _relationship.GetByPersonIdAsync(person.Id);
|
||||
List<RelationShipDto> relationShips = rlist.Data;
|
||||
RelationShipDto relate;
|
||||
string type = node.Type;
|
||||
TreeNode<string> child;
|
||||
PersonDto dto;
|
||||
Person pe;
|
||||
int fatherId, motherId;
|
||||
fatherId = motherId = 0;
|
||||
string data = person.Sex;
|
||||
TreeNode<string> citem;
|
||||
string pName = "";
|
||||
string key = "";
|
||||
for (int i = 0; i < relationShips.Count; i++)
|
||||
{
|
||||
relate = relationShips[i];
|
||||
if (relate.PersonId == person.Id)
|
||||
{
|
||||
if (data == "M")
|
||||
{
|
||||
fatherId = relate.PersonId;
|
||||
motherId = relate.RelatePersonId;
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
fatherId = relate.RelatePersonId;
|
||||
motherId = relate.PersonId;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (data == "M")
|
||||
{
|
||||
fatherId = relate.PersonId;
|
||||
motherId = relate.RelatePersonId;
|
||||
}
|
||||
else
|
||||
{
|
||||
fatherId = relate.RelatePersonId;
|
||||
motherId = relate.PersonId;
|
||||
}
|
||||
}
|
||||
//get children
|
||||
List<PersonDto> children = await GetChildrens(fatherId, motherId);
|
||||
if (children.Count > 0)
|
||||
{
|
||||
if (person.Id != motherId)
|
||||
{
|
||||
//kham
|
||||
if (motherId > 0)
|
||||
{
|
||||
pe = await GetPerson(motherId);
|
||||
pName = pe.FirstName;
|
||||
key = motherId.ToString();
|
||||
data = "F";
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (fatherId > 0)
|
||||
{
|
||||
pe = await GetPerson(fatherId);
|
||||
pName = pe.FirstName;
|
||||
key = fatherId.ToString();
|
||||
data = "M";
|
||||
}
|
||||
}
|
||||
|
||||
citem = new TreeNode<string>();
|
||||
citem.Label = pName;
|
||||
citem.Expanded = true;
|
||||
citem.Data = data;
|
||||
citem.Type = type;
|
||||
citem.Key = key;
|
||||
citem.Children = new List<TreeNode<string>>();
|
||||
node.Children.Add(citem);
|
||||
for (int j = 0; j < children.Count; j++)
|
||||
{
|
||||
dto = children[j];
|
||||
child = new TreeNode<string>();
|
||||
child.Expanded = true;
|
||||
child.Type = type;
|
||||
child.Label = dto.FirstName;
|
||||
child.Key = dto.Id.ToString();
|
||||
child.Data = dto.Sex;
|
||||
child.Children = new();
|
||||
citem.Children.Add(child);
|
||||
//get child partner and repeat this.
|
||||
await GetPartnerChildrens(dto, child);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/*****************************************/
|
||||
}
|
||||
|
||||
public async Task<ResultModel<PersonDto>> GetByIdAsync(int id)
|
||||
{
|
||||
int statuscode = 0;
|
||||
string error = "";
|
||||
PersonDto dto = new();
|
||||
try
|
||||
{
|
||||
var item = await _context.Persons.FindAsync(id);
|
||||
if (item == null)
|
||||
{
|
||||
statuscode = -1;
|
||||
}
|
||||
else
|
||||
{
|
||||
dto = FillDto(item);
|
||||
statuscode = 1;
|
||||
ResultModel<List<RelationShipDto>> rlist = await _relationship.GetByPersonIdAsync(dto.Id);
|
||||
dto.RelationShips = rlist.Data;
|
||||
statuscode = rlist.StatusCode;
|
||||
error = rlist.Message;
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
error = ex.ToString();
|
||||
statuscode = -1;
|
||||
|
||||
}
|
||||
return new ResultModel<PersonDto>()
|
||||
{
|
||||
Data = dto,
|
||||
StatusCode = statuscode,
|
||||
Message = error
|
||||
};
|
||||
}
|
||||
private string GetDateTimeNow()
|
||||
{
|
||||
return DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// need filename to get extension file and family name for id combine to
|
||||
/// name to table.
|
||||
/// </summary>
|
||||
/// <param name="fileName"></param>
|
||||
/// <param name="familyId"></param>
|
||||
/// <param name="base64"></param>
|
||||
private string SaveFile(string fileName, int familyId, string base64)
|
||||
{
|
||||
string path = "";
|
||||
|
||||
int statusCode = 0;
|
||||
string error = "";
|
||||
string sdate = GetCurrentDateTime();
|
||||
string filename, extention;
|
||||
filename = extention = "";
|
||||
int first = base64.IndexOf("base64,") +"base64,".Length;
|
||||
int last = base64.Length;
|
||||
string rbase = base64.Substring(first, last - first);
|
||||
|
||||
byte[] newBytes = Convert.FromBase64String(rbase);
|
||||
path = _config["AppSettings:ImageFolder"];
|
||||
if (!Directory.Exists(path))
|
||||
{
|
||||
Directory.CreateDirectory(path);
|
||||
}
|
||||
extention = System.IO.Path.GetExtension(fileName);
|
||||
filename = familyId + "_" + sdate + extention;
|
||||
string fullpath = System.IO.Path.Combine(path, filename);
|
||||
/*
|
||||
using (var fileStream = new FileStream(fullpath, FileMode.Create))
|
||||
{
|
||||
StreamWriter writer = new StreamWriter(fileStream);
|
||||
writer.Write(newBytes);
|
||||
//writer.BaseStream.Write(bytes, 0, bytes.Length);
|
||||
|
||||
}
|
||||
*/
|
||||
using (MemoryStream ms = new MemoryStream(newBytes))
|
||||
{
|
||||
Image image = Image.FromStream(ms);
|
||||
image.Save(fullpath);
|
||||
}
|
||||
return filename;
|
||||
}
|
||||
public async Task<ResultModel<int>> SaveAsync(PersonForSave container)
|
||||
{
|
||||
int result = default(int);
|
||||
int statuscode = 0;
|
||||
string error = "";
|
||||
|
||||
HttpContext? httpContext = _httpContext.HttpContext;
|
||||
string loginName = "";
|
||||
if (httpContext != null)
|
||||
{
|
||||
UserDto? user = (UserDto?)httpContext.Items["User"];
|
||||
if (user != null)
|
||||
loginName = user.FirstName + " " + user.LastName;
|
||||
}
|
||||
PersonDto item = container.Person;
|
||||
try
|
||||
{
|
||||
|
||||
|
||||
Person model;
|
||||
if (item.Id < 1)
|
||||
{
|
||||
model = new();
|
||||
model = FillModel(model, item);
|
||||
|
||||
// model.Active = true;
|
||||
// model.AddedBy = loginName;
|
||||
// model.AddedOn = DateTime.Now;
|
||||
_context.Persons.Add(model);
|
||||
var successid = await _context.SaveChangesAsync();
|
||||
result = model.Id;
|
||||
if (!string.IsNullOrEmpty(container.FileName))
|
||||
{
|
||||
|
||||
string image = SaveFile(container.FileName, result, container.FormData);
|
||||
// update the image in table to new
|
||||
model.Image = image;
|
||||
await _context.SaveChangesAsync();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
var model1 = await _context.Persons.FindAsync(item.Id);
|
||||
if (model1 != null)
|
||||
{
|
||||
model1 = FillModel(model1, item);
|
||||
|
||||
result = item.Id;
|
||||
if (!string.IsNullOrEmpty(container.FileName))
|
||||
{
|
||||
string image = SaveFile(container.FileName, result, container.FormData);
|
||||
// update the image in table to new
|
||||
model1.Image = image;
|
||||
}
|
||||
var successid = await _context.SaveChangesAsync();
|
||||
}
|
||||
// model.LastModified = DateTime.Now;
|
||||
// model.LastModifiedId = loginName;
|
||||
}
|
||||
|
||||
statuscode = 1;
|
||||
if (item.RelationShips != null)
|
||||
{
|
||||
ResultModel<int> rresult = await this._relationship.SaveAsync(item.RelationShips);
|
||||
statuscode = rresult.StatusCode;
|
||||
error += rresult.Message;
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
error = ex.ToString();
|
||||
statuscode = -1;
|
||||
}
|
||||
//var dto = await Task.Run(() => result);
|
||||
return new ResultModel<int>()
|
||||
{
|
||||
Data = result,
|
||||
StatusCode = statuscode,
|
||||
Message = error
|
||||
};
|
||||
}
|
||||
|
||||
public async Task<ResultModel<int>> DeleteAsync(int id)
|
||||
{
|
||||
int result = 1;
|
||||
int statuscode = 0;
|
||||
string error = "";
|
||||
try
|
||||
{
|
||||
var model = await _context.Persons.FindAsync(id);
|
||||
if (model != null)
|
||||
_context.Persons.Remove(model);
|
||||
|
||||
var successCount = await _context.SaveChangesAsync();
|
||||
statuscode = 1;
|
||||
result = 1;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
error = ex.ToString();
|
||||
statuscode = -1;
|
||||
|
||||
}
|
||||
//var dto = await Task.Run(() => result);
|
||||
return new ResultModel<int>()
|
||||
{
|
||||
Data = result,
|
||||
StatusCode = statuscode,
|
||||
Message = error
|
||||
};
|
||||
}
|
||||
|
||||
public Task<ResultModel<string>> UploadImage(UploadCriteria criteria) {
|
||||
return UploadImagep(criteria);
|
||||
}
|
||||
|
||||
private string GetCurrentDateTime()
|
||||
{
|
||||
DateTime now = DateTime.Now;
|
||||
return now.ToString("yyyyMMdd");
|
||||
}
|
||||
|
||||
private async Task<ResultModel<string>> UploadImagep(UploadCriteria criteria)
|
||||
{
|
||||
string path = "";
|
||||
|
||||
int statusCode = 0;
|
||||
string error = "";
|
||||
string sdate = GetCurrentDateTime();
|
||||
string filename, extention;
|
||||
filename = extention = "";
|
||||
try
|
||||
{
|
||||
if (criteria.File.Length > 0)
|
||||
{
|
||||
path = _config["AppSettings:ImageFolder"];
|
||||
if (!Directory.Exists(path))
|
||||
{
|
||||
Directory.CreateDirectory(path);
|
||||
}
|
||||
extention = System.IO.Path.GetExtension(criteria.FileName);
|
||||
filename = criteria.FamilyId + "_" + sdate + extention;
|
||||
|
||||
using (var fileStream = new FileStream(System.IO.Path.Combine(path, filename), FileMode.Create))
|
||||
{
|
||||
await criteria.File.CopyToAsync(fileStream);
|
||||
}
|
||||
|
||||
statusCode = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
statusCode = -1;
|
||||
error = "file contain is empty";
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
statusCode = -1;
|
||||
error = ex.Message;
|
||||
|
||||
}
|
||||
|
||||
return new ResultModel<string>()
|
||||
{
|
||||
Data = filename,
|
||||
StatusCode = statusCode,
|
||||
Message = error
|
||||
};
|
||||
}
|
||||
|
||||
public ResultModel<int> DeleteUploadFile(DeleteFileCriteria criteria)
|
||||
{
|
||||
int result = -1;
|
||||
int statusCode = 0;
|
||||
string error = "";
|
||||
var filePath = _config["AppSettings:ImageFolder"];
|
||||
var myfile = filePath + "\\" + criteria.Filename;
|
||||
try
|
||||
{
|
||||
File.Delete(myfile);
|
||||
result = 1;
|
||||
|
||||
statusCode = 1;
|
||||
Person? model = _context.Persons.Find(criteria.FamilyId);
|
||||
if (model != null)
|
||||
{
|
||||
model.Image = null;
|
||||
_context.SaveChanges();
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
result = -1;
|
||||
statusCode = -1;
|
||||
error += e.Message;
|
||||
}
|
||||
return new ResultModel<int>()
|
||||
{
|
||||
Data = result,
|
||||
StatusCode = statusCode,
|
||||
Message = error
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,139 @@
|
||||
using FamilyTreeAPI.Entities;
|
||||
using FamilyTreeAPI.Models;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using System.Drawing.Text;
|
||||
namespace FamilyTreeAPI.Repository;
|
||||
|
||||
public partial class PersonRepository
|
||||
{
|
||||
private TreeNode<string> PopulateItem(Person model)
|
||||
{
|
||||
TreeNode<string> treeNode = new();
|
||||
treeNode.Label = model.FirstName;
|
||||
treeNode.Data = model.Id.ToString();
|
||||
treeNode.Key = model.Id.ToString();
|
||||
treeNode.Children = new();
|
||||
return treeNode;
|
||||
}
|
||||
private bool UseFamilyCriteria(FamilyCriteria criteria, Person person)
|
||||
{
|
||||
bool result = false;
|
||||
if (criteria.UseFather && criteria.UseMother)
|
||||
{
|
||||
result = person.FatherId.GetValueOrDefault(0) == 0
|
||||
&& person.MotherId.GetValueOrDefault(0) == 0;
|
||||
}
|
||||
else if (criteria.UseFather)
|
||||
{
|
||||
result = person.FatherId.GetValueOrDefault(0) == 0;
|
||||
}
|
||||
else if (criteria.UseMother)
|
||||
{
|
||||
result = person.MotherId.GetValueOrDefault(0) == 0;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
private bool UseChildFamilyCriteria(FamilyCriteria criteria, int id, Person person)
|
||||
{
|
||||
bool result = false;
|
||||
int parentId;
|
||||
if (criteria.UseFather)
|
||||
{
|
||||
parentId = person.FatherId.GetValueOrDefault(0);
|
||||
result = parentId == id;
|
||||
}
|
||||
else if (criteria.UseMother)
|
||||
{
|
||||
parentId = person.MotherId.GetValueOrDefault(0);
|
||||
result = parentId == id;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
private List<Person> SplitListOfTopLevel(List<Person> list, FamilyCriteria criteria)
|
||||
{
|
||||
List<Person> result = new();
|
||||
Person item;
|
||||
for (int i = list.Count - 1; i > -1; i--)
|
||||
{
|
||||
item = list[i];
|
||||
if (UseFamilyCriteria(criteria,item))
|
||||
{
|
||||
result.Add(item);
|
||||
list.RemoveAt(i);
|
||||
}
|
||||
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private List<Person> GetParentId(List<Person> list,int id, FamilyCriteria criteria, Func<FamilyCriteria, int, Person, bool> conditionFn)
|
||||
{
|
||||
List<Person> result = new();
|
||||
Person item;
|
||||
for (int i = list.Count - 1; i > -1; i--)
|
||||
{
|
||||
item = list[i];
|
||||
if (conditionFn(criteria,id, item))
|
||||
{
|
||||
result.Add(item);
|
||||
list.RemoveAt(i);
|
||||
}
|
||||
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private List<TreeNode<string>> PopulateChild(FamilyCriteria criteria,int id, List<Person> childList, Func<FamilyCriteria, int ,Person,bool> conditionFn)
|
||||
{
|
||||
Person person;
|
||||
TreeNode<string> treeNode;
|
||||
List<TreeNode<string>> list = new();
|
||||
List<Person> children = GetParentId(childList,id, criteria, conditionFn);
|
||||
for (int i = 0; i < children.Count; i++)
|
||||
{
|
||||
person = children[i];
|
||||
treeNode = PopulateItem(person);
|
||||
list.Add(treeNode);
|
||||
// get children of this one too
|
||||
treeNode.Children = PopulateChild(criteria, person.Id, childList, UseChildFamilyCriteria);
|
||||
}
|
||||
return list;
|
||||
}
|
||||
public async Task<ResultModel<List<TreeNode<string>>> > GetFamilyTreeBy(FamilyCriteria criteria)
|
||||
{
|
||||
int statusCode = -1;
|
||||
string error = "";
|
||||
Person person;
|
||||
TreeNode<string> treeNode;
|
||||
List<TreeNode<string>> data = new();
|
||||
try
|
||||
{
|
||||
var personList = await _context.Persons.ToListAsync();
|
||||
var topList = SplitListOfTopLevel(personList, criteria);
|
||||
for (int i = 0; i < topList.Count; i++)
|
||||
{
|
||||
person = topList[i];
|
||||
treeNode = PopulateItem(person);
|
||||
data.Add(treeNode);
|
||||
treeNode.Children = PopulateChild(criteria, person.Id, personList, UseChildFamilyCriteria);
|
||||
|
||||
}
|
||||
statusCode = 1;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
error = ex.ToString();
|
||||
statusCode = -1;
|
||||
}
|
||||
|
||||
return new ResultModel<List<TreeNode<string>>>
|
||||
{
|
||||
Data = data,
|
||||
StatusCode = statusCode,
|
||||
Message = error
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,184 @@
|
||||
using FamilyTreeAPI.Entities;
|
||||
using FamilyTreeAPI.Interface;
|
||||
using FamilyTreeAPI.Models;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
|
||||
namespace FamilyTreeAPI.Repository;
|
||||
|
||||
public class RelationShipRepository: IRelationShipd
|
||||
{
|
||||
private readonly FamilyTreeDBContext _context;
|
||||
private readonly IHttpContextAccessor _httpContext;
|
||||
private readonly IConfiguration _config;
|
||||
public RelationShipRepository(IConfiguration config, FamilyTreeDBContext context, IHttpContextAccessor httpContext)
|
||||
{
|
||||
_context = context;
|
||||
_config = config;
|
||||
_httpContext = httpContext;
|
||||
}
|
||||
private RelationShip FillModel(RelationShipDto dto, RelationShip model)
|
||||
{
|
||||
model.RelatePersonId = dto.RelatePersonId;
|
||||
model.PersonId = dto.PersonId;
|
||||
return model;
|
||||
}
|
||||
|
||||
private RelationShipDto FillDto(RelationShip model)
|
||||
{
|
||||
RelationShipDto dto = new();
|
||||
dto.Id = model.Id;
|
||||
dto.PersonId = model.PersonId;
|
||||
dto.RelatePersonId = model.RelatePersonId;
|
||||
return dto;
|
||||
}
|
||||
public async Task<ResultModel<int>> SaveAsync(List<RelationShipDto> list)
|
||||
{
|
||||
int statusCode = 0;
|
||||
string error = "";
|
||||
RelationShipDto item;
|
||||
RelationShip model;
|
||||
try
|
||||
{
|
||||
for (int i = 0; i < list.Count; i++)
|
||||
{
|
||||
item = list[i];
|
||||
if (item.Id < 1)
|
||||
{
|
||||
model = new();
|
||||
model = FillModel(item, model);
|
||||
_context.RelationShips.Add(model);
|
||||
}
|
||||
else if (item.State == enumState.Modify)
|
||||
{
|
||||
RelationShip? RelationShip = await _context.RelationShips.FindAsync(item.Id);
|
||||
if (RelationShip != null)
|
||||
{
|
||||
RelationShip = FillModel(item, RelationShip);
|
||||
}
|
||||
}
|
||||
else if (item.State == enumState.Delete)
|
||||
{
|
||||
RelationShip? RelationShip = await _context.RelationShips.FindAsync(item.Id);
|
||||
if (RelationShip != null)
|
||||
{
|
||||
_context.RelationShips.Remove(RelationShip);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
statusCode = 1;
|
||||
await _context.SaveChangesAsync();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
error = ex.ToString();
|
||||
statusCode = -1;
|
||||
}
|
||||
|
||||
return new ResultModel<int>
|
||||
{
|
||||
StatusCode = statusCode,
|
||||
Data = statusCode,
|
||||
Message = error
|
||||
};
|
||||
}
|
||||
|
||||
public async Task<ResultModel<List<RelationShipDto>>> GetByPersonIdAsync(int personId)
|
||||
{
|
||||
string error = "";
|
||||
int statusCode = -1;
|
||||
List<RelationShipDto> list = new();
|
||||
RelationShipDto dto;
|
||||
RelationShip model;
|
||||
try
|
||||
{
|
||||
|
||||
|
||||
var mlist = await _context.RelationShips.Where(x => x.PersonId == personId).ToListAsync();
|
||||
for (int i = 0; i < mlist.Count; i++)
|
||||
{
|
||||
model = mlist[i];
|
||||
dto = FillDto(model);
|
||||
list.Add(dto);
|
||||
}
|
||||
var rlist = await _context.RelationShips.Where(x => x.RelatePersonId == personId).ToListAsync();
|
||||
for (int i = 0; i < rlist.Count; i++)
|
||||
{
|
||||
model = rlist[i];
|
||||
dto = FillDto(model);
|
||||
list.Add(dto);
|
||||
}
|
||||
|
||||
statusCode = 1;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
error = ex.ToString();
|
||||
statusCode = -1;
|
||||
}
|
||||
|
||||
return new ResultModel<List<RelationShipDto>>
|
||||
{
|
||||
StatusCode = statusCode,
|
||||
Data = list,
|
||||
Message = error
|
||||
};
|
||||
}
|
||||
|
||||
public async Task<ResultModel<RelationShipDto>> GetByIdAsync(int Id)
|
||||
{
|
||||
string error = "";
|
||||
int statusCode = -1;
|
||||
|
||||
RelationShipDto dto =new();
|
||||
RelationShip? model;
|
||||
try
|
||||
{
|
||||
|
||||
|
||||
model = await _context.RelationShips.FindAsync(Id);
|
||||
if (model != null)
|
||||
dto = FillDto(model);
|
||||
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
error = ex.ToString();
|
||||
statusCode = -1;
|
||||
}
|
||||
|
||||
return new ResultModel<RelationShipDto>
|
||||
{
|
||||
StatusCode = statusCode,
|
||||
Data = dto,
|
||||
Message = error
|
||||
};
|
||||
}
|
||||
|
||||
public async Task<ResultModel<int>> DeleteAsync(int Id)
|
||||
{
|
||||
int result = -1;
|
||||
string error = "";
|
||||
int statusCode = -1;
|
||||
try
|
||||
{
|
||||
RelationShip? RelationShip = await _context.RelationShips.FindAsync(Id);
|
||||
if (RelationShip != null)
|
||||
{
|
||||
_context.RelationShips.Remove(RelationShip);
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
error = e.ToString();
|
||||
statusCode = -1;
|
||||
}
|
||||
|
||||
return new ResultModel<int>
|
||||
{
|
||||
StatusCode = statusCode,
|
||||
Data = result,
|
||||
Message = error
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,272 @@
|
||||
using FamilyTreeAPI.Entities;
|
||||
using FamilyTreeAPI.Interface;
|
||||
using FamilyTreeAPI.Models;
|
||||
using SpreadsheetLight;
|
||||
using System.Linq;
|
||||
using DocumentFormat.OpenXml.Spreadsheet;
|
||||
|
||||
namespace FamilyTreeAPI.Repository;
|
||||
|
||||
public class ReportRepository : IReport
|
||||
{
|
||||
private enum EnumStaffWork
|
||||
{
|
||||
Id = 0,
|
||||
FirstName,
|
||||
LastName,
|
||||
StartDate,
|
||||
startTime,
|
||||
stopTime,
|
||||
Task,
|
||||
Job,
|
||||
Hour
|
||||
};
|
||||
private readonly FamilyTreeDBContext _context;
|
||||
//private readonly ILookup _lookup;
|
||||
const string DateTimeFormat = "dd/MM/yyyy HH:mm";
|
||||
const string TimeFormat = "HH:mm";
|
||||
const string DateFormat = "dd/MM/yyyy";
|
||||
private readonly IStaff _staff;
|
||||
private Dictionary<int, StaffDto> _dstaff;
|
||||
private readonly ILookup _lookup;
|
||||
private string DisplayTime(DateTime date)
|
||||
{
|
||||
string result = "";
|
||||
if (date != DateTime.MinValue)
|
||||
result = date.ToString(TimeFormat);
|
||||
return result;
|
||||
}
|
||||
|
||||
private string DisplayDateTime(DateTime? date)
|
||||
{
|
||||
string result = "";
|
||||
if (date != DateTime.MinValue)
|
||||
result = date!.Value.ToString(DateFormat);
|
||||
return result;
|
||||
}
|
||||
private string FormatTime(int hour)
|
||||
{
|
||||
string result;
|
||||
if (hour < 10)
|
||||
result = "0" + hour.ToString() + ":00";
|
||||
else
|
||||
result = hour.ToString() + ":00";
|
||||
return result;
|
||||
}
|
||||
|
||||
public ReportRepository(FamilyTreeDBContext context, ILookup lookup,IStaff staff)
|
||||
{
|
||||
_context = context;
|
||||
_lookup = lookup;
|
||||
_staff = staff;
|
||||
}
|
||||
|
||||
// public async Task<ResultModel<FileContent>> GetStaffWorkReportAsync(StaffWorkCriteria criteria)
|
||||
// {
|
||||
// //var data = await _lookup.GetLookupDicAsync("TypeOfUse");
|
||||
// //if (data != null)
|
||||
// //{
|
||||
// // this._ServiceTypeDic = data.Data;
|
||||
// //}
|
||||
// var rstaff = await _staff.GetDicStaffs();
|
||||
// if (rstaff.StatusCode == 1)
|
||||
// _dstaff = rstaff.Data;
|
||||
// //data = await _lookup.GetLookupDicAsync("Status");
|
||||
// //if (data != null)
|
||||
// //{
|
||||
// // this._StatusDic = data.Data;
|
||||
// //}
|
||||
// int statusCode = 1;
|
||||
// int col = 1;
|
||||
// int row = 1;
|
||||
// SLDocument sl = new SLDocument();
|
||||
// SLStyle styleRed = sl.CreateStyle();
|
||||
// styleRed.SetFontColor(System.Drawing.Color.Red);
|
||||
|
||||
|
||||
|
||||
// //first sheetName
|
||||
// sl.RenameWorksheet(SLDocument.DefaultFirstSheetName, "Staff Work Report");
|
||||
// SLStyle style = sl.CreateStyle();
|
||||
// style.SetFontUnderline(DocumentFormat.OpenXml.Spreadsheet.UnderlineValues.Single);
|
||||
// style.SetFontBold(true);
|
||||
// style.SetFont("Calibri", 14);
|
||||
// sl.SetCellStyle(1, 3, style);
|
||||
// sl.SetRowHeight(1, 1, 25);
|
||||
// sl.SetCellValue(row++, 3, "Staff Work");
|
||||
// // sl.SetCellValue(row, 3, "From Date: " + fromDate.ToString(DateFormat) + " - " + toDate.ToString(DateFormat));
|
||||
// sl.SetCellValue(1, 6, " " + DateTime.Now.ToString("ddd dd/MM/yyyy HH:mm"));
|
||||
// // sl.SetCellValue(row, 6, "Hospital: " + facility);
|
||||
|
||||
|
||||
// int startTitleRow = 3;
|
||||
// row = startTitleRow;
|
||||
// //make the title bold
|
||||
// style = sl.CreateStyle();
|
||||
// style.Font.Bold = true;
|
||||
// sl.SetRowStyle(startTitleRow, style);
|
||||
// //set it height
|
||||
// sl.SetRowHeight(startTitleRow, startTitleRow, 25);
|
||||
// // add the title first
|
||||
|
||||
// sl.SetCellValue(row, (int)EnumStaffWork.Id, "Id");
|
||||
// sl.SetCellValue(row, (int) EnumStaffWork.FirstName, "FirstName");
|
||||
// sl.SetCellValue(row, (int) EnumStaffWork.LastName, "SurName");
|
||||
// sl.SetCellValue(row, (int) EnumStaffWork.StartDate, "StartDate");
|
||||
// sl.SetCellValue(row, (int)EnumStaffWork.startTime, "Start Time");
|
||||
// sl.SetCellValue(row, (int)EnumStaffWork.stopTime, "Stop Time");
|
||||
// sl.SetCellValue(row, (int)EnumStaffWork.Hour, "Hour");
|
||||
|
||||
// /*
|
||||
// style = sl.CreateStyle();
|
||||
// style.SetFontColor(System.Drawing.Color.Blue);
|
||||
// sl.SetRowStyle(row, style);
|
||||
// */
|
||||
// sl.FreezePanes(row, 0); //frozen the row.
|
||||
// //wrap text on is concession Expiry
|
||||
// style = sl.CreateStyle();
|
||||
// style.SetWrapText(true);
|
||||
// sl.SetColumnStyle(4, style);
|
||||
|
||||
// //format date
|
||||
|
||||
// // style = sl.CreateStyle();
|
||||
// //style.FormatCode = DateTimeFormat;
|
||||
// // sl.SetColumnStyle(1, style);
|
||||
// //make column width
|
||||
// sl.SetColumnWidth((int)EnumStaffWork.Id, 10);
|
||||
// sl.SetColumnWidth((int)EnumStaffWork.FirstName, 30);
|
||||
// sl.SetColumnWidth((int)EnumStaffWork.LastName, 30);
|
||||
// sl.SetColumnWidth((int)EnumStaffWork.StartDate, 25);
|
||||
// sl.SetColumnWidth((int)EnumStaffWork.startTime, 10);
|
||||
// sl.SetColumnWidth((int)EnumStaffWork.stopTime, 10);
|
||||
// sl.SetColumnWidth((int)EnumStaffWork.Hour, 20);
|
||||
|
||||
|
||||
// style = sl.CreateStyle();
|
||||
// style.FormatCode = DateFormat;
|
||||
// sl.SetColumnStyle(5, style);
|
||||
// //style = sl.CreateStyle();
|
||||
// //style.FormatCode = DateTimeFormat;
|
||||
// //sl.SetColumnStyle(1, style);
|
||||
// sl.SetColumnWidth(10, 20);
|
||||
|
||||
// int startRowFrom = startTitleRow + 1;
|
||||
|
||||
//// DateTime ttdate = toDate.ToLocalTime(); //add 1 days so if to inclusive todate 02/09
|
||||
// var container = await _context.LoadStaffWorkAsync(criteria); //fromDate.ToLocalTime(), ttdate.AddDays(1), typeOfCall);
|
||||
// var list = container;
|
||||
// list.Sort((x, y) => x.StartDate.Value.CompareTo(y.StartDate.Value));
|
||||
// StaffWorkViewDto item;
|
||||
// DateTime startTime, stopTime;
|
||||
// double hour =0;
|
||||
// string fname, lname;
|
||||
// StaffWorkDetailDto detail;
|
||||
// for (int i = 0; i < list.Count; i++)
|
||||
// {
|
||||
|
||||
// item = list[i];
|
||||
// row = i + startRowFrom;
|
||||
// (startTime, stopTime ) = GetSSTime(item);
|
||||
// if (item.Details != null)
|
||||
// for (int j = 0; j < item.Details.Count; j++)
|
||||
// {
|
||||
// detail = item.Details[j];
|
||||
// hour += detail.TotalMinuts();
|
||||
// }
|
||||
// (fname, lname) = GetStaffName(item.StaffId.Value);
|
||||
// sl.SetCellValue(row, (int)EnumStaffWork.StartDate, item.StartDate.Value);
|
||||
// sl.SetCellValue(row, (int)EnumStaffWork.FirstName, fname);
|
||||
// sl.SetCellValue(row, (int)EnumStaffWork.LastName, lname);
|
||||
// sl.SetCellValue(row, (int)EnumStaffWork.startTime, startTime);
|
||||
// sl.SetCellValue(row, (int)EnumStaffWork.stopTime, stopTime);
|
||||
// sl.SetCellValue(row, (int)EnumStaffWork.Hour, hour/60);
|
||||
|
||||
// }
|
||||
|
||||
// byte[] array;
|
||||
// // sl.SaveAs("C:\\Temp\\Report\\ConcessionValidationDate" + DateTime.Now.ToString("yyyyMMddHHmm") + ".xlsx");
|
||||
// using (MemoryStream ws = new MemoryStream())
|
||||
// {
|
||||
// sl.SaveAs(ws);
|
||||
// array = ws.ToArray();
|
||||
// /*
|
||||
// using (FileStream fs = new FileStream("c:\\temp\\Report\\conReport.xlsx",FileMode.Create,FileAccess.Write))
|
||||
// {
|
||||
// ws.WriteTo(fs);
|
||||
// fs.Close();
|
||||
// }
|
||||
// */
|
||||
// ws.Close();
|
||||
// }
|
||||
|
||||
// var result = new FileContent
|
||||
// {
|
||||
// Content = array,
|
||||
// FileName = "StaffWork_Report" + DateTime.Now.ToString("yyyy_MM_dd_HH_mm") + ".xlsx",
|
||||
// };
|
||||
|
||||
// return new ResultModel<FileContent>
|
||||
// {
|
||||
// Data = result,
|
||||
// StatusCode = statusCode
|
||||
// };
|
||||
|
||||
// }
|
||||
private (string, string) GetStaffName(int staffId)
|
||||
{
|
||||
|
||||
StaffDto staff;
|
||||
if (_dstaff.ContainsKey(staffId))
|
||||
{
|
||||
staff = _dstaff[staffId];
|
||||
return ( staff.Firstname ?? "" , staff.Lastname ?? "");
|
||||
}
|
||||
return ("","");
|
||||
}
|
||||
//private (DateTime firstTime, DateTime lastTime) GetSSTime(StaffWorkViewDto item)
|
||||
//{
|
||||
// DateTime sTime, lTime;
|
||||
// DateTime? value;
|
||||
// int count = 0;
|
||||
// sTime = lTime = DateTime.Now;
|
||||
// List<StaffWorkDetailDto> detail = item.Details ?? new();
|
||||
// count = detail.Count;
|
||||
// if (count > 0)
|
||||
// {
|
||||
|
||||
// value = detail[0].StartTime;
|
||||
// if (value.HasValue)
|
||||
// {
|
||||
// sTime = value.Value;
|
||||
// }
|
||||
// value = detail[count - 1].StopTime;
|
||||
// if (value.HasValue)
|
||||
// {
|
||||
// lTime = value.Value;
|
||||
// }
|
||||
// }
|
||||
// return (sTime, lTime);
|
||||
//}
|
||||
private string GetValue(string item, string text)
|
||||
{
|
||||
string result = item;
|
||||
if (!string.IsNullOrEmpty(text))
|
||||
result = text;
|
||||
return result;
|
||||
}
|
||||
//private string GetPools(List<string> poolIds)
|
||||
//{
|
||||
// string result = "";
|
||||
// string id;
|
||||
// for (int i = 0; i < poolIds.Count; i++)
|
||||
// {
|
||||
// id = poolIds[i];
|
||||
// if (this._PoolDic.ContainsKey(id))
|
||||
// result += _PoolDic[id].Description + ",";
|
||||
// }
|
||||
// result = result.Remove(result.Length-1, 1);
|
||||
// return result;
|
||||
//}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,83 @@
|
||||
using FamilyTreeAPI.Models;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
|
||||
namespace FamilyTreeAPI.Repository;
|
||||
|
||||
public class Seed
|
||||
{
|
||||
private readonly FamilyTreeDBContext _context;
|
||||
public Seed(FamilyTreeDBContext context)
|
||||
{
|
||||
_context = context;
|
||||
}
|
||||
public int InsertOneUser()
|
||||
{
|
||||
int id = -1;
|
||||
//password = password
|
||||
string txt = " INSERT INTO staff ( " +
|
||||
"firstname, lastname, email, phone, stype, srole, spassword, sactive) " +
|
||||
"VALUES" +
|
||||
" ( 'kham', 'vilaythong', 'kham.vilaythong@gmail.com', '009', 1, 2, 'cGFzc3dvcmQ=', true), " +
|
||||
" ( 'sy', 'vilaythong', 'sy.vilaythong@gmail.com', '007', 1, 2, 'cGFzc3dvcmQ=', true), " +
|
||||
" ( 'Hung', 'Nguyen', 'hung.gnuyen@gmail.com', '008', 1, 2, 'cGFzc3dvcmQ=', true); ";
|
||||
string workertxt = "INSERT INTO person ( firstname, lastname,email,phone,address,dob ,alive, fatherId, image, sex)" +
|
||||
"VALUES " +
|
||||
" ('Ho 1','Tran', 'Ho.Tran@hotmail.com', '002', '1 Cabramatta','1960-09-01', true, 0,'', 'M'), " +
|
||||
" ('Jimmy 2','Tran', 'Ho.Tran@hotmail.com', '003', '34 Cabramatta','1980-09-01', true, 1,'','M'), " +
|
||||
" ('Joe 3','Tran', 'Joe.Tran@hotmail.com', '006', '32 Cabramatta','1980-10-01', true, 1,'','M'), " +
|
||||
" ('John 4','Tran', 'John.Tran@hotmail.com', '008', '30 Cabramatta','1990-12-01', true, 3,'','M')," +
|
||||
" ('Lee 5','Tran', 'Lee.Tran@hotmail.com', '030', '18 Cabramatta','2000-12-01', true, 2,'','M'), " +
|
||||
" ('Len 6','Nguyen', 'Len.nguyen@hotmail.com', '001', '1 Home','1950-01-01', true, 0,'','M'), " +
|
||||
" ('Son 7','Nguyen', 'son.Nguyen@hotmail.com', '001', '10 Home','1980-01-01', true,6,'','M'), " +
|
||||
" ('Loa 8','Tran', 'Loa.Tran@hotmail.com', '020', '11 Cabramatta','2002-12-01', true, 3,'','M'), " +
|
||||
" ('Du 9','Tran', 'Du.Tran@hotmail.com', '001', '12 Cabramatta','2002-12-01', true, 4,'','M'), " +
|
||||
" ('Linh 10','Tran', 'Du.Tran@hotmail.com', '001', '12 Cabramatta','2002-12-01', true, 5,'','M'), " +
|
||||
" ('COA 11','Tran', 'Du.Tran@hotmail.com', '001', '12 Cabramatta','2002-12-01', true, 8,'','M'), " +
|
||||
" ('Hoa 12','Tran', 'Du.Tran@hotmail.com', '001', '12 Cabramatta','2002-12-01', true, 8,'','F'), " +
|
||||
" ('Nhi 13','Tran', 'Du.Tran@hotmail.com', '001', '12 Cabramatta','2002-12-01', true, 8,'','F'), " +
|
||||
" ('Mai 14','Tran', 'Du.Tran@hotmail.com', '001', '12 Cabramatta','2002-12-01', true, 8,'','F'), " +
|
||||
" ('Trang 15','Tran', 'Du.Tran@hotmail.com', '001', '12 Cabramatta','2002-12-01', true, 7,'','F'), " +
|
||||
" ('Tom 16','Tran', 'Ho.Tran@hotmail.com', '007', '34 Cabramatta','1999-01-01', true, 2,'','M');";
|
||||
|
||||
|
||||
try
|
||||
{
|
||||
int count = _context.staff.Count();
|
||||
if (count < 1)
|
||||
{
|
||||
var conn = _context.Database.GetDbConnection();
|
||||
try
|
||||
{
|
||||
|
||||
conn.Open();
|
||||
var command = conn.CreateCommand();
|
||||
command.CommandText = txt;
|
||||
command.CommandType = System.Data.CommandType.Text;
|
||||
command.ExecuteNonQuery();
|
||||
|
||||
command.CommandText = workertxt;
|
||||
command.CommandType = System.Data.CommandType.Text;
|
||||
|
||||
command.ExecuteNonQuery();
|
||||
id = 9;
|
||||
}
|
||||
catch
|
||||
{
|
||||
id = -1;
|
||||
}
|
||||
finally
|
||||
{
|
||||
conn.Close();
|
||||
}
|
||||
}
|
||||
else
|
||||
id = 1;
|
||||
|
||||
}
|
||||
catch
|
||||
{
|
||||
id = -10;
|
||||
}
|
||||
return id;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,381 @@
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
using FamilyTreeAPI.Models;
|
||||
using FamilyTreeAPI.Entities;
|
||||
using FamilyTreeAPI.Interface;
|
||||
using DocumentFormat.OpenXml.Drawing.Diagrams;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using DocumentFormat.OpenXml.Spreadsheet;
|
||||
using DocumentFormat.OpenXml.Wordprocessing;
|
||||
|
||||
namespace FamilyTreeAPI.Repository;
|
||||
|
||||
/* password = cGFzc3dvcmQ=
|
||||
*
|
||||
INSERT INTO public.staff(
|
||||
firstname, lastname, email, phone, stype, srole, spassword, sactive)
|
||||
VALUES ( 'kham', 'vilaythong', 'kham.vilaythong', '009', 1, 2, 'cGFzc3dvcmQ=', true);
|
||||
*/
|
||||
public class StaffRepository : IStaff
|
||||
{
|
||||
private readonly FamilyTreeDBContext _context;
|
||||
private readonly IHttpContextAccessor _httpContext;
|
||||
|
||||
|
||||
public StaffRepository(FamilyTreeDBContext context, IHttpContextAccessor httpContext)
|
||||
{
|
||||
_context = context;
|
||||
_httpContext = httpContext;
|
||||
}
|
||||
|
||||
private StaffDto FillDto(staff model)
|
||||
{
|
||||
StaffDto dto = new StaffDto();
|
||||
dto.Firstname = model.Firstname;
|
||||
dto.Lastname = model.Lastname;
|
||||
dto.Type = model.Stype;
|
||||
dto.Phone = model.Phone;
|
||||
dto.Active = model.Sactive ?? false;
|
||||
dto.Email = model.Email;
|
||||
/*
|
||||
dto.AddedOn = model.AddedOn;
|
||||
|
||||
dto.RoleType = model.RoleType;
|
||||
|
||||
*/
|
||||
dto.RoleType = model.Srole;
|
||||
dto.Id = model.Id;
|
||||
return dto;
|
||||
}
|
||||
private staff FillModel(staff model, StaffDto dto)
|
||||
{
|
||||
if (!string.IsNullOrEmpty(dto.Firstname))
|
||||
model.Firstname = dto.Firstname.Trim();
|
||||
if (!string.IsNullOrEmpty(dto.Lastname))
|
||||
model.Lastname = dto.Lastname.Trim();
|
||||
if (!string.IsNullOrEmpty(dto.Phone))
|
||||
model.Phone = dto.Phone.Trim();
|
||||
|
||||
if (dto.Id > 0)
|
||||
model.Id = dto.Id;
|
||||
|
||||
if (!string.IsNullOrEmpty(dto.Password))
|
||||
{
|
||||
string password = dto.Password.Trim();
|
||||
model.Spassword = Ultils.Base64Encode(password);
|
||||
}
|
||||
|
||||
model.Email = dto.Email;
|
||||
model.Srole = dto.RoleType;
|
||||
model.Sactive = dto.Active;
|
||||
return model;
|
||||
}
|
||||
|
||||
|
||||
public async Task<ResultModel<Dictionary<int,StaffDto>>> GetDicStaffs()
|
||||
{
|
||||
Dictionary<int,StaffDto> dlist = new();
|
||||
int statuscode = 0;
|
||||
string error = "";
|
||||
StaffDto item;
|
||||
staff model;
|
||||
try
|
||||
{
|
||||
var list = await _context.staff.ToListAsync();
|
||||
for (int i = 0; i< list.Count; i++)
|
||||
{
|
||||
model = list[i];
|
||||
item = FillDto(model);
|
||||
dlist.Add(item.Id, item);
|
||||
}
|
||||
statuscode = 1;
|
||||
//list.Sort((x, y) => x.Code.CompareTo(y.Code));
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
|
||||
error = ex.ToString();
|
||||
statuscode = -1;
|
||||
|
||||
}
|
||||
return new ResultModel<Dictionary<int,StaffDto>>()
|
||||
{
|
||||
Data = dlist,
|
||||
StatusCode = statuscode,
|
||||
Message = error
|
||||
};
|
||||
}
|
||||
|
||||
public async Task<ResultModel<List<StaffDto> >> GetStaff(StaffCriteria criteria)
|
||||
{
|
||||
List<StaffDto> list = new();
|
||||
int statuscode = 0;
|
||||
string error = "";
|
||||
try
|
||||
{
|
||||
list = await _context.LoadStaffAsync(criteria);
|
||||
statuscode = 1;
|
||||
//list.Sort((x, y) => x.Code.CompareTo(y.Code));
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
|
||||
error = ex.ToString();
|
||||
statuscode = -1;
|
||||
|
||||
}
|
||||
return new ResultModel<List<StaffDto>>()
|
||||
{
|
||||
Data = list,
|
||||
StatusCode = statuscode,
|
||||
Message = error
|
||||
};
|
||||
}
|
||||
|
||||
public async Task<ResultModel<StaffDto>> GetStaffById(int id)
|
||||
{
|
||||
int statuscode = 0;
|
||||
string error = "";
|
||||
StaffDto dto = new StaffDto();
|
||||
try
|
||||
{
|
||||
var item = await _context.staff.FindAsync(id);
|
||||
if (item == null)
|
||||
{
|
||||
statuscode = -1;
|
||||
}
|
||||
else
|
||||
{
|
||||
dto = FillDto(item);
|
||||
statuscode = 1;
|
||||
}
|
||||
}
|
||||
catch(Exception ex)
|
||||
{
|
||||
error = ex.ToString();
|
||||
statuscode = -1;
|
||||
|
||||
}
|
||||
return new ResultModel<StaffDto>()
|
||||
{
|
||||
Data = dto,
|
||||
StatusCode = statuscode,
|
||||
Message = error
|
||||
};
|
||||
}
|
||||
private string GetDateTimeNow()
|
||||
{
|
||||
return DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss");
|
||||
}
|
||||
public async Task<ResultModel<int>> ResetPassword(ResetPassDto item)
|
||||
{
|
||||
int result = -1;
|
||||
int statuscode = 0;
|
||||
string error = "";
|
||||
try
|
||||
{
|
||||
staff? model1 = await _context.staff.FindAsync(item.Id);
|
||||
if (model1 != null)
|
||||
{
|
||||
if (!string.IsNullOrEmpty(item.Password))
|
||||
{
|
||||
string password = item.Password.Trim();
|
||||
model1.Spassword = Ultils.Base64Encode(password);
|
||||
}
|
||||
|
||||
// model.LastModified = DateTime.Now;
|
||||
// model.LastModifiedId = loginName;
|
||||
var successid = await _context.SaveChangesAsync();
|
||||
result = item.Id;
|
||||
}
|
||||
statuscode = 1;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
statuscode = -1;
|
||||
error = ex.ToString();
|
||||
}
|
||||
return new ResultModel<int>()
|
||||
{
|
||||
Data = result,
|
||||
StatusCode = statuscode,
|
||||
Message = error
|
||||
};
|
||||
}
|
||||
public async Task<ResultModel<int>> SaveStaff(StaffDto item)
|
||||
{
|
||||
int result = default(int);
|
||||
int statuscode = 0;
|
||||
string error = "";
|
||||
|
||||
HttpContext? httpContext = _httpContext.HttpContext;
|
||||
string loginName = "";
|
||||
if (httpContext != null)
|
||||
{
|
||||
UserDto? user = (UserDto?)httpContext.Items["User"];
|
||||
if (user != null)
|
||||
loginName = user.FirstName + " " + user.LastName;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
if (item.Id < 1)
|
||||
{
|
||||
bool already = await CheckLoginAlready(item.Email.Trim());
|
||||
if (already)
|
||||
{
|
||||
return new ResultModel<int>()
|
||||
{
|
||||
Data = 0,
|
||||
StatusCode = 0,
|
||||
Message = "user name already exist in Database"
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
staff model;
|
||||
if (item.Id < 1)
|
||||
{
|
||||
model = new();
|
||||
model = FillModel(model, item);
|
||||
|
||||
// model.Active = true;
|
||||
// model.AddedBy = loginName;
|
||||
// model.AddedOn = DateTime.Now;
|
||||
_context.staff.Add(model);
|
||||
await _context.SaveChangesAsync();
|
||||
result = model.Id;
|
||||
}
|
||||
else
|
||||
{
|
||||
staff? model1 = await _context.staff.FindAsync(item.Id);
|
||||
model1 = FillModel(model1, item);
|
||||
// model.LastModified = DateTime.Now;
|
||||
// model.LastModifiedId = loginName;
|
||||
var successid = await _context.SaveChangesAsync();
|
||||
result = item.Id;
|
||||
}
|
||||
|
||||
|
||||
statuscode = 1;
|
||||
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
error = ex.ToString();
|
||||
statuscode = -1;
|
||||
|
||||
}
|
||||
//var dto = await Task.Run(() => result);
|
||||
return new ResultModel<int>()
|
||||
{
|
||||
Data = result,
|
||||
StatusCode = statuscode,
|
||||
Message = error
|
||||
};
|
||||
}
|
||||
private async Task<bool> CheckLoginAlready(string login)
|
||||
{
|
||||
bool result = false;
|
||||
var model = await _context.staff.Where(x => x.Email == login).ToListAsync();
|
||||
if (model.Count > 0)
|
||||
result = true;
|
||||
return result;
|
||||
}
|
||||
public async Task<ResultModel<int>> SaveStaffNew(StaffDto item)
|
||||
{
|
||||
int result = default(int);
|
||||
int statuscode = 0;
|
||||
string error = "";
|
||||
|
||||
try
|
||||
{
|
||||
if (item.Id < 1)
|
||||
{
|
||||
bool already = await CheckLoginAlready(item.Email.Trim());
|
||||
if (already)
|
||||
{
|
||||
return new ResultModel<int>()
|
||||
{
|
||||
Data = 0,
|
||||
StatusCode = 0,
|
||||
Message = "user name already exist in db"
|
||||
};
|
||||
}
|
||||
}
|
||||
staff model;
|
||||
if (item.Id < 1)
|
||||
{
|
||||
model = new();
|
||||
model = FillModel(model, item);
|
||||
// model.AddedOn = DateTime.Now;
|
||||
|
||||
// model.Active = true;
|
||||
_context.staff.Add(model);
|
||||
}
|
||||
else
|
||||
{
|
||||
model = await _context.staff.FindAsync(item.Id);
|
||||
model = FillModel(model, item);
|
||||
}
|
||||
var successid = await _context.SaveChangesAsync();
|
||||
|
||||
result = 1;
|
||||
statuscode = 1;
|
||||
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
error = ex.ToString();
|
||||
statuscode = -1;
|
||||
|
||||
}
|
||||
//var dto = await Task.Run(() => result);
|
||||
return new ResultModel<int>()
|
||||
{
|
||||
Data = result,
|
||||
StatusCode = statuscode,
|
||||
Message = error
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
public async Task<ResultModel<int>> Delete(int id)
|
||||
{
|
||||
int result = 1;
|
||||
int statuscode = 0;
|
||||
string error = "";
|
||||
try
|
||||
{
|
||||
staff model;
|
||||
model = await _context.staff.FindAsync(id);
|
||||
// if (model != null)
|
||||
// model.Active = false;
|
||||
|
||||
var successCount = await _context.SaveChangesAsync();
|
||||
statuscode = 1;
|
||||
result = 1;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
error = ex.ToString();
|
||||
statuscode = -1;
|
||||
|
||||
}
|
||||
//var dto = await Task.Run(() => result);
|
||||
return new ResultModel<int>()
|
||||
{
|
||||
Data = result,
|
||||
StatusCode = statuscode,
|
||||
Message = error
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,251 @@
|
||||
/**************************************/
|
||||
|
||||
CREATE TABLE IF NOT EXISTS public.client
|
||||
(
|
||||
id integer NOT NULL GENERATED ALWAYS AS IDENTITY ( INCREMENT 1 START 1 MINVALUE 1 MAXVALUE 2147483647 CACHE 1 ),
|
||||
clientname character(80) COLLATE pg_catalog."default",
|
||||
contact character(80) COLLATE pg_catalog."default",
|
||||
cactive boolean,
|
||||
address character(120),
|
||||
email character(80),
|
||||
phone character(30),
|
||||
CONSTRAINT client_pkey PRIMARY KEY (id)
|
||||
)
|
||||
TABLESPACE pg_default;
|
||||
|
||||
ALTER TABLE IF EXISTS public.client
|
||||
OWNER to postgres;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS public.lookup
|
||||
(
|
||||
id integer NOT NULL GENERATED ALWAYS AS IDENTITY ( INCREMENT 1 START 1 MINVALUE 1 MAXVALUE 2147483647 CACHE 1 ),
|
||||
code character(10) COLLATE pg_catalog."default",
|
||||
description character(80) COLLATE pg_catalog."default",
|
||||
lactive boolean,
|
||||
ltype character(20) COLLATE pg_catalog."default",
|
||||
CONSTRAINT lookup_pkey PRIMARY KEY (id)
|
||||
)
|
||||
|
||||
TABLESPACE pg_default;
|
||||
|
||||
ALTER TABLE IF EXISTS public.lookup
|
||||
OWNER to postgres;
|
||||
|
||||
|
||||
-- Table: public.job
|
||||
|
||||
-- DROP TABLE IF EXISTS public.job;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS public.job
|
||||
(
|
||||
id integer NOT NULL GENERATED ALWAYS AS IDENTITY ( INCREMENT 1 START 1 MINVALUE 1 MAXVALUE 2147483647 CACHE 1 ),
|
||||
code character(10) COLLATE pg_catalog."default",
|
||||
description character(80) COLLATE pg_catalog."default",
|
||||
jactive boolean,
|
||||
CONSTRAINT job_pkey PRIMARY KEY (id)
|
||||
)
|
||||
|
||||
TABLESPACE pg_default;
|
||||
|
||||
ALTER TABLE IF EXISTS public.job
|
||||
OWNER to postgres;
|
||||
|
||||
-- Table: public.servicetask
|
||||
|
||||
-- DROP TABLE IF EXISTS public.servicetask;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS public.servicetask
|
||||
(
|
||||
id integer NOT NULL GENERATED ALWAYS AS IDENTITY ( INCREMENT 1 START 1 MINVALUE 1 MAXVALUE 2147483647 CACHE 1 ),
|
||||
assignto integer,
|
||||
clientid integer,
|
||||
code character(10) COLLATE pg_catalog."default",
|
||||
description character(80) COLLATE pg_catalog."default",
|
||||
sdate date,
|
||||
serviceno character(20) COLLATE pg_catalog."default",
|
||||
staffid integer,
|
||||
status integer,
|
||||
CONSTRAINT servicetask_pkey PRIMARY KEY (id)
|
||||
)
|
||||
TABLESPACE pg_default;
|
||||
|
||||
ALTER TABLE IF EXISTS public.servicetask
|
||||
OWNER to postgres;
|
||||
|
||||
|
||||
-- Table: public.staffwork
|
||||
|
||||
-- DROP TABLE IF EXISTS public.staffwork;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS public.staffwork
|
||||
(
|
||||
id integer NOT NULL GENERATED ALWAYS AS IDENTITY ( INCREMENT 1 START 1 MINVALUE 1 MAXVALUE 2147483647 CACHE 1 ),
|
||||
description character(80) COLLATE pg_catalog."default",
|
||||
sactive boolean,
|
||||
staffid integer,
|
||||
startdate date,
|
||||
CONSTRAINT staffwork_pkey PRIMARY KEY (id)
|
||||
)
|
||||
|
||||
TABLESPACE pg_default;
|
||||
|
||||
ALTER TABLE IF EXISTS public.staffwork
|
||||
OWNER to postgres;
|
||||
|
||||
-- Table: public.staffworkdetail
|
||||
|
||||
-- DROP TABLE IF EXISTS public.staffworkdetail;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS public.staffworkdetail
|
||||
(
|
||||
id integer NOT NULL GENERATED ALWAYS AS IDENTITY ( INCREMENT 1 START 1 MINVALUE 1 MAXVALUE 2147483647 CACHE 1 ),
|
||||
jobid integer,
|
||||
sactive boolean,
|
||||
starttime timestamp without time zone,
|
||||
stoptime timestamp without time zone,
|
||||
task character(80) COLLATE pg_catalog."default",
|
||||
swid integer,
|
||||
CONSTRAINT staffworkdetail_pkey PRIMARY KEY (id)
|
||||
)
|
||||
|
||||
TABLESPACE pg_default;
|
||||
|
||||
ALTER TABLE IF EXISTS public.staffworkdetail
|
||||
OWNER to postgres;
|
||||
|
||||
/******************************************/
|
||||
ALTER TABLE servicetask
|
||||
ADD FOREIGN KEY (clientid) REFERENCES client(id);
|
||||
|
||||
ALTER TABLE servicetask
|
||||
ADD FOREIGN KEY (staffid) REFERENCES staff(id);
|
||||
|
||||
ALTER TABLE servicetask
|
||||
ADD FOREIGN KEY (assignto) REFERENCES staff(id);
|
||||
|
||||
ALTER TABLE staffwork
|
||||
ADD FOREIGN KEY (staffid) REFERENCES staff(id);
|
||||
|
||||
ALTER TABLE staffworkdetail
|
||||
ADD FOREIGN KEY (swid) REFERENCES staffwork(id);
|
||||
|
||||
ALTER TABLE staffworkdetail
|
||||
ADD FOREIGN KEY (jobid) REFERENCES job(id);
|
||||
|
||||
/************************************/
|
||||
|
||||
CREATE OR REPLACE FUNCTION usp_search_user (
|
||||
iemail character varying,
|
||||
ifirstname character varying,
|
||||
ilastname character varying)
|
||||
RETURNS TABLE(id integer, fistname character varying, lastname character varying, email character varying, stype integer, sactive boolean, srole integer, spassword character varying)
|
||||
LANGUAGE 'plpgsql'
|
||||
COST 100
|
||||
VOLATILE PARALLEL UNSAFE
|
||||
ROWS 1000
|
||||
|
||||
AS $BODY$
|
||||
begin
|
||||
return query SELECT
|
||||
e.id,
|
||||
e.firstname,
|
||||
e.lastname,
|
||||
e.email,
|
||||
e.stype,
|
||||
e.sactive,
|
||||
e.srole,
|
||||
e.spassword
|
||||
|
||||
|
||||
|
||||
FROM staff e
|
||||
WHERE (iemail = '' or e.email ilike iemail || '%')
|
||||
and (ilastname = '' or e.lastname ilike ilastname || '%')
|
||||
and (ifirstname = '' or e.firstname ilike ifirstname || '%');
|
||||
|
||||
end;
|
||||
$BODY$;
|
||||
|
||||
CREATE OR REPLACE FUNCTION usp_staffwork_detail(
|
||||
ifromdate date,
|
||||
itodate date,
|
||||
istaffid integer)
|
||||
RETURNS TABLE(id integer, staffid integer, description character varying(80),
|
||||
startdate date, sactive boolean, did integer, starttime timestamp, stoptime timestamp,
|
||||
task character varying(80))
|
||||
LANGUAGE 'plpgsql'
|
||||
COST 100
|
||||
VOLATILE PARALLEL UNSAFE
|
||||
ROWS 1000
|
||||
|
||||
AS $BODY$
|
||||
begin
|
||||
return query SELECT
|
||||
w.id,
|
||||
w.staffid,
|
||||
w.description,
|
||||
w.startdate,
|
||||
w.sactive,
|
||||
d.id as did,
|
||||
d.starttime,
|
||||
d.stoptime,
|
||||
d.task
|
||||
|
||||
FROM staffwork w,
|
||||
staffworkdetail d
|
||||
where w.id = d.swid
|
||||
and (istaffid = 0 or w.staffid = istaffid)
|
||||
and w.startdate >= ifromdate
|
||||
and w.startdate <= itodate
|
||||
order by id, did;
|
||||
|
||||
|
||||
end;
|
||||
$BODY$;
|
||||
|
||||
|
||||
CREATE OR REPLACE FUNCTION usp_servicetask_sel(
|
||||
ifromdate date,
|
||||
itodate date,
|
||||
istaffid integer,
|
||||
iassignto integer,
|
||||
iclientid integer
|
||||
)
|
||||
RETURNS TABLE(id integer,
|
||||
staffid integer,
|
||||
sdate date,
|
||||
description character varying(80),
|
||||
code character varying(10),
|
||||
status integer,
|
||||
assignTo integer,
|
||||
clientid integer,
|
||||
serviceno character varying(20))
|
||||
LANGUAGE 'plpgsql'
|
||||
COST 100
|
||||
VOLATILE PARALLEL UNSAFE
|
||||
ROWS 1000
|
||||
|
||||
|
||||
AS $BODY$
|
||||
begin
|
||||
return query SELECT
|
||||
s.id,
|
||||
s.staffid,
|
||||
s.sdate,
|
||||
s.description,
|
||||
s.code,
|
||||
s.status,
|
||||
s.assignto,
|
||||
s.clientid,
|
||||
s."serviceNo"
|
||||
FROM servicetask s
|
||||
|
||||
where (istaffid < 1 or s.staffid = istaffid)
|
||||
and (iassignto < 1 or s.assignto = iassignto)
|
||||
and (iclientid < 1 or s.clientid = iclientid)
|
||||
and s.sdate >= ifromdate
|
||||
and s.sdate <= itodate
|
||||
|
||||
;
|
||||
end;
|
||||
$BODY$;
|
||||
@@ -0,0 +1,16 @@
|
||||
namespace FamilyTreeAPI.Repository
|
||||
{
|
||||
public class Ultils
|
||||
{
|
||||
public static string Base64Encode(string plainText)
|
||||
{
|
||||
var plainTextBytes = System.Text.Encoding.UTF8.GetBytes(plainText);
|
||||
return System.Convert.ToBase64String(plainTextBytes);
|
||||
}
|
||||
public static string Base64Decode(string base64EncodedData)
|
||||
{
|
||||
var base64EncodedBytes = System.Convert.FromBase64String(base64EncodedData);
|
||||
return System.Text.Encoding.UTF8.GetString(base64EncodedBytes);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,257 @@
|
||||
//using BCryptNet = BCrypt.Net.BCrypt;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.Extensions.Options;
|
||||
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using FamilyTreeAPI.Interface;
|
||||
using FamilyTreeAPI.Entities;
|
||||
|
||||
using System;
|
||||
using FamilyTreeAPI.Models;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using System.Text.Json;
|
||||
|
||||
|
||||
namespace FamilyTreeAPI.Repository;
|
||||
public class UserServiceRepository : IUserService
|
||||
{
|
||||
private FamilyTreeDBContext _context;
|
||||
private IJwtUtils _jwtUtils;
|
||||
private readonly IHttpContextAccessor _httpcontext;
|
||||
private readonly AppSettings _appSettings;
|
||||
|
||||
public UserServiceRepository(
|
||||
FamilyTreeDBContext context,
|
||||
IJwtUtils jwtUtils,
|
||||
IHttpContextAccessor httpcontext,
|
||||
IOptions<AppSettings> appSettings)
|
||||
{
|
||||
_context = context;
|
||||
_jwtUtils = jwtUtils;
|
||||
_appSettings = appSettings.Value;
|
||||
this._httpcontext = httpcontext;
|
||||
|
||||
}
|
||||
public Task<ResultModel<int>> Logout(string token, UserDto user, string remoteIpAddress)
|
||||
{
|
||||
/*
|
||||
int retval = 1;
|
||||
int statuscode = 1;
|
||||
string str255 = token;
|
||||
var histo = await _context.AdminLoginHistories.Where(x => x.UserId == user.Id
|
||||
&& x.RecordIntegrity == token
|
||||
&& x.LoginTyped == user.Username).ToListAsync();
|
||||
if (histo.Count > 0)
|
||||
{
|
||||
histo[0].LogoutDatetime = DateTime.Now;
|
||||
await _context.SaveChangesAsync();
|
||||
}
|
||||
*/
|
||||
var result = new ResultModel<int>()
|
||||
{
|
||||
Data = 1,
|
||||
StatusCode = 1
|
||||
};
|
||||
|
||||
return Task.FromResult(result);
|
||||
|
||||
}
|
||||
private bool checkLogin(staff user, string email, string password)
|
||||
{
|
||||
bool result = false;
|
||||
// string dpassword = Ultils.Base64Encode(password);
|
||||
result = user.Spassword == password;
|
||||
return result;
|
||||
}
|
||||
public async Task<ResultModel<AuthenticateResponse>> Login(AuthenticateRequest model)
|
||||
{
|
||||
UserDto myUser = new();
|
||||
AuthenticateResponse retval = null;
|
||||
string error = "user name is not in DB or user Name profile is not generic";
|
||||
int statuscode = 0;
|
||||
|
||||
try
|
||||
{
|
||||
//now check the adminuser table
|
||||
myUser.Username = model.Username;
|
||||
var user = _context.staff.
|
||||
SingleOrDefault(x => x.Email == model.Username
|
||||
&& true == x.Sactive);
|
||||
if (user != null)
|
||||
{
|
||||
bool loginOK = checkLogin(user, model.Username, model.Password);
|
||||
if (loginOK)
|
||||
{
|
||||
|
||||
|
||||
// myUser.Role = user.RoleType;
|
||||
myUser.Id = user.Id;
|
||||
myUser.Role = user.Srole ?? 0;
|
||||
myUser.Email = user.Email;
|
||||
myUser.Phone = user.Phone;
|
||||
myUser.FirstName = user.Firstname;
|
||||
myUser.LastName = user.Lastname;
|
||||
//myUser.ValidationPointId = user.ValidationPointID ?? 0;
|
||||
statuscode = 1;
|
||||
}
|
||||
else //not allow
|
||||
{
|
||||
statuscode = -1;
|
||||
myUser.Role = 1;
|
||||
myUser.Id = -1;
|
||||
|
||||
error = "user name cannot login email or password";
|
||||
}
|
||||
// validate
|
||||
// if (user == null || !BCryptNet.Verify(model.Password, user.PasswordHash))
|
||||
|
||||
// authentication successful so generate jwt token
|
||||
if (statuscode == 1)
|
||||
{
|
||||
var jwtToken = _jwtUtils.GenerateJwtToken(myUser);
|
||||
retval = new AuthenticateResponse(myUser, jwtToken, myUser.Role);
|
||||
error = "";
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
error = "user name or password is not correct";
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
retval = null;
|
||||
error = ex.ToString();
|
||||
statuscode = -1;
|
||||
|
||||
}
|
||||
//writelog for login user.
|
||||
// if (myUser != null)
|
||||
// await AddToSession(myUser);
|
||||
return new ResultModel<AuthenticateResponse>()
|
||||
{
|
||||
Data = retval,
|
||||
StatusCode = statuscode,
|
||||
Message = error
|
||||
};
|
||||
|
||||
}
|
||||
public async Task<ResultModel<AuthenticateResponse>> LoginApiAD(AuthenticateRequest model, string remoteIpAddress)
|
||||
{
|
||||
UserDto myUser = new();
|
||||
AuthenticateResponse retval = null;
|
||||
string error = "user name is not in DB or user Name profile is not generic";
|
||||
int statuscode = 0;
|
||||
string webAPIUrl = _appSettings.LoginWebAPI;
|
||||
//KCO, D204KCO
|
||||
//now check the adminuser table
|
||||
//ward clerk
|
||||
try
|
||||
{
|
||||
//now check the adminuser table
|
||||
myUser.Username = model.Username;
|
||||
var user = _context.staff.
|
||||
SingleOrDefault(x => x.Email == model.Username
|
||||
&& true == x.Sactive);
|
||||
if (user != null)
|
||||
{
|
||||
bool loginOK = checkLogin(user,model.Username, model.Password);
|
||||
if (loginOK)
|
||||
{
|
||||
// myUser.Role = user.RoleType;
|
||||
myUser.Id = user.Id;
|
||||
myUser.Role = user.Srole ?? 0;
|
||||
myUser.Email = user.Email;
|
||||
myUser.Phone = user.Phone;
|
||||
myUser.FirstName = user.Firstname;
|
||||
myUser.LastName = user.Lastname;
|
||||
|
||||
//myUser.ValidationPointId = user.ValidationPointID ?? 0;
|
||||
statuscode = 1;
|
||||
}
|
||||
else // allow
|
||||
{
|
||||
statuscode = 1;
|
||||
myUser.Role = 1;
|
||||
myUser.Id = -1;
|
||||
|
||||
//error = "user name does not exist in adminUser";
|
||||
}
|
||||
// validate
|
||||
// if (user == null || !BCryptNet.Verify(model.Password, user.PasswordHash))
|
||||
|
||||
// authentication successful so generate jwt token
|
||||
if (statuscode == 1)
|
||||
{
|
||||
var jwtToken = _jwtUtils.GenerateJwtToken(myUser);
|
||||
retval = new AuthenticateResponse(myUser, jwtToken, myUser.Role);
|
||||
error = "";
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
error = "user name or password is not correct";
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
retval = null;
|
||||
error = ex.ToString();
|
||||
statuscode = -1;
|
||||
|
||||
}
|
||||
//writelog for login user.
|
||||
// if (myUser != null)
|
||||
// await AddToSession(myUser);
|
||||
return new ResultModel<AuthenticateResponse>()
|
||||
{
|
||||
Data = retval,
|
||||
StatusCode = statuscode,
|
||||
Message = error
|
||||
};
|
||||
|
||||
}
|
||||
//get like this
|
||||
private async Task GetCurrentUser()
|
||||
{
|
||||
await _httpcontext.HttpContext.Session.LoadAsync();
|
||||
|
||||
string userString = _httpcontext.HttpContext.Session.GetString("user");
|
||||
|
||||
if (userString != null && userString != "")
|
||||
{
|
||||
var user = JsonSerializer.Deserialize<UserDto>(userString);
|
||||
if (user != null)
|
||||
{
|
||||
// return user;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
private User LoginADStaff(ADConfig adConfig, string username, string password)
|
||||
{
|
||||
|
||||
ADStaffLink staffLink = new ADStaffLink(adConfig);
|
||||
MyADObject myADObj = staffLink.CheckADCredentials(username,password);
|
||||
User user = new()
|
||||
{
|
||||
Username = myADObj.StafflinkNo,
|
||||
Email = myADObj.Email,
|
||||
FirstName = myADObj.FirstName,
|
||||
LastName = myADObj.LastName
|
||||
};
|
||||
// myADObj.JobTitle;
|
||||
return user;
|
||||
|
||||
// return null;
|
||||
}
|
||||
*/
|
||||
}
|
||||
@@ -0,0 +1,118 @@
|
||||
/*
|
||||
declare @id int
|
||||
set @id = 7
|
||||
delete from MotorAccess where mv_id = @id
|
||||
delete from [dbo].[MotorVehicle]
|
||||
where mv_id = @id
|
||||
*/
|
||||
|
||||
|
||||
CREATE OR REPLACE FUNCTION public.usp_search_user(
|
||||
iemail character varying,
|
||||
ifirstname character varying,
|
||||
ilastname character varying)
|
||||
RETURNS TABLE(id integer, fistname character varying, lastname character varying, email character varying, stype integer, sactive boolean, srole integer, spassword character varying)
|
||||
LANGUAGE 'plpgsql'
|
||||
COST 100
|
||||
VOLATILE PARALLEL UNSAFE
|
||||
ROWS 1000
|
||||
|
||||
AS $BODY$
|
||||
begin
|
||||
return query SELECT
|
||||
e.id,
|
||||
e.firstname,
|
||||
e.lastname,
|
||||
e.email,
|
||||
e.stype,
|
||||
e.sactive,
|
||||
e.srole,
|
||||
e.spassword
|
||||
|
||||
|
||||
|
||||
FROM staff e
|
||||
WHERE (iemail = '' or e.email ilike iemail || '%')
|
||||
and (ilastname = '' or e.lastname ilike ilastname || '%')
|
||||
and (ifirstname = '' or e.firstname ilike ifirstname || '%');
|
||||
|
||||
end;
|
||||
$BODY$;
|
||||
|
||||
CREATE OR REPLACE FUNCTION get_staff (
|
||||
iemail character varying,
|
||||
ifirstname character varying,
|
||||
ilastname character varying
|
||||
)
|
||||
RETURNS TABLE (
|
||||
id int,
|
||||
firstname varchar,
|
||||
lastname varchar,
|
||||
email varchar,
|
||||
stype INT,
|
||||
sactive boolean,
|
||||
srole INT,
|
||||
spassword varchar )
|
||||
AS $$
|
||||
BEGIN
|
||||
RETURN QUERY
|
||||
e.id,
|
||||
e.firstname,
|
||||
e.lastname,
|
||||
e.email,
|
||||
e.stype,
|
||||
e.sactive,
|
||||
e.srole,
|
||||
e.spassword
|
||||
FROM staff e
|
||||
WHERE (iemail = '' or e.email ilike iemail || '%')
|
||||
and (ilastname = '' or e.lastname ilike ilastname || '%')
|
||||
and (ifirstname = '' or e.firstname ilike ifirstname || '%');
|
||||
END; $$
|
||||
|
||||
LANGUAGE 'plpgsql';
|
||||
|
||||
|
||||
how to host under .net 8 web api under linux
|
||||
|
||||
1) create [webAPI_name].service
|
||||
******************************************
|
||||
# Example: /etc/systemd/system/yourwebapp.service
|
||||
[Unit]
|
||||
Description=Your .NET 8 Web API
|
||||
After=network.target
|
||||
|
||||
[Service]
|
||||
WorkingDirectory=/var/www/yourwebapp
|
||||
ExecStart=/usr/bin/dotnet /var/www/yourwebapp/YourWebApi.dll
|
||||
Restart=always
|
||||
RestartSec=10
|
||||
SyslogIdentifier=yourwebapp
|
||||
User=www-data # or a dedicated user
|
||||
Environment=ASPNETCORE_ENVIRONMENT=Production
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
************************************************
|
||||
2) start /stop the service under linux
|
||||
***********************************************
|
||||
sudo systemctl enable yourwebapp.service
|
||||
sudo systemctl start yourwebapp.service
|
||||
**********************************************
|
||||
|
||||
3) host under nginx or apache
|
||||
************************************************
|
||||
server {
|
||||
listen 80;
|
||||
server_name yourdomain.com;
|
||||
|
||||
location / {
|
||||
proxy_pass http://localhost:5000; # Kestrel's listening port
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $scheme;
|
||||
}
|
||||
}
|
||||
***********************************************************************
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
{
|
||||
"Logging": {
|
||||
"LogLevel": {
|
||||
"Default": "Information",
|
||||
"Microsoft.AspNetCore": "Warning"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
{
|
||||
|
||||
"AppSettings": {
|
||||
"Secret": "Nepean Blue Mountain Super Secret SIGN AND VERIFY JWT TOKENS, BEARER TOKEN USE WHEN CALLING THIS API.",
|
||||
"SQLConnectionString": "host=localhost;port=5432;database=FamilyTreeDB;username=postgres;password=Positive~1;",
|
||||
"LoginWebAPI": "http://nephmdb-sql006/CommonWebApiAD/api/AD",
|
||||
"ClientURL": "http://localhost:4200/approval",
|
||||
"ImageFolder": "c:\\temp\\Family"
|
||||
|
||||
},
|
||||
"Logging": {
|
||||
"LogLevel": {
|
||||
"Default": "Information",
|
||||
"Microsoft.AspNetCore": "Warning",
|
||||
"Microsoft.AspNetCore.DataProtection": "None"
|
||||
}
|
||||
},
|
||||
"AllowedHosts": "*"
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="15.0" Sdk="Microsoft.Docker.Sdk">
|
||||
<PropertyGroup Label="Globals">
|
||||
<ProjectVersion>2.1</ProjectVersion>
|
||||
<DockerTargetOS>Linux</DockerTargetOS>
|
||||
<DockerPublishLocally>False</DockerPublishLocally>
|
||||
<ProjectGuid>81dded9d-158b-e303-5f62-77a2896d2a5a</ProjectGuid>
|
||||
<DockerLaunchAction>LaunchBrowser</DockerLaunchAction>
|
||||
<DockerServiceUrl>{Scheme}://localhost:{ServicePort}/swagger</DockerServiceUrl>
|
||||
<DockerServiceName>workapi</DockerServiceName>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<None Include="docker-compose.override.yml">
|
||||
<DependentUpon>docker-compose.yml</DependentUpon>
|
||||
</None>
|
||||
<None Include="docker-compose.yml" />
|
||||
<None Include=".dockerignore" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
@@ -0,0 +1,12 @@
|
||||
services:
|
||||
workapi:
|
||||
environment:
|
||||
- ASPNETCORE_ENVIRONMENT=Development
|
||||
- ASPNETCORE_HTTP_PORTS=8080
|
||||
ports:
|
||||
- "8080"
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,72 @@
|
||||
networks:
|
||||
dev:
|
||||
driver: bridge
|
||||
services:
|
||||
postgresdb:
|
||||
image: postgres
|
||||
container_name: ${DOCKER_REGISTRY-}postgresql-db
|
||||
ports:
|
||||
- "5432:5432"
|
||||
environment:
|
||||
- POSTGRES_DB=FamilyTreeDB
|
||||
- POSTGRES_USER=postgres
|
||||
- POSTGRES_PASSWORD=Positive~1
|
||||
- PGDATA=/var/lib/postgresql/data/pgdata
|
||||
restart: always
|
||||
volumes:
|
||||
- postgresdata:/var/lib/postgresql/data
|
||||
networks:
|
||||
- dev
|
||||
pgadmin:
|
||||
image: dpage/pgadmin4
|
||||
container_name: pgadmin4_container
|
||||
restart: always
|
||||
depends_on:
|
||||
- "postgresdb"
|
||||
volumes:
|
||||
- pgadmin-data:/var/lib/pgadmin
|
||||
environment:
|
||||
PGADMIN_DEFAULT_EMAIL: postgres@domain.com
|
||||
PGADMIN_DEFAULT_PASSWORD: Positive~1
|
||||
ports:
|
||||
- "5050:80"
|
||||
networks:
|
||||
- dev
|
||||
familytreeui:
|
||||
image: ${DOCKER_REGISTRY-}familytreeui
|
||||
depends_on:
|
||||
- "familytreeapi"
|
||||
ports:
|
||||
- "4200:80"
|
||||
build:
|
||||
context: UI
|
||||
dockerfile: Dockerfile
|
||||
container_name: workui
|
||||
volumes:
|
||||
- ./:/app
|
||||
networks:
|
||||
- dev
|
||||
familytreeapi:
|
||||
image: ${DOCKER_REGISTRY-}familytreeapi
|
||||
container_name: familytreeapi-services
|
||||
depends_on:
|
||||
- "postgresdb"
|
||||
environment:
|
||||
- "Logging:Microsoft.AspNetCore.DataProtection:None"
|
||||
- "AppSettings:SQLConnectionString=host=postgresdb;database=FamilyTreeDB;username=postgres;password=Positive~1"
|
||||
volumes:
|
||||
- myapikey:/home/app/.aspnet/DataProtection-Keys
|
||||
ports:
|
||||
- "8080:8080"
|
||||
build:
|
||||
context: .
|
||||
dockerfile: FamilyTreeAPI/Dockerfile
|
||||
networks:
|
||||
- dev
|
||||
volumes:
|
||||
myapikey:
|
||||
external: true
|
||||
pgadmin-data:
|
||||
external: true
|
||||
postgresdata:
|
||||
external: true
|
||||
@@ -0,0 +1,11 @@
|
||||
{
|
||||
"profiles": {
|
||||
"Docker Compose": {
|
||||
"commandName": "DockerCompose",
|
||||
"commandVersion": "1.0",
|
||||
"serviceActions": {
|
||||
"workapi": "StartDebugging"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
# Editor configuration, see https://editorconfig.org
|
||||
root = true
|
||||
|
||||
[*]
|
||||
charset = utf-8
|
||||
indent_style = space
|
||||
indent_size = 2
|
||||
insert_final_newline = true
|
||||
trim_trailing_whitespace = true
|
||||
|
||||
[*.ts]
|
||||
quote_type = single
|
||||
ij_typescript_use_double_quotes = false
|
||||
|
||||
[*.md]
|
||||
max_line_length = off
|
||||
trim_trailing_whitespace = false
|
||||
@@ -0,0 +1,5 @@
|
||||
{
|
||||
"plugins": {
|
||||
"@tailwindcss/postcss": {}
|
||||
}
|
||||
}
|
||||
Vendored
+4
@@ -0,0 +1,4 @@
|
||||
{
|
||||
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=827846
|
||||
"recommendations": ["angular.ng-template"]
|
||||
}
|
||||
Vendored
+20
@@ -0,0 +1,20 @@
|
||||
{
|
||||
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
|
||||
"version": "0.2.0",
|
||||
"configurations": [
|
||||
{
|
||||
"name": "ng serve",
|
||||
"type": "chrome",
|
||||
"request": "launch",
|
||||
"preLaunchTask": "npm: start",
|
||||
"url": "http://localhost:4200/"
|
||||
},
|
||||
{
|
||||
"name": "ng test",
|
||||
"type": "chrome",
|
||||
"request": "launch",
|
||||
"preLaunchTask": "npm: test",
|
||||
"url": "http://localhost:9876/debug.html"
|
||||
}
|
||||
]
|
||||
}
|
||||
Vendored
+3
@@ -0,0 +1,3 @@
|
||||
{
|
||||
"git.ignoreLimitWarning": true
|
||||
}
|
||||
Vendored
+42
@@ -0,0 +1,42 @@
|
||||
{
|
||||
// For more information, visit: https://go.microsoft.com/fwlink/?LinkId=733558
|
||||
"version": "2.0.0",
|
||||
"tasks": [
|
||||
{
|
||||
"type": "npm",
|
||||
"script": "start",
|
||||
"isBackground": true,
|
||||
"problemMatcher": {
|
||||
"owner": "typescript",
|
||||
"pattern": "$tsc",
|
||||
"background": {
|
||||
"activeOnStart": true,
|
||||
"beginsPattern": {
|
||||
"regexp": "(.*?)"
|
||||
},
|
||||
"endsPattern": {
|
||||
"regexp": "bundle generation complete"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "npm",
|
||||
"script": "test",
|
||||
"isBackground": true,
|
||||
"problemMatcher": {
|
||||
"owner": "typescript",
|
||||
"pattern": "$tsc",
|
||||
"background": {
|
||||
"activeOnStart": true,
|
||||
"beginsPattern": {
|
||||
"regexp": "(.*?)"
|
||||
},
|
||||
"endsPattern": {
|
||||
"regexp": "bundle generation complete"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,59 @@
|
||||
# FamilyTree
|
||||
|
||||
This project was generated using [Angular CLI](https://github.com/angular/angular-cli) version 20.1.1.
|
||||
|
||||
## Development server
|
||||
|
||||
To start a local development server, run:
|
||||
|
||||
```bash
|
||||
ng serve
|
||||
```
|
||||
|
||||
Once the server is running, open your browser and navigate to `http://localhost:4200/`. The application will automatically reload whenever you modify any of the source files.
|
||||
|
||||
## Code scaffolding
|
||||
|
||||
Angular CLI includes powerful code scaffolding tools. To generate a new component, run:
|
||||
|
||||
```bash
|
||||
ng generate component component-name
|
||||
```
|
||||
|
||||
For a complete list of available schematics (such as `components`, `directives`, or `pipes`), run:
|
||||
|
||||
```bash
|
||||
ng generate --help
|
||||
```
|
||||
|
||||
## Building
|
||||
|
||||
To build the project run:
|
||||
|
||||
```bash
|
||||
ng build
|
||||
```
|
||||
|
||||
This will compile your project and store the build artifacts in the `dist/` directory. By default, the production build optimizes your application for performance and speed.
|
||||
|
||||
## Running unit tests
|
||||
|
||||
To execute unit tests with the [Karma](https://karma-runner.github.io) test runner, use the following command:
|
||||
|
||||
```bash
|
||||
ng test
|
||||
```
|
||||
|
||||
## Running end-to-end tests
|
||||
|
||||
For end-to-end (e2e) testing, run:
|
||||
|
||||
```bash
|
||||
ng e2e
|
||||
```
|
||||
|
||||
Angular CLI does not come with an end-to-end testing framework by default. You can choose one that suits your needs.
|
||||
|
||||
## Additional Resources
|
||||
|
||||
For more information on using the Angular CLI, including detailed command references, visit the [Angular CLI Overview and Command Reference](https://angular.dev/tools/cli) page.
|
||||
@@ -0,0 +1,88 @@
|
||||
{
|
||||
"$schema": "./node_modules/@angular/cli/lib/config/schema.json",
|
||||
"version": 1,
|
||||
"newProjectRoot": "projects",
|
||||
"projects": {
|
||||
"FamilyTree": {
|
||||
"projectType": "application",
|
||||
"schematics": {},
|
||||
"root": "",
|
||||
"sourceRoot": "src",
|
||||
"prefix": "app",
|
||||
"architect": {
|
||||
"build": {
|
||||
"builder": "@angular/build:application",
|
||||
"options": {
|
||||
"browser": "src/main.ts",
|
||||
"tsConfig": "tsconfig.app.json",
|
||||
"assets": [
|
||||
{
|
||||
"glob": "**/*",
|
||||
"input": "public"
|
||||
}
|
||||
],
|
||||
"styles": [
|
||||
"src/styles.css"
|
||||
]
|
||||
},
|
||||
"configurations": {
|
||||
"production": {
|
||||
"budgets": [
|
||||
{
|
||||
"type": "initial",
|
||||
"maximumWarning": "5MB",
|
||||
"maximumError": "6MB"
|
||||
},
|
||||
{
|
||||
"type": "anyComponentStyle",
|
||||
"maximumWarning": "4kB",
|
||||
"maximumError": "8kB"
|
||||
}
|
||||
],
|
||||
"outputHashing": "all"
|
||||
},
|
||||
"development": {
|
||||
"optimization": false,
|
||||
"extractLicenses": false,
|
||||
"sourceMap": true
|
||||
}
|
||||
},
|
||||
"defaultConfiguration": "production"
|
||||
},
|
||||
"serve": {
|
||||
"builder": "@angular/build:dev-server",
|
||||
"configurations": {
|
||||
"production": {
|
||||
"buildTarget": "FamilyTree:build:production"
|
||||
},
|
||||
"development": {
|
||||
"buildTarget": "FamilyTree:build:development"
|
||||
}
|
||||
},
|
||||
"defaultConfiguration": "development"
|
||||
},
|
||||
"extract-i18n": {
|
||||
"builder": "@angular/build:extract-i18n"
|
||||
},
|
||||
"test": {
|
||||
"builder": "@angular/build:karma",
|
||||
"options": {
|
||||
"tsConfig": "tsconfig.spec.json",
|
||||
"assets": [
|
||||
{
|
||||
"glob": "**/*",
|
||||
"input": "public"
|
||||
}
|
||||
],
|
||||
"styles": [
|
||||
"src/styles.css"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"cli": {
|
||||
"analytics": false
|
||||
}
|
||||
}
|
||||
Generated
+10246
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,53 @@
|
||||
{
|
||||
"name": "family-tree",
|
||||
"version": "0.0.0",
|
||||
"scripts": {
|
||||
"ng": "ng",
|
||||
"start": "ng serve",
|
||||
"build": "ng build",
|
||||
"watch": "ng build --watch --configuration development",
|
||||
"test": "ng test"
|
||||
},
|
||||
"prettier": {
|
||||
"overrides": [
|
||||
{
|
||||
"files": "*.html",
|
||||
"options": {
|
||||
"parser": "angular"
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
"private": true,
|
||||
"dependencies": {
|
||||
"@angular/common": "^20.1.0",
|
||||
"@angular/compiler": "^20.1.0",
|
||||
"@angular/core": "^20.1.0",
|
||||
"@angular/forms": "^20.1.0",
|
||||
"@angular/platform-browser": "^20.1.0",
|
||||
"@angular/router": "^20.1.0",
|
||||
"@primeuix/themes": "^1.2.1",
|
||||
"@tailwindcss/postcss": "^4.1.11",
|
||||
"moment": "^2.30.1",
|
||||
"postcss": "^8.5.6",
|
||||
"primeicons": "^7.0.0",
|
||||
"primeng": "^20.0.0",
|
||||
"rxjs": "~7.8.0",
|
||||
"tailwindcss": "^4.1.11",
|
||||
"tailwindcss-primeui": "^0.6.1",
|
||||
"tslib": "^2.3.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@angular/build": "^20.1.1",
|
||||
"@angular/cli": "^20.1.1",
|
||||
"@angular/compiler-cli": "^20.1.0",
|
||||
"@types/jasmine": "~5.1.0",
|
||||
"jasmine-core": "~5.8.0",
|
||||
"karma": "~6.4.0",
|
||||
"karma-chrome-launcher": "~3.2.0",
|
||||
"karma-coverage": "~2.2.0",
|
||||
"karma-jasmine": "~5.1.0",
|
||||
"karma-jasmine-html-reporter": "~2.1.0",
|
||||
"typescript": "~5.8.2"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
{
|
||||
"baseUrl": "http://localhost:5015",
|
||||
"attachment": "http://localhost/document/family"
|
||||
}
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 15 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 19 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 23 KiB |
@@ -0,0 +1,19 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<configuration>
|
||||
|
||||
<system.webServer>
|
||||
<rewrite>
|
||||
<rules>
|
||||
<rule name="Angular Routes" stopProcessing="true">
|
||||
<match url=".*" />
|
||||
<conditions logicalGrouping="MatchAll">
|
||||
<add input="{REQUEST_FILENAME}" matchType="IsFile" negate="true" />
|
||||
<add input="{REQUEST_FILENAME}" matchType="IsDirectory" negate="true" />
|
||||
</conditions>
|
||||
<action type="Rewrite" url="./index.html" />
|
||||
</rule>
|
||||
</rules>
|
||||
</rewrite>
|
||||
</system.webServer>
|
||||
|
||||
</configuration>
|
||||
@@ -0,0 +1,32 @@
|
||||
import { ApplicationConfig, provideAppInitializer, provideBrowserGlobalErrorListeners, provideZonelessChangeDetection } from '@angular/core';
|
||||
import { provideRouter } from '@angular/router';
|
||||
import { JwtInterceptor, ErrorInterceptor, initializeApp } from './shares';
|
||||
import { provideAnimationsAsync } from '@angular/platform-browser/animations/async';
|
||||
import { providePrimeNG } from 'primeng/config';
|
||||
import { provideHttpClient, withInterceptors } from '@angular/common/http';
|
||||
import { ConfirmationService, MessageService } from 'primeng/api';
|
||||
import { routes } from './app.routes';
|
||||
import MyPreset from './mythem';
|
||||
|
||||
export const appConfig: ApplicationConfig = {
|
||||
providers: [
|
||||
provideBrowserGlobalErrorListeners(),
|
||||
MessageService, ConfirmationService,
|
||||
provideAppInitializer(initializeApp()),
|
||||
provideHttpClient(withInterceptors([JwtInterceptor, ErrorInterceptor])),
|
||||
provideZonelessChangeDetection(),
|
||||
provideAnimationsAsync(),
|
||||
providePrimeNG({
|
||||
theme: {
|
||||
preset: MyPreset,
|
||||
options: {
|
||||
cssLayer: {
|
||||
name: 'primeng',
|
||||
order: 'theme, base, primeng'
|
||||
}
|
||||
}
|
||||
}
|
||||
}),
|
||||
provideRouter(routes)
|
||||
]
|
||||
};
|
||||
@@ -0,0 +1,5 @@
|
||||
<p-toast position="bottom-center" />
|
||||
<app-toolbar> </app-toolbar>
|
||||
<router-outlet />
|
||||
<p-confirmDialog [style]="{width: '50vw'}"
|
||||
rejectButtonStyleClass="p-button-text"> </p-confirmDialog>
|
||||
@@ -0,0 +1,15 @@
|
||||
import { Routes } from '@angular/router';
|
||||
import { Login } from './login';
|
||||
import { StaffComponent, StaffEditComponent } from './staff';
|
||||
import { AuthGuard } from './route-guard';
|
||||
import { FamilyTree, FamilyList} from './person';
|
||||
export const routes: Routes = [
|
||||
{ path: '', redirectTo: 'login', pathMatch: 'full' },
|
||||
// { path: 'approval', component: ApprovalComponent,canActivate: [AuthGuard], data: { roleAllowed: '1,2,3' }},},
|
||||
{ path: 'login', component: Login},
|
||||
{ path: 'staff', component: StaffComponent},
|
||||
{ path: 'person', component: FamilyList},
|
||||
{ path: 'familytree', component: FamilyTree},
|
||||
{ path: 'staff/:id', component: StaffEditComponent},
|
||||
|
||||
];
|
||||
@@ -0,0 +1,14 @@
|
||||
import { Component, signal } from '@angular/core';
|
||||
import { RouterOutlet } from '@angular/router';
|
||||
import { ToolbarComponent } from './toolbar/toolbar.component';
|
||||
import { ToastModule } from 'primeng/toast';
|
||||
import { ConfirmDialogModule } from 'primeng/confirmdialog';
|
||||
@Component({
|
||||
selector: 'app-root',
|
||||
imports: [RouterOutlet,ToastModule,ToolbarComponent,ConfirmDialogModule],
|
||||
templateUrl: './app.html',
|
||||
styleUrl: './app.css'
|
||||
})
|
||||
export class App {
|
||||
protected readonly title = signal('FamilyTree');
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
export * from './login';
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
.btnloginRigh {
|
||||
display: flex;
|
||||
flex-direction:reverse;
|
||||
justify-content:flex-end;
|
||||
width: 100%;
|
||||
}
|
||||
.myerror {
|
||||
background-color: red;
|
||||
color: white;
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
<div class="flex justify-center items-center h-full">
|
||||
<form [formGroup]="loginForm" (ngSubmit)="onSubmit()" style="max-width: 600px;min-width: 450px;">
|
||||
<p-card>
|
||||
<div>
|
||||
<img class="border-round" style="width:100%;height:100px;" alt="Logo" src="images/application_image_login.png">
|
||||
</div>
|
||||
<div class="mt-4">
|
||||
<div class="flex flex-col">
|
||||
<label for="email" class="w-full">Email<strong class="validateStar">*</strong></label>
|
||||
<input type="text" pInputText formControlName="username" name="email"
|
||||
[ngClass]="{ 'is-invalid': submitted && f.username.errors }" class="p-inputtext-sm inputfield">
|
||||
|
||||
</div>
|
||||
<div class="flex flex-col">
|
||||
<label for="ppassword" class="w-full">Password <strong class="validateStar">*</strong></label>
|
||||
<input type="password" formControlName="password" name="ppassword" pInputText
|
||||
[ngClass]="{ 'is-invalid': submitted && f.password.errors }" class="p-inputtext-sm inputfield">
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<!--p-footer -->
|
||||
<div class="btnloginRigh">
|
||||
<div class="mt-4 pt-2">
|
||||
<button pButton type="submit" label="Login" class="p-button-sm" [disabled]="isFieldsChange"
|
||||
[loading]="loading"></button>
|
||||
</div>
|
||||
</div>
|
||||
<!--/p-footer-->
|
||||
|
||||
</p-card>
|
||||
<div class="myerror">{{error}}</div>
|
||||
<div style="padding-top: 10px;"></div>
|
||||
<!--div
|
||||
style="text-align: center;display:inline-block;border-radius: var(--border-radius) !important;background-color:#e1e1e1; color:#222;font-size:13px;width:100%; margin-left:5px;margin-right: 5px;">
|
||||
<p >
|
||||
For management access to this application please email
|
||||
</p>
|
||||
<a href="mailto:NBMLHD-fleetteamreceipt@health.nsw.gov.au">NBMLHD-fleetteamreceipt@health.nsw.gov.au
|
||||
</a>
|
||||
|
||||
</div-->
|
||||
<!--pre> {{loginForm.value|json}} </pre-->
|
||||
</form>
|
||||
|
||||
</div>
|
||||
@@ -0,0 +1,135 @@
|
||||
import { Component, OnDestroy, OnInit, inject } from '@angular/core';
|
||||
import { Router, ActivatedRoute, RouterModule } from '@angular/router';
|
||||
import { FormBuilder, Validators, FormGroup } from '@angular/forms';
|
||||
import { first } from 'rxjs/operators';
|
||||
|
||||
import { AuthenticationService } from '../user-services';
|
||||
|
||||
import { ConfirmationService } from 'primeng/api';
|
||||
import { Subject, Subscription } from 'rxjs';
|
||||
import { CommonModule } from '@angular/common';
|
||||
import { CardModule } from 'primeng/card';
|
||||
import { ReactiveFormsModule, FormsModule } from '@angular/forms';
|
||||
import { ButtonModule } from 'primeng/button';
|
||||
import { InputTextModule } from 'primeng/inputtext';
|
||||
|
||||
import { Utils } from '../shares';
|
||||
@Component({
|
||||
templateUrl: './login.html',
|
||||
styleUrl: './login.css',
|
||||
selector: 'login',
|
||||
imports: [FormsModule, ReactiveFormsModule, ButtonModule, InputTextModule,
|
||||
RouterModule, CommonModule, CardModule],
|
||||
|
||||
})
|
||||
export class Login implements OnInit, OnDestroy {
|
||||
loginForm: FormGroup;
|
||||
confirmationService = inject(ConfirmationService);
|
||||
route = inject(ActivatedRoute);
|
||||
router = inject(Router);
|
||||
authenticationService = inject(AuthenticationService);
|
||||
formBuilder = inject(FormBuilder);
|
||||
loading = false;
|
||||
homeUrl = "/person";
|
||||
submitted = false;
|
||||
isChange = true; // disable use false//true for not disable. make sure it true is disable button.
|
||||
subChanged$ = new Subject<boolean>();
|
||||
// get return url from route parameters or default to '/'
|
||||
returnUrl = this.route.snapshot.queryParams['returnUrl'] || this.homeUrl;
|
||||
error = '';
|
||||
private subscription: Subscription = new Subscription();
|
||||
|
||||
constructor() {
|
||||
|
||||
this.loginForm = this.formBuilder.group({
|
||||
username: ['kham.vilaythong@gmail.com', Validators.required],
|
||||
password: ['password', Validators.required],
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
ngOnInit() {
|
||||
// reset login status
|
||||
this.loading = false;
|
||||
this.subscription.add(this.loginForm.valueChanges.subscribe((x: any) => this.isChange = false));
|
||||
this.subscription.add(this.subChanged$.subscribe(x => this.isChange = x));
|
||||
|
||||
}
|
||||
|
||||
updateData($event: Event) {
|
||||
console.log("onChange click", $event);
|
||||
}
|
||||
|
||||
// convenience getter for easy access to form fields
|
||||
get f() { return this.loginForm.value; }
|
||||
get isFieldsChange() {
|
||||
const chan = this.isChange || !this.loginForm.valid; // this disable so need true valid = true not
|
||||
//console.log(this.msg + 'is fields change', chan);
|
||||
return chan;
|
||||
}
|
||||
onSubmit() {
|
||||
|
||||
//this.playAudio();
|
||||
|
||||
// stop here if form is invalid
|
||||
if (this.loginForm.invalid) {
|
||||
return;
|
||||
}
|
||||
const fvalue = this.loginForm.value;
|
||||
this.loading = true;
|
||||
this.error = "";
|
||||
let username = "";
|
||||
let password = "";
|
||||
if (fvalue.username != null)
|
||||
username = fvalue.username;
|
||||
if (fvalue.password != null)
|
||||
password = fvalue.password;
|
||||
this.authenticationService.login(username, password)
|
||||
.pipe(first())
|
||||
.subscribe({
|
||||
next: (x: any) => {
|
||||
this.loading = false;
|
||||
console.log("login result ", x.data, this.returnUrl);
|
||||
if (x.statusCode == 1) {
|
||||
// if (x.data.role == 1) {
|
||||
// this.homeService.reportDate = Utils.getLastMonth();
|
||||
// this.router.navigate(['/addkpi/' + x.data.id + '/' + x.data.measureId], { queryParams: { returnUrl: '/login' } });
|
||||
|
||||
// }
|
||||
// else if (x.data.role == 3) {
|
||||
// this.homeService.reportDate = Utils.getLastMonth();
|
||||
// this.router.navigate(['/approval/' + x.data.id], { queryParams: { returnUrl: '/login' } });
|
||||
|
||||
//}
|
||||
// else
|
||||
this.router.navigate([this.homeUrl]);
|
||||
}
|
||||
else {
|
||||
this.loginForm.patchValue({ password: '' });
|
||||
// alert("Invalid Username or Password. Please try again.");
|
||||
console.error("error in login", x);
|
||||
this.confirmationService.confirm({
|
||||
message: 'Error in Login: Invalid username or password. May be your password is expired',
|
||||
header: 'Error Login',
|
||||
icon: 'pi pi-info-circle',
|
||||
rejectVisible: false,
|
||||
acceptLabel: 'OK',
|
||||
|
||||
});
|
||||
}
|
||||
},
|
||||
error: er => {
|
||||
console.log("error in login", er);
|
||||
this.error = er.message;
|
||||
this.loading = false;
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
ngOnDestroy(): void {
|
||||
this.subscription.unsubscribe();
|
||||
this.loading = false;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
export interface Code {
|
||||
id:number;
|
||||
name:string;
|
||||
status?:string;
|
||||
active?:boolean;
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
export enum ConfigureUrl
|
||||
{
|
||||
//baseUrl = "http://localhost:61744",
|
||||
loginApiUrl = "api/Users/Login",
|
||||
searchStaffUrl = "api/Users/SearchADStaff",
|
||||
staffUrl = "api/Staff",
|
||||
personUrl = "api/Person",
|
||||
staffWorkUrl = "api/StaffWork",
|
||||
jobUrl ="api/Job",
|
||||
clientUrl ="api/Client",
|
||||
relationShipUrl ="api/RelationShip",
|
||||
logoutUrl ="api/Users/Logout",
|
||||
adminUserUrl = "api/Staff",
|
||||
lookupUrl = "api/Lookup",
|
||||
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
export const MIMEType = {
|
||||
png: 'image/png',
|
||||
jpg: 'image/jpg',
|
||||
jpeg: 'image/jpeg',
|
||||
gif: 'image/gif',
|
||||
txt: 'text/plain',
|
||||
pdf: 'application/pdf'
|
||||
};
|
||||
|
||||
|
||||
//for status of object 0 no change, 1 changed , -1 is deleted.
|
||||
export enum mState {
|
||||
Delete = -1,
|
||||
NoChange = 0,
|
||||
Modified = 1,
|
||||
New =2,
|
||||
};
|
||||
|
||||
export enum userRole {
|
||||
Normal = 1,
|
||||
Admin = 2,
|
||||
ServiceManager =3,
|
||||
Accounting = 4,
|
||||
WorkShop = 5,
|
||||
|
||||
};
|
||||
|
||||
export enum enumReqStatus {
|
||||
Canel = -1,
|
||||
Decline = -2,
|
||||
NewRequest = 0,
|
||||
Allocate = 1,
|
||||
Arrival = 2,
|
||||
Completed = 3,
|
||||
OnHold = 4,
|
||||
OffHold = 5
|
||||
};
|
||||
@@ -0,0 +1,10 @@
|
||||
export * from './code';
|
||||
export * from './configureUrl';
|
||||
export * from './user';
|
||||
export * from './resultmodel';
|
||||
export * from './enum';
|
||||
export * from './lookup';
|
||||
export * from './staff';
|
||||
export * from './person';
|
||||
export * from './job';
|
||||
export * from './relationship';
|
||||
@@ -0,0 +1,12 @@
|
||||
|
||||
export interface JobSearch {
|
||||
code:string;
|
||||
description:string;
|
||||
}
|
||||
export interface Job {
|
||||
id:number;
|
||||
code:string|null|undefined;
|
||||
description:string |null|undefined;
|
||||
active:boolean |null|undefined;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
// using for priority and infectionType
|
||||
export interface Lookup {
|
||||
id:number;
|
||||
codeId:string;
|
||||
description:string;
|
||||
|
||||
}
|
||||
|
||||
export interface LookupEdit {
|
||||
id:number;
|
||||
codeId:string;
|
||||
description:string;
|
||||
active:boolean;
|
||||
type:string;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
export interface MyDetail{
|
||||
id:number,
|
||||
login:string,
|
||||
firstname:string,
|
||||
surname:string,
|
||||
jobTitle:string,
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
import { RelationShip } from "./relationship";
|
||||
|
||||
export interface FamilySearch {
|
||||
email:string|null;
|
||||
phone:string |null;
|
||||
clientname:string |null;
|
||||
}
|
||||
|
||||
export interface Person {
|
||||
|
||||
id: number;
|
||||
title?:string| null| undefined;
|
||||
firstName: string | null|undefined;
|
||||
lastName: string | null|undefined;
|
||||
email: string | null|undefined;
|
||||
phone: string | null|undefined;
|
||||
address?: string | null|undefined;
|
||||
alive: boolean | null|undefined;
|
||||
dob? : string | null|undefined;
|
||||
fatherId?: number| null|undefined;
|
||||
motherId?: number| null|undefined;
|
||||
image?: string|null|undefined;
|
||||
sex?: string|null|undefined;
|
||||
fatherName?:string |null;
|
||||
motherName?:string |null;
|
||||
relationShips?: RelationShip[];
|
||||
}
|
||||
|
||||
export interface PersonContainer
|
||||
{
|
||||
person: Person;
|
||||
formData?:FormData;
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,27 @@
|
||||
import { mState } from "./enum";
|
||||
|
||||
export interface RelationShip {
|
||||
id: number;
|
||||
relatePersonId: number;
|
||||
personId: number;
|
||||
state: mState;
|
||||
}
|
||||
//relationship id this relatePersonId person has relation with other person
|
||||
// also other person has also has relation with you. look in two way
|
||||
// person id = 1 has to relation id = 90
|
||||
// that means when you edit person 90 their relation ship also be there.
|
||||
// so personid = 1 and relation id = 90 we need to show other way around.
|
||||
//example first name = Smith has partner Jennifer
|
||||
// when we edit Jennifer it should show Smith as her partner too.
|
||||
|
||||
export interface RelationShipView {
|
||||
id: number;
|
||||
relatePersonId:number;
|
||||
personId : number;
|
||||
pfirstName: string |null |undefined;
|
||||
plastName: string |null |undefined;
|
||||
sex:string |null |undefined;
|
||||
state: mState;
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
export interface ResultModel<T> {
|
||||
data: T;
|
||||
message: string;
|
||||
statusCode:number;
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
export interface StaffView {
|
||||
id:number,
|
||||
email:string,
|
||||
firstname:string,
|
||||
lastname:string,
|
||||
active:boolean,
|
||||
}
|
||||
|
||||
export interface ResetPassword{
|
||||
id:number;
|
||||
password:string;
|
||||
}
|
||||
|
||||
export interface Staff {
|
||||
id:number,
|
||||
email:string,
|
||||
firstname:string,
|
||||
lastname:string,
|
||||
phone:string,
|
||||
type:number;
|
||||
active:boolean;
|
||||
roleType: number;
|
||||
password?:string,
|
||||
}
|
||||
|
||||
export interface StaffSearch {
|
||||
email:string;
|
||||
firstName:string;
|
||||
lastName:string;
|
||||
}
|
||||
|
||||
//this use for new user only.
|
||||
export interface AdminUserNew {
|
||||
loginId:number;
|
||||
user: Staff;// first get userid from this table and
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,36 @@
|
||||
export class User {
|
||||
id: number = 0;
|
||||
username: string = '';
|
||||
role: number = -1;
|
||||
firstName: string = '';
|
||||
lastName: string = '';
|
||||
email:string = '';
|
||||
token:string ='';
|
||||
position: string ='';
|
||||
department: string = '';
|
||||
managerEmail:string ='';
|
||||
phone:string='';
|
||||
|
||||
}
|
||||
|
||||
export interface UserAD
|
||||
{
|
||||
id: number,
|
||||
firstName: string,
|
||||
lastName: string,
|
||||
email: string,
|
||||
username: string,
|
||||
department: string,
|
||||
position: string,
|
||||
role: number,
|
||||
phone:string,
|
||||
managerEmail:string
|
||||
}
|
||||
|
||||
export class SecAccessLevel {
|
||||
accessName:string='';
|
||||
request:number=0;
|
||||
report:number=0;
|
||||
admin:number=0;
|
||||
allocation:number=0;
|
||||
}
|
||||
@@ -0,0 +1,59 @@
|
||||
|
||||
|
||||
//mypreset.ts
|
||||
import { definePreset } from '@primeuix/themes';
|
||||
import Aura from '@primeuix/themes/aura';
|
||||
|
||||
const MyPreset = definePreset(Aura, {
|
||||
semantic: {
|
||||
colorScheme: {
|
||||
primary: {
|
||||
50: '{zinc.50}',
|
||||
100: '{zinc.100}',
|
||||
200: '{zinc.200}',
|
||||
300: '{zinc.300}',
|
||||
400: '{zinc.400}',
|
||||
500: '{zinc.500}',
|
||||
600: '{zinc.600}',
|
||||
700: '{zinc.700}',
|
||||
800: '{zinc.800}',
|
||||
900: '{zinc.900}',
|
||||
950: '{zinc.950}'
|
||||
},
|
||||
light: {
|
||||
surface: {
|
||||
0: '#ffffff',
|
||||
50: '{zinc.50}',
|
||||
100: '{zinc.100}',
|
||||
200: '{zinc.200}',
|
||||
300: '{zinc.300}',
|
||||
400: '{zinc.400}',
|
||||
500: '{zinc.500}',
|
||||
600: '{zinc.600}',
|
||||
700: '{zinc.700}',
|
||||
800: '{zinc.800}',
|
||||
900: '{zinc.900}',
|
||||
950: '{zinc.950}'
|
||||
}
|
||||
},
|
||||
dark: {
|
||||
surface: {
|
||||
0: '#ffffff',
|
||||
50: '{slate.50}',
|
||||
100: '{slate.100}',
|
||||
200: '{slate.200}',
|
||||
300: '{slate.300}',
|
||||
400: '{slate.400}',
|
||||
500: '{slate.500}',
|
||||
600: '{slate.600}',
|
||||
700: '{slate.700}',
|
||||
800: '{slate.800}',
|
||||
900: '{slate.900}',
|
||||
950: '{slate.950}'
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
export default MyPreset;
|
||||
@@ -0,0 +1,12 @@
|
||||
table {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.mat-form-field {
|
||||
font-size: 14px;
|
||||
width: 100%;
|
||||
}
|
||||
td.mat-column-edit, .mat-column-delete {
|
||||
width: 35px;
|
||||
padding-right: 2px;
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user