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.
|
# 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
|
# Compiled output
|
||||||
dist/
|
dist/
|
||||||
bin/
|
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