Compare commits

...

123 Commits

Author SHA1 Message Date
Vijay Uppu
65b4ca6356 Group by issue in responses 2024-01-22 12:09:00 -05:00
Vijay Uppu
54bc663f95 fixed region issue 2024-01-18 11:40:57 -05:00
Vijay Uppu
a83bbb09b1 added active and in active survey endpoints 2023-12-19 13:17:44 -05:00
Vijay Uppu
e3f34e17c3 Modified logic to get latest response based on survetid, locationId, ane employee id 2023-12-16 12:45:36 -05:00
Vijay Uppu
db6fbf67a6 added survey start and end date validation 2023-12-13 16:56:50 -05:00
Vijay Uppu
432a011d00 adding multiple questions for survey id 2023-12-07 09:51:49 -05:00
Vijay Uppu
572b4dba66 changed download url format and added new endpoint for doculink isactive update 2023-12-04 14:28:13 -05:00
Vijay Uppu
df98a1e0f4 added IsActive flag in doculinks request 2023-12-04 09:27:58 -05:00
Vijay Uppu
4aea45914e attachment and doculinks url changes 2023-12-01 17:20:11 -05:00
Vijay Uppu
9f2655d596 added multi language support for doculink attachments 2023-11-30 18:51:14 -05:00
Vijay Uppu
a407bfdf7b Return Employee ID for POST 2023-11-28 12:00:12 -05:00
Vijay Uppu
1f3c0f0524 fixed multiple question saving issue 2023-11-15 09:07:17 -05:00
Vijay Uppu
b227d32f89 Added new endpoint for creating multiple questions 2023-11-14 15:13:23 -05:00
uppuv
7f276ed532 completed heatmap api changes for location and response api 2023-11-07 16:51:10 -05:00
uppuv
227795aeda fixed survey issue in response level, and added logic for start and end date as optional date 2023-11-05 14:19:37 -05:00
uppuv
c80749e292 ixed survey issue in response level, and added logic for start and end date as optional date. 2023-11-05 13:20:29 -05:00
uppuv
6f10e99627 added excel export and removed random number 2023-11-01 12:42:30 -04:00
uppuv
499ac9248b reverted doculinks grouping by linktype 2023-10-24 12:15:13 -04:00
uppuv
e8e649efd9 reverted doculinks chages for linktype grouping 2023-10-24 11:42:28 -04:00
uppuv
7b7e5c0ce8 added status field in survey micro service 2023-10-23 12:03:50 -04:00
uppuv
2182b9a6b3 added status field in survey micro service 2023-10-23 11:39:56 -04:00
Santhosh S
f9b7fad33b Updated with folder path 2023-10-17 23:04:28 -04:00
Santhosh S
d219faa147 Updated with folder path 2023-10-17 22:40:34 -04:00
Santhosh S
40ab868e82 Updated relative path 2023-10-17 22:18:56 -04:00
Santhosh S
aae073d456 modified push acr script 2023-10-17 22:10:31 -04:00
Santhosh S
39df8c017b modified push acr script 2023-10-17 22:07:15 -04:00
Santhosh S
0cc5be64ee modified push acr script 2023-10-17 15:27:44 -04:00
Santhosh S
fa68071d64 modified push acr script 2023-10-17 15:14:41 -04:00
Santhosh S
acb5067ce5 Merge branch 'docker-branch' of https://dev.azure.com/MDCSB-Telecommuters/Emergency%20Preparedness%20Disaster%20Recovery%20Project%20%28EPDRP%29/_git/Backend-API-Services into docker-branch 2023-10-17 12:53:26 -04:00
Santhosh S
f7141493ca Updated relative path 2023-10-17 12:51:51 -04:00
Santhosh Nair
e8cbe76166 Update azure-pipelines.yml for Azure Pipelines 2023-10-17 16:44:04 +00:00
Santhosh Nair
afb520463a Update azure-pipelines.yml for Azure Pipelines 2023-10-17 16:41:54 +00:00
Santhosh Nair
1f046e0c70 Update azure-pipelines.yml for Azure Pipelines 2023-10-17 16:37:23 +00:00
Santhosh S
7b821decbd Updated with folder path 2023-10-17 12:09:42 -04:00
Santhosh S
f321641870 folder for Common build support scripts 2023-10-17 11:36:35 -04:00
Santhosh Nair
8349e78f6e Update azure-pipelines.yml for Azure Pipelines 2023-10-16 23:30:50 +00:00
uppuv
8a803ad157 added logic to get active surveys from survey responses 2023-10-16 14:02:49 -04:00
Santhosh Nair
c89c6f60c3 Update azure-pipelines.yml for Azure Pipelines 2023-10-16 11:21:54 +00:00
Santhosh Nair
08f873e8e3 Update azure-pipelines.yml for Azure Pipelines 2023-10-16 03:47:09 +00:00
Santhosh Nair
dadbcf98b9 Update azure-pipelines.yml for Azure Pipelines 2023-10-16 03:44:19 +00:00
Santhosh Nair
7935302b2d Update azure-pipelines.yml for Azure Pipelines 2023-10-16 03:40:48 +00:00
Santhosh Nair
55e27059e5 Update azure-pipelines.yml for Azure Pipelines 2023-10-16 03:31:15 +00:00
Santhosh Nair
3ac36bf86f Update azure-pipelines.yml for Azure Pipelines 2023-10-15 16:48:47 +00:00
Santhosh Nair
7985428f8b Update azure-pipelines.yml for Azure Pipelines 2023-10-14 04:16:24 +00:00
Santhosh Nair
0dd6d3b1e3 Update azure-pipelines.yml for Azure Pipelines 2023-10-14 04:14:40 +00:00
Santhosh Nair
d3cf6a63e5 Update azure-pipelines.yml for Azure Pipelines 2023-10-14 04:13:24 +00:00
Santhosh Nair
45109881ad Update azure-pipelines.yml for Azure Pipelines 2023-10-14 04:12:30 +00:00
Santhosh S
f91b935374 Added Azure Pipeline to ACR 2023-10-13 18:28:15 -04:00
uppuv
6ad5bb1572 merged latest changes from docker to dev 2023-10-13 14:48:08 -04:00
uppuv
cb3c7f8f6a added muilti language return format for question categories for question by survey 2023-10-13 13:21:33 -04:00
uppuv
26e79432e2 table name changes 2023-10-12 16:01:24 -04:00
uppuv
885fdeb117 updated question category 2023-10-11 19:24:50 -04:00
uppuv
fa3e3bbd99 added seed data for questions and surveys for demo 2023-10-11 15:33:21 -04:00
uppuv
3911980842 doculink changes for grouping moving to docker branch 2023-10-09 20:39:37 -04:00
uppuv
71d4b524e7 doculinks changes for grouping 2023-10-09 13:29:01 -04:00
Santhosh S
9b91afd329 bug fix with seed data changes 2023-10-06 18:22:37 -04:00
uppuv
1510c3ab12 Seed changes for doculink microservice 2023-10-06 16:25:38 -04:00
uppuv
c7a2dc5910 seed changes for doculinks 2023-10-06 15:53:09 -04:00
Santhosh Nair
15b5fba35e Deleted appsettings.Test.json 2023-10-06 01:53:42 +00:00
Santhosh Nair
7d3968bb62 Deleted appsettings.Production.json 2023-10-06 01:53:24 +00:00
Santhosh Nair
cee61c9b87 Deleted appsettings.Development.json 2023-10-06 01:53:05 +00:00
uppuv
2aca01c8b4 seed data changes for answers and new survey 2023-10-05 15:42:41 -04:00
uppuv
bac2eef4fb added doculinks seed data for multi language titles and descriptions 2023-10-05 14:27:24 -04:00
Santhosh S
6ae57c9818 Fix for Namespace SurveyResponses 2023-10-04 18:45:51 -04:00
Santhosh S
d2ae8a30a6 Added Response sample data 2023-10-04 18:19:27 -04:00
Santhosh S
076a8004e2 Merge branch 'dev' of https://dev.azure.com/MDCSB-Telecommuters/Emergency%20Preparedness%20Disaster%20Recovery%20Project%20%28EPDRP%29/_git/Backend-API-Services into dev 2023-10-04 15:19:12 -04:00
uppuv
54d6fab64f enabled seed data and changed survey Response project name 2023-10-04 15:03:59 -04:00
Santhosh S
045a0995bb merge with latest change in endpoints 2023-10-04 12:34:03 -04:00
Santhosh S
dc1cb899d0 Merge branch 'dev' of https://dev.azure.com/MDCSB-Telecommuters/Emergency%20Preparedness%20Disaster%20Recovery%20Project%20%28EPDRP%29/_git/Backend-API-Services into dev 2023-10-04 12:23:55 -04:00
uppuv
044876b23b changed all end points to small case 2023-10-04 11:55:35 -04:00
Santhosh S
30751bc491 fix doculink test reference 2023-10-04 00:28:04 -04:00
Santhosh S
fa0ec795c1 Employee uri to employee 2023-10-04 00:07:33 -04:00
Santhosh S
8e31691044 change of port for testing socker-compose.asf.yml 2023-10-01 23:20:04 -04:00
Santhosh S
82c768a0d9 change of port for testing socker-compose.asf.yml 2023-10-01 21:15:42 -04:00
Santhosh S
f5c2b2da44 Proxy Port update for AzureFabricsService test reverted 2023-09-29 11:38:43 -04:00
Santhosh S
17b4177a26 Proxy Port update for AzureFabricsService 6006 changed to doculink 2023-09-29 11:08:11 -04:00
Santhosh S
c5f3473ccb port change for cluster 2023-09-29 10:11:53 -04:00
Santhosh S
8744761b00 Proxy Port update for AzureFabricsService test 2023-09-29 01:11:19 -04:00
Santhosh S
7f82b10bbc added docker-compose for service cluster 2023-09-27 22:02:07 -04:00
Santhosh S
31eeb2b63d Updated Doculink Docker 2023-09-25 23:38:20 -04:00
Santhosh S
49d809bbff Update docker for Responses 2023-09-25 23:34:52 -04:00
Santhosh S
cddbe63464 Merge branch 'docker-branch' of https://dev.azure.com/MDCSB-Telecommuters/Emergency%20Preparedness%20Disaster%20Recovery%20Project%20%28EPDRP%29/_git/Backend-API-Services into docker-branch 2023-09-25 23:27:56 -04:00
Santhosh S
7a59d300d4 Response project name conflict 2023-09-25 23:26:54 -04:00
Santhosh Nair
947efebdf3 Update docker-compose.yml for Azure Pipelines 2023-09-26 03:15:19 +00:00
Santhosh Nair
86f4eebe72 Update docker-compose.yml for Azure Pipelines 2023-09-26 03:11:36 +00:00
Santhosh S
fb5a69fa19 latest fixes sprint 4 2023-09-25 22:51:54 -04:00
Santhosh S
427fa3e559 port update 2023-09-25 22:30:20 -04:00
Santhosh S
eab826cf09 Resolved conflict with doculink port 2023-09-25 22:24:17 -04:00
uppuv
f2c1d47749 doculink changes 2023-09-22 11:56:09 -04:00
9dcd9d243e Created Groupings and added a few more
Tests should be grouped so that they can create, update, then eventually delete the data.
All the Gets are grouped together, but then later on you may need them to preform the CRUD operations.
2023-09-21 23:13:21 -05:00
8833fca734 Adding in tests for the endpoints after creation
Having tests on our code is essential, but it's equally crucial to ensure that all endpoints function correctly with each deployment. Once these validations are in place, we can integrate them into Jenkins during the build process to ensure that our releases are free of bugs.
2023-09-21 17:52:13 -05:00
Reginald Cherenfant Jasmin
a0033ca045 Add EmployeeId as filter in the endpoints, add endpoints to get all active and historical surveys for a particular employee 2023-09-21 00:58:29 -04:00
Santhosh S
3207b58b96 Dockerize with DocuLinks Inital version 2023-09-14 15:35:23 -04:00
Reginald CHERENFANT JASMIN
8d386af40a Changing Microservice name from Survey to Surveys 2023-09-14 11:57:23 -05:00
uppuv
0ad7bd5420 Merge branch 'DocumentsAPI' into dev 2023-09-13 16:50:56 -04:00
uppuv
3b91282419 document api link type changes 2023-09-13 16:49:59 -04:00
Reginald Cherenfant Jasmin
fedbb8a93e Merge branch 'dev' of https://dev.azure.com/MDCSB-Telecommuters/Emergency%20Preparedness%20Disaster%20Recovery%20Project%20%28EPDRP%29/_git/Backend-API-Services into localdev 2023-09-13 01:29:14 -04:00
Reginald Cherenfant Jasmin
9109d0d793 Update survey response, adding EmployeeId , Location Id as int, adjust end point for ansers submission in batch 2023-09-13 01:28:24 -04:00
uppuv
a6eed848f8 Merge branch 'DocumentsAPI' into dev 2023-09-11 13:42:40 -04:00
uppuv
b878cd706c 314: updated document multi language output format 2023-09-11 13:23:50 -04:00
uppuv
4cf7d9f891 Multi language dynamic object changes 2023-09-08 15:40:06 -04:00
Reginald Cherenfant Jasmin
24a6e6513e Adding external services to Service folder 2023-09-04 21:59:21 -04:00
Reginald Cherenfant Jasmin
a1a9fd1dc5 Update SeedData to be executed when MS launched, Enable other properties in SurveyResponse 2023-09-04 21:31:41 -04:00
Reginald Cherenfant Jasmin
81e14c387d Merge branch 'dev' of https://dev.azure.com/MDCSB-Telecommuters/Emergency%20Preparedness%20Disaster%20Recovery%20Project%20%28EPDRP%29/_git/Backend-API-Services into localdev 2023-09-01 12:19:08 -04:00
Reginald Cherenfant Jasmin
5a4dda12ff Update on the controller for NoContent return type 2023-09-01 12:14:25 -04:00
uppuv
debcb42021 Merge branch 'DocumentsAPI' into dev 2023-08-31 19:14:57 -04:00
uppuv
d78d5e0ba4 Modified Documents api for InMemory Logic 2023-08-31 19:12:47 -04:00
uppuv
fd65417a7b Added Document api solution 2023-08-31 19:00:51 -04:00
Reginald Cherenfant Jasmin
cd261a5556 Test project for location service updated 2023-08-31 01:57:14 -04:00
Reginald Cherenfant Jasmin
96ccb96bf1 Update to Async Attachement, Answer and Update Multiple Answers submission - backlog #288 2023-08-27 11:55:58 -04:00
Reginald Cherenfant Jasmin
5a641ff3aa Update controller in Location for Models Class 2023-08-25 18:51:50 -04:00
Reginald Cherenfant Jasmin
1e16a23a1a Merge branch 'dev' of https://dev.azure.com/MDCSB-Telecommuters/Emergency%20Preparedness%20Disaster%20Recovery%20Project%20%28EPDRP%29/_git/Backend-API-Services into localdev 2023-08-25 18:49:07 -04:00
Reginald Cherenfant Jasmin
7a50089f6a Update DbContext Changes 2023-08-25 18:44:04 -04:00
uppuv
82f2ae265a Db context changes for auto insertion 2023-08-25 18:24:46 -04:00
Reginald Cherenfant Jasmin
099055d088 Conflict resolved in Questions, Surveys 2023-08-25 17:51:07 -04:00
Reginald Cherenfant Jasmin
fe1614fee3 Multi Language support 2023-08-25 11:36:31 -04:00
Reginald Cherenfant Jasmin
448950ea27 Multilingual support for survey and Questions 2023-08-25 09:17:53 -04:00
Reginald Cherenfant Jasmin
47b0c7b202 Update Question and Survey to support multilingual functionnality and Make language optional in URL 2023-08-25 08:55:11 -04:00
uppuv
cf3a04891b Completed sync call for answer and attachment put and post methods 2023-08-25 07:20:37 -04:00
Santhosh S
e56ffae1a4 Swagger Documentation Enhancement (273) 2023-08-24 21:25:38 -04:00
uppuv
9345ee2ca5 Removed QuestionGroup from the Question model and from the db entity 2023-08-22 17:05:51 -04:00
Reginald Cherenfant Jasmin
22261f42ca User Role and Authorization features added 2023-08-18 15:30:34 -04:00
Santhosh S
4160c2300b Copy from old Repository 2023-08-15 23:52:30 -04:00
192 changed files with 15055 additions and 19 deletions

398
DamageAssesmentApi/.gitignore vendored Normal file
View File

@ -0,0 +1,398 @@
## 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/main/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/
[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
*.tlog
*.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 6 auto-generated project file (contains which files were open etc.)
*.vbp
# Visual Studio 6 workspace and project file (working project files containing files to include in project)
*.dsw
*.dsp
# Visual Studio 6 technical files
*.ncb
*.aps
# 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/
# Visual Studio History (VSHistory) files
.vshistory/
# 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
# VS Code files for those working on multiple tools
.vscode/*
!.vscode/settings.json
!.vscode/tasks.json
!.vscode/launch.json
!.vscode/extensions.json
*.code-workspace
# Local History for Visual Studio Code
.history/
# Windows Installer files from build outputs
*.cab
*.msi
*.msix
*.msm
*.msp
# JetBrains Rider
*.sln.iml

View File

@ -0,0 +1,189 @@
using AutoMapper;
using DamageAssesment.Api.Answers.Controllers;
using DamageAssesment.Api.Answers.Db;
using DamageAssesment.Api.Answers.Interfaces;
using DamageAssesment.Api.Answers.Profiles;
using DamageAssesment.Api.Answers.Providers;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using Moq;
using Xunit;
namespace DamageAssesment.Api.Answers.Test
{
public class AnswersServiceTest
{
[Fact(DisplayName = "Get Answers - Ok case")]
public async Task GetAnswersAsync_ShouldReturnStatusCode200()
{
var mockAnswerService = new Mock<IAnswersProvider>();
var mockResponse = await MockData.getOkResponse();
mockAnswerService.Setup(service => service.GetAnswersAsync()).ReturnsAsync(mockResponse);
var AnswerProvider = new AnswersController(mockAnswerService.Object);
var result = (OkObjectResult)await AnswerProvider.GetAnswersAsync();
Assert.Equal(200, result.StatusCode);
}
[Fact(DisplayName = "Get Answers - NoContent Case")]
public async Task GetAnswersAsync_ShouldReturnStatusCode204()
{
var mockAnswerService = new Mock<IAnswersProvider>();
var mockResponse = await MockData.getNoContentResponse();
mockAnswerService.Setup(service => service.GetAnswersAsync()).ReturnsAsync(mockResponse);
var AnswerProvider = new AnswersController(mockAnswerService.Object);
var result = (NoContentResult)await AnswerProvider.GetAnswersAsync();
Assert.Equal(204, result.StatusCode);
}
[Fact(DisplayName = "Get Answer by Id - Ok case")]
public async Task GetAnswerAsync_ShouldReturnStatusCode200()
{
var mockAnswerService = new Mock<IAnswersProvider>();
var mockResponse = await MockData.getOkResponse(1);
mockAnswerService.Setup(service => service.GetAnswerByIdAsync(1)).ReturnsAsync(mockResponse);
var AnswerProvider = new AnswersController(mockAnswerService.Object);
var result = (OkObjectResult)await AnswerProvider.GetAnswerByIdAsync(1);
Assert.Equal(200, result.StatusCode);
}
[Fact(DisplayName = "Get Answer by Id - NotFound case")]
public async Task GetAnswerAsync_ShouldReturnStatusCode404()
{
var mockAnswerService = new Mock<IAnswersProvider>();
var mockResponse = await MockData.getNotFoundResponse();
mockAnswerService.Setup(service => service.GetAnswerByIdAsync(99)).ReturnsAsync(mockResponse);
var AnswerProvider = new AnswersController(mockAnswerService.Object);
var result = (NotFoundResult)await AnswerProvider.GetAnswerByIdAsync(99);
Assert.Equal(404, result.StatusCode);
}
[Fact(DisplayName = "Get Answers by Survey resopnse id - Ok case")]
public async Task GetAnswersByResponseIdAsync_ShouldReturnStatusCode200()
{
var mockAnswerService = new Mock<IAnswersProvider>();
var mockResponse = await MockData.getOkResponse();
mockAnswerService.Setup(service => service.GetAnswersAsync(1)).ReturnsAsync(mockResponse);
var AnswerProvider = new AnswersController(mockAnswerService.Object);
var result = (OkObjectResult)await AnswerProvider.GetAnswersByResponseId(1);
Assert.Equal(200, result.StatusCode);
}
[Fact(DisplayName = "Get Answers by Survey resopnse id - NoContent Case")]
public async Task GetAnswersByResponseIdAsync_ShouldReturnStatusCode204()
{
var mockAnswerService = new Mock<IAnswersProvider>();
var mockResponse = await MockData.getNoContentResponse();
mockAnswerService.Setup(service => service.GetAnswersAsync(99)).ReturnsAsync(mockResponse);
var AnswerProvider = new AnswersController(mockAnswerService.Object);
var result = (NoContentResult)await AnswerProvider.GetAnswersByResponseId(99);
Assert.Equal(204, result.StatusCode);
}
[Fact(DisplayName = "Post Answer - Ok case")]
public async Task PostAnswerAsync_ShouldReturnStatusCode200()
{
var mockAnswerService = new Mock<IAnswersProvider>();
var mockResponse = await MockData.getOkResponse(1);
var mockInputAnswer = await MockData.getInputAnswerData();
mockAnswerService.Setup(service => service.PostAnswerAsync(mockInputAnswer)).ReturnsAsync(mockResponse);
var AnswerProvider = new AnswersController(mockAnswerService.Object);
var result = (OkObjectResult) await AnswerProvider.CreateAnswer(mockInputAnswer);
Assert.Equal(200, result.StatusCode);
}
[Fact(DisplayName = "Post Answer - BadRequest case")]
public async Task PostAnswerAsync_ShouldReturnStatusCode400()
{
var mockAnswerService = new Mock<IAnswersProvider>();
var mockInputAnswer = await MockData.getInputAnswerData();
var mockResponse = await MockData.getBadRequestResponse();
mockAnswerService.Setup(service => service.PostAnswerAsync(mockInputAnswer)).ReturnsAsync(mockResponse);
var AnswerProvider = new AnswersController(mockAnswerService.Object);
var result = (BadRequestObjectResult) await AnswerProvider.CreateAnswer(mockInputAnswer);
Assert.Equal(400, result.StatusCode);
}
[Fact(DisplayName = "Put Answer - Ok case")]
public async Task PutAnswerAsync_ShouldReturnStatusCode200()
{
var mockAnswerService = new Mock<IAnswersProvider>();
var mockResponse = await MockData.getOkResponse(1);
var mockInputAnswer = await MockData.getInputAnswerData();
mockAnswerService.Setup(service => service.UpdateAnswerAsync(mockInputAnswer)).ReturnsAsync(mockResponse);
var AnswerProvider = new AnswersController(mockAnswerService.Object);
var result = (OkObjectResult) await AnswerProvider.UpdateAnswer(mockInputAnswer);
Assert.Equal(200, result.StatusCode);
}
[Fact(DisplayName = "Put Answer - NotFound case")]
public async Task PutAnswerAsync_ShouldReturnStatusCode404()
{
var mockAnswerService = new Mock<IAnswersProvider>();
var mockResponse = await MockData.getNotFoundResponse();
var mockInputAnswer = await MockData.getInputAnswerData();
mockAnswerService.Setup(service => service.UpdateAnswerAsync(mockInputAnswer)).ReturnsAsync(mockResponse);
var AnswerProvider = new AnswersController(mockAnswerService.Object);
var result = (NotFoundObjectResult) await AnswerProvider.UpdateAnswer(mockInputAnswer);
Assert.Equal(404, result.StatusCode);
}
[Fact(DisplayName = "Put Answer - BadRequest case")]
public async Task PutAnswerAsync_ShouldReturnStatusCode400()
{
var mockAnswerService = new Mock<IAnswersProvider>();
var mockResponse = await MockData.getBadRequestResponse();
var mockInputAnswer = await MockData.getInputAnswerData();
mockAnswerService.Setup(service => service.UpdateAnswerAsync(mockInputAnswer)).ReturnsAsync(mockResponse);
var AnswerProvider = new AnswersController(mockAnswerService.Object);
var result = (BadRequestObjectResult) await AnswerProvider.UpdateAnswer(mockInputAnswer);
Assert.Equal(400, result.StatusCode);
}
[Fact(DisplayName = "Delete Answer - Ok case")]
public async Task DeleteAnswerAsync_ShouldReturnStatusCode200()
{
var mockAnswerService = new Mock<IAnswersProvider>();
var mockResponse = await MockData.getOkResponse(1);
mockAnswerService.Setup(service => service.DeleteAnswerAsync(1)).ReturnsAsync(mockResponse);
var AnswerProvider = new AnswersController(mockAnswerService.Object);
var result = (OkObjectResult)await AnswerProvider.DeleteAnswer(1);
Assert.Equal(200, result.StatusCode);
}
[Fact(DisplayName = "Delete Answer - NotFound case")]
public async Task DeleteAnswerAsync_ShouldReturnStatusCode404()
{
var mockAnswerService = new Mock<IAnswersProvider>();
var mockResponse = await MockData.getNotFoundResponse();
mockAnswerService.Setup(service => service.DeleteAnswerAsync(1)).ReturnsAsync(mockResponse);
var AnswerProvider = new AnswersController(mockAnswerService.Object);
var result = (NotFoundResult)await AnswerProvider.DeleteAnswer(1);
Assert.Equal(404, result.StatusCode);
}
}
}

View File

@ -0,0 +1,30 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net6.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<IsPackable>false</IsPackable>
<IsTestProject>true</IsTestProject>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.5.0" />
<PackageReference Include="Moq" Version="4.18.4" />
<PackageReference Include="xunit" Version="2.4.2" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.5">
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
<PrivateAssets>all</PrivateAssets>
</PackageReference>
<PackageReference Include="coverlet.collector" Version="3.2.0">
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
<PrivateAssets>all</PrivateAssets>
</PackageReference>
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\DamageAssesment.Api.Answers\DamageAssesment.Api.Answers.csproj" />
</ItemGroup>
</Project>

View File

@ -0,0 +1,53 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace DamageAssesment.Api.Answers.Test
{
public class MockData
{
public static async Task<(bool, IEnumerable<Answers.Models.Answer>, string)> getOkResponse()
{
IEnumerable<Answers.Models.Answer> list = new List<Answers.Models.Answer>();
for (int i = 0; i < 10; i++)
{
list.Append(new Answers.Models.Answer { Id = i, AnswerText = "Yes", Comment = "", QuestionId = i, SurveyResponseId = i });
}
return (true, list, null);
}
public static async Task<(bool, Answers.Models.Answer, string)> getOkResponse(int Id)
{
var Answers = await getOkResponse();
var Answer = Answers.Item2.FirstOrDefault(s => s.Id == Id);
return (true, Answer, null);
}
public static async Task<(bool, Answers.Models.Answer, string)> getBadRequestResponse()
{
return (false, null, "Bad Request");
}
public static async Task<(bool, Answers.Models.Answer, string)> getNotFoundResponse()
{
return (false, null, "Not Found");
}
public static async Task<(bool, IEnumerable<Answers.Models.Answer>, string)> getNoContentResponse()
{
IEnumerable<Answers.Models.Answer> list = new List<Answers.Models.Answer>();
return (false, list, null);
}
public static async Task<Answers.Models.Answer> getInputAnswerData()
{
return new Answers.Models.Answer { Id = 1, AnswerText = "Yes", Comment = "", QuestionId = 1, SurveyResponseId = 1 };
}
}
}

View File

@ -0,0 +1,130 @@
using DamageAssesment.Api.Answers.Interfaces;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using Microsoft.OpenApi.Any;
namespace DamageAssesment.Api.Answers.Controllers
{
[ApiController]
public class AnswersController: ControllerBase
{
private IAnswersProvider answerProvider;
public AnswersController(IAnswersProvider answersProvider) {
this.answerProvider=answersProvider;
}
/// <summary>
/// Get all answers
/// </summary>
[HttpGet("answers")]
public async Task<ActionResult> GetAnswersAsync() {
var result = await answerProvider.GetAnswersAsync();
if(result.IsSuccess)
{
return Ok(result.Answers);
}
return NoContent();
}
/// <summary>
/// Get an answer based on answerId.
/// </summary>
[HttpGet("answers/{id}")]
public async Task<ActionResult> GetAnswerByIdAsync(int id)
{
var result = await answerProvider.GetAnswerByIdAsync(id);
if (result.IsSuccess)
{
return Ok(result.Answer);
}
return NotFound();
}
/// <summary>
/// Get all answers based on responseId.
/// </summary>
[HttpGet("answers/byresponse/{responseid}")]
public async Task<IActionResult> GetAnswersByResponseId(int responseid)
{
var result = await this.answerProvider.GetAnswersAsync(responseid);
if(result.IsSuccess)
{
return Ok(result.Answers);
}
return NoContent();
}
/// <summary>
/// Get all answers based on questionId.
/// </summary>
[HttpGet("answers/byquestion/{questionid}")]
public async Task<IActionResult> AnswersByQuestionId(int questionid)
{
var result = await this.answerProvider.GetAnswersByQuestionAsync(questionid);
if (result.IsSuccess)
{
return Ok(result.Answers);
}
return NotFound();
}
/// <summary>
/// Update an existing answer.
/// </summary>
[HttpPut("answers")]
public async Task<IActionResult> UpdateAnswer(Models.Answer answer)
{
if (answer != null)
{
var result = await this.answerProvider.UpdateAnswerAsync(answer);
if (result.IsSuccess)
{
return Ok(result.Answer);
}
if (result.ErrorMessage == "Not Found")
return NotFound(result.ErrorMessage);
return BadRequest(result.ErrorMessage);
}
return NotFound();
}
/// <summary>
/// Save a new answer.
/// </summary>
[HttpPost("answers")]
public async Task<IActionResult> CreateAnswer(Models.Answer answer)
{
if (answer != null)
{
var result = await this.answerProvider.PostAnswerAsync(answer);
if (result.IsSuccess)
{
return Ok(result.Answer);
}
return BadRequest(result.ErrorMessage);
}
return CreatedAtRoute("DefaultApi", new { id = answer.Id }, answer);
}
/// <summary>
/// Delete an existing answer.
/// </summary>
[HttpDelete("answers/{id}")]
public async Task<IActionResult> DeleteAnswer(int id)
{
var result = await this.answerProvider.DeleteAnswerAsync(id);
if (result.IsSuccess)
{
return Ok(result.Answer);
}
return NotFound();
}
}
}

View File

@ -0,0 +1,18 @@
<Project Sdk="Microsoft.NET.Sdk.Web">
<PropertyGroup>
<TargetFramework>net6.0</TargetFramework>
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
<GenerateDocumentationFile>True</GenerateDocumentationFile>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="AutoMapper.Extensions.Microsoft.DependencyInjection" Version="12.0.1" />
<PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="6.0.21" />
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="7.0.9" />
<PackageReference Include="Microsoft.EntityFrameworkCore.InMemory" Version="7.0.9" />
<PackageReference Include="Swashbuckle.AspNetCore" Version="6.2.3" />
</ItemGroup>
</Project>

View File

@ -0,0 +1,21 @@
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
namespace DamageAssesment.Api.Answers.Db
{
[Table("Answers")]
public class Answer
{
[Key]
public int Id { get; set; }
[ForeignKey("Question")]
public int QuestionId { get; set; }
[StringLength(250)]
public string AnswerText { get; set; }
public string Comment { get; set; }
[ForeignKey("SurveyResponse")]
public int? SurveyResponseId { get; set; }
}
}

View File

@ -0,0 +1,22 @@
using Microsoft.EntityFrameworkCore;
namespace DamageAssesment.Api.Answers.Db
{
public class AnswerDbContext:DbContext
{
public AnswerDbContext(DbContextOptions options):base(options)
{
}
public DbSet<Db.Answer> Answers { get; set; }
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
modelBuilder.Entity<Answer>()
.Property(item => item.Id)
.ValueGeneratedOnAdd();
}
}
}

View File

@ -0,0 +1,14 @@
namespace DamageAssesment.Api.Answers.Interfaces
{
public interface IAnswersProvider
{
Task<(bool IsSuccess,IEnumerable< Models.Answer> Answers, string ErrorMessage)> GetAnswersAsync();
Task<(bool IsSuccess, IEnumerable<Models.Answer> Answers, string ErrorMessage)> GetAnswersByQuestionAsync(int questionId);
Task<(bool IsSuccess, Models.Answer Answer, string ErrorMessage)> GetAnswerByIdAsync(int Id);
Task<(bool IsSuccess, IEnumerable<Models.Answer> Answers, string ErrorMessage)> GetAnswersAsync(int responseId);
Task<(bool IsSuccess, Models.Answer Answer, string ErrorMessage)> PostAnswerAsync(Models.Answer Answer);
Task<(bool IsSuccess, Models.Answer Answer, string ErrorMessage)> UpdateAnswerAsync(Models.Answer Answer);
Task<(bool IsSuccess, Models.Answer Answer, string ErrorMessage)> DeleteAnswerAsync(int Id);
void SeedData();
}
}

View File

@ -0,0 +1,15 @@
using System.ComponentModel.DataAnnotations;
namespace DamageAssesment.Api.Answers.Models
{
public class Answer
{
public int Id { get; set; }
public int QuestionId { get; set; }
[StringLength(250)]
public string AnswerText { get; set; }
public string Comment { get; set; }
public int? SurveyResponseId { get; set; }
}
}

View File

@ -0,0 +1,13 @@
using AutoMapper;
namespace DamageAssesment.Api.Answers.Profiles
{
public class AnswersProfile : AutoMapper.Profile
{
public AnswersProfile()
{
CreateMap<Db.Answer,Models.Answer>();
CreateMap<Models.Answer, Db.Answer>();
}
}
}

View File

@ -0,0 +1,43 @@
using DamageAssesment.Api.Answers.Db;
using DamageAssesment.Api.Answers.Interfaces;
using DamageAssesment.Api.Answers.Providers;
using Microsoft.EntityFrameworkCore;
using System.Reflection;
var builder = WebApplication.CreateBuilder(args);
// Add services to the container.
builder.Services.AddControllers();
// Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle
builder.Services.AddEndpointsApiExplorer();
//builder.Services.AddSwaggerGen();
builder.Services.AddSwaggerGen(c =>
{
// Include XML comments from your assembly
var xmlFile = $"{Assembly.GetExecutingAssembly().GetName().Name}.xml";
var xmlPath = Path.Combine(AppContext.BaseDirectory, xmlFile);
c.IncludeXmlComments(xmlPath);
});
builder.Services.AddScoped<IAnswersProvider, AnswersProvider>();
builder.Services.AddAutoMapper(AppDomain.CurrentDomain.GetAssemblies()); //4/30
builder.Services.AddDbContext<AnswerDbContext>(option =>
{
option.UseInMemoryDatabase("Answers");
});
var app = builder.Build();
// Configure the HTTP request pipeline.
if (app.Environment.IsDevelopment())
{
app.UseSwagger();
app.UseSwaggerUI();
}
app.UseAuthorization();
app.MapControllers();
app.Run();

View File

@ -0,0 +1,31 @@
{
"$schema": "https://json.schemastore.org/launchsettings.json",
"iisSettings": {
"windowsAuthentication": false,
"anonymousAuthentication": true,
"iisExpress": {
"applicationUrl": "http://localhost:18005",
"sslPort": 0
}
},
"profiles": {
"DamageAssesment.Api.Answers": {
"commandName": "Project",
"dotnetRunMessages": true,
"launchBrowser": true,
"launchUrl": "swagger",
"applicationUrl": "http://localhost:5200",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
},
"IIS Express": {
"commandName": "IISExpress",
"launchBrowser": true,
"launchUrl": "swagger",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
}
}
}

View File

@ -0,0 +1,212 @@
using AutoMapper;
using DamageAssesment.Api.Answers.Db;
using DamageAssesment.Api.Answers.Interfaces;
using DamageAssesment.Api.Answers.Models;
using Microsoft.EntityFrameworkCore;
namespace DamageAssesment.Api.Answers.Providers
{
public class AnswersProvider : IAnswersProvider
{
private AnswerDbContext answerDbContext;
private ILogger<AnswersProvider> logger;
private IMapper mapper;
// Constructor with dependency injection and data seeding
public AnswersProvider(AnswerDbContext answerDbContext, ILogger<AnswersProvider> logger, IMapper mapper)
{
this.answerDbContext = answerDbContext;
this.logger = logger;
this.mapper = mapper;
SeedData(); // Seed initial data if the table is empty
}
// Get all answers
public async Task<(bool IsSuccess, IEnumerable<Models.Answer> Answers, string ErrorMessage)> GetAnswersAsync()
{
try
{
logger?.LogInformation("Query Question");
var answer = await answerDbContext.Answers.AsNoTracking().ToListAsync();
if (answer != null)
{
logger?.LogInformation($"{answer.Count} Answers(s) found");
var result = mapper.Map<IEnumerable<Db.Answer>, IEnumerable<Models.Answer>>(answer);
return (true, result, null);
}
return (false, null, "Not found");
}
catch (Exception ex)
{
logger?.LogError(ex.ToString());
return (false, null, ex.Message);
}
}
// Get an answer by its ID
public async Task<(bool IsSuccess, Models.Answer Answer, string ErrorMessage)> GetAnswerByIdAsync(int Id)
{
try
{
logger?.LogInformation("Query Answer");
var answer = await answerDbContext.Answers.AsNoTracking().FirstOrDefaultAsync(q => q.Id == Id);
if (answer != null)
{
logger?.LogInformation($"{answer} customer(s) found");
var result = mapper.Map<Db.Answer, Models.Answer>(answer);
return (true, result, null);
}
return (false, null, "Not found");
}
catch (Exception ex)
{
logger?.LogError(ex.ToString());
return (false, null, ex.Message);
}
}
// Get answers by survey response ID
public async Task<(bool IsSuccess, IEnumerable<Models.Answer> Answers, string ErrorMessage)> GetAnswersAsync(int surveyResponseId)
{
try
{
var respAnswers = await answerDbContext.Answers.AsNoTracking()
.Where(a => a.SurveyResponseId == surveyResponseId).AsNoTracking()
.ToListAsync();
if (respAnswers != null)
{
var result = mapper.Map<IEnumerable<Db.Answer>, IEnumerable<Models.Answer>>(respAnswers);
return (true, result, null);
}
return (false, null, "Not Found");
}
catch (Exception ex)
{
logger?.LogError(ex.ToString());
return (false, null, ex.Message);
}
}
// Get answers by question ID
public async Task<(bool IsSuccess, IEnumerable<Models.Answer> Answers, string ErrorMessage)> GetAnswersByQuestionAsync(int questionId)
{
try
{
var respAnswers = await answerDbContext.Answers.AsNoTracking()
.Where(a => a.QuestionId == questionId).AsNoTracking()
.ToListAsync();
if (respAnswers != null)
{
var result = mapper.Map<IEnumerable<Db.Answer>, IEnumerable<Models.Answer>>(respAnswers);
return (true, result, null);
}
return (false, null, "Not Found");
}
catch (Exception ex)
{
logger?.LogError(ex.ToString());
return (false, null, ex.Message);
}
}
// Create a new answer
public async Task<(bool IsSuccess, Models.Answer Answer, string ErrorMessage)> PostAnswerAsync(Models.Answer Answer)
{
try
{
logger?.LogInformation("Query Answer");
if (!AnswerExists(Answer.Id))
{
Db.Answer answer = mapper.Map<Models.Answer, Db.Answer>(Answer);
answerDbContext.Answers.Add(answer);
await answerDbContext.SaveChangesAsync();
var result = mapper.Map<Db.Answer, Models.Answer>(answer);
return (true, result, null);
}
return (false, null, "Answer is already exists");
}
catch (Exception ex)
{
logger?.LogError(ex.ToString());
return (false, null, ex.Message);
}
}
// Update an existing answer
public async Task<(bool IsSuccess, Models.Answer Answer, string ErrorMessage)> UpdateAnswerAsync(Models.Answer Answer)
{
try
{
if (Answer != null)
{
var existing = answerDbContext.Answers.AsNoTracking().FirstOrDefault(x => x.Id == Answer.Id);
if (existing != null)
{
Db.Answer answer = mapper.Map<Models.Answer, Db.Answer>(Answer);
answerDbContext.Answers.Update(answer);
await answerDbContext.SaveChangesAsync();
return (true, mapper.Map<Db.Answer, Models.Answer>(answer), "Successful");
}
else
{
logger?.LogInformation($"{Answer} Not found");
return (false, null, "Not Found");
}
}
else
{
logger?.LogInformation($"{Answer} Bad Request");
return (false, null, "Bad request");
}
}
catch (Exception ex)
{
logger?.LogError(ex.ToString());
return (false, null, ex.Message);
}
}
// Delete an answer by its ID
public async Task<(bool IsSuccess, Models.Answer Answer, string ErrorMessage)> DeleteAnswerAsync(int Id)
{
try
{
Db.Answer answer = answerDbContext.Answers.AsNoTracking().Where(a => a.Id == Id).FirstOrDefault();
if (answer == null)
{
return (false, null, "Not Found");
}
answerDbContext.Answers.Remove(answer);
answerDbContext.SaveChanges();
return (true, mapper.Map<Db.Answer, Models.Answer>(answer), $"AnswerId {Id} deleted successfully");
}
catch (Exception ex)
{
logger?.LogError(ex.ToString());
return (false, null, ex.Message);
}
}
// Check if an answer with a specific ID exists
private bool AnswerExists(int id)
{
return answerDbContext.Answers.AsNoTracking().Count(e => e.Id == id) > 0;
}
// Seed initial data if the table is empty
public void SeedData()
{
if (!answerDbContext.Answers.Any())
{
answerDbContext.Answers.Add(new Db.Answer() { Id = 1, AnswerText = "Yes", Comment = "Comment test 4", QuestionId = 1, SurveyResponseId = 1 });
answerDbContext.Answers.Add(new Db.Answer() { Id = 2, AnswerText = "No", Comment = "Comment test 5", QuestionId = 2, SurveyResponseId = 1 });
// Uncomment the lines below to add more initial data if needed
//answerDbContext.Answers.Add(new Db.Answer() { Id = 3, AnswerText = "No", Comment = "No Comment", QuestionId = 3, SurveyResponseId = 1 });
//answerDbContext.Answers.Add(new Db.Answer() { Id = 4, AnswerText = "Yes", Comment = "No Comment", QuestionId = 1, SurveyResponseId = 2 });
//answerDbContext.Answers.Add(new Db.Answer() { Id = 5, AnswerText = "No", Comment = "No Comment", QuestionId = 2, SurveyResponseId = 2 });
//answerDbContext.Answers.Add(new Db.Answer() { Id = 6, AnswerText = "No", Comment = "No Comment", QuestionId = 3, SurveyResponseId = 2 });
answerDbContext.SaveChanges();
}
}
}
}

View File

@ -0,0 +1,12 @@
{
"JwtSettings": {
"securitykey": "bWlhbWkgZGFkZSBzY2hvb2xzIHNlY3JldCBrZXk="
},
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft.AspNetCore": "Warning"
}
},
"AllowedHosts": "*"
}

View File

@ -0,0 +1,162 @@
using AutoMapper;
using DamageAssesment.Api.Attachments.Controllers;
using DamageAssesment.Api.Attachments.Db;
using DamageAssesment.Api.Attachments.Interfaces;
using DamageAssesment.Api.Attachments.Models;
using DamageAssesment.Api.Attachments.Profiles;
using DamageAssesment.Api.Attachments.Providers;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using Moq;
using System.Collections.Generic;
using Xunit;
namespace DamageAssesment.Api.Attachments.Test
{
public class AttachmentServiceTest
{
[Fact(DisplayName = "Get Attachments - Ok case")]
public async Task GetAttachmentsAsync_ShouldReturnStatusCode200()
{
var mockAttachmentService = new Mock<IAttachmentsProvider>();
var mockUploadService = new Mock<IUploadService>();
var mockResponse = await MockData.getOkResponse();
mockAttachmentService.Setup(service => service.GetAttachmentsAsync()).ReturnsAsync(mockResponse);
var AttachmentProvider = new AttachmentsController(mockAttachmentService.Object, mockUploadService.Object);
var result = (OkObjectResult)await AttachmentProvider.GetAttachmentsAsync();
Assert.Equal(200, result.StatusCode);
}
[Fact(DisplayName = "Get Attachments - NoContent Case")]
public async Task GetAttachmentsAsync_ShouldReturnStatusCode204()
{
var mockAttachmentService = new Mock<IAttachmentsProvider>();
var mockUploadService = new Mock<IUploadService>();
var mockResponse = await MockData.getNoContentResponse();
mockAttachmentService.Setup(service => service.GetAttachmentsAsync()).ReturnsAsync(mockResponse);
var AttachmentProvider = new AttachmentsController(mockAttachmentService.Object, mockUploadService.Object);
var result = (NoContentResult)await AttachmentProvider.GetAttachmentsAsync();
Assert.Equal(204, result.StatusCode);
}
[Fact(DisplayName = "Get Attachment by Id - Ok case")]
public async Task GetAttachmentAsync_ShouldReturnStatusCode200()
{
var mockAttachmentService = new Mock<IAttachmentsProvider>();
var mockUploadService = new Mock<IUploadService>();
var mockResponse = await MockData.getOkResponse(1);
mockAttachmentService.Setup(service => service.GetAttachmentByIdAsync(1)).ReturnsAsync(mockResponse);
var AttachmentProvider = new AttachmentsController(mockAttachmentService.Object, mockUploadService.Object);
var result = (OkObjectResult)await AttachmentProvider.GetAttachmentbyIdAsync(1);
Assert.Equal(200, result.StatusCode);
}
[Fact(DisplayName = "Get Attachment by Id - NotFound case")]
public async Task GetAttachmentAsync_ShouldReturnStatusCode404()
{
var mockAttachmentService = new Mock<IAttachmentsProvider>();
var mockUploadService = new Mock<IUploadService>();
var mockResponse = await MockData.getNotFoundResponse();
mockAttachmentService.Setup(service => service.GetAttachmentByIdAsync(99)).ReturnsAsync(mockResponse);
var AttachmentProvider = new AttachmentsController(mockAttachmentService.Object, mockUploadService.Object);
var result = (NotFoundResult)await AttachmentProvider.GetAttachmentbyIdAsync(99);
Assert.Equal(404, result.StatusCode);
}
[Fact(DisplayName = "Post Attachment - Ok case")]
public async Task PostAttachmentAsync_ShouldReturnStatusCode200()
{
var mockAttachmentService = new Mock<IAttachmentsProvider>();
var mockUploadService = new Mock<IUploadService>();
var mockResponse = await MockData.getOkResponse();
var AttachmentResponse = await MockData.GetAttachmentInfo(0);
var mockInputAttachment = await MockData.getInputAttachmentData();
mockAttachmentService.Setup(service => service.PostAttachmentAsync(mockInputAttachment)).ReturnsAsync(mockResponse);
var AttachmentProvider = new AttachmentsController(mockAttachmentService.Object, mockUploadService.Object);
var result = (NoContentResult) await AttachmentProvider.UploadAttachmentAsync(AttachmentResponse);
Assert.Equal(204, result.StatusCode);
}
[Fact(DisplayName = "Post Attachment - BadRequest case")]
public async Task PostAttachmentAsync_ShouldReturnStatusCode400()
{
var mockAttachmentService = new Mock<IAttachmentsProvider>();
var mockUploadService = new Mock<IUploadService>();
var mockInputAttachment = await MockData.getInputAttachmentData();
var mockResponse = await MockData.getBadRequestResponse();
mockAttachmentService.Setup(service => service.PostAttachmentAsync(mockInputAttachment)).ReturnsAsync(mockResponse);
var AttachmentProvider = new AttachmentsController(mockAttachmentService.Object, mockUploadService.Object);
AttachmentInfo attachmentInfo=new AttachmentInfo();
var result = (BadRequestObjectResult) await AttachmentProvider.UploadAttachmentAsync(attachmentInfo);
Assert.Equal(400, result.StatusCode);
}
[Fact(DisplayName = "Put Attachment - Ok case")]
public async Task PutAttachmentAsync_ShouldReturnStatusCode200()
{
var mockAttachmentService = new Mock<IAttachmentsProvider>();
var mockUploadService = new Mock<IUploadService>();
var mockResponse = await MockData.getOkResponse();
var AttachmentResponse = await MockData.GetAttachmentInfo(1);
var mockInputAttachment = await MockData.getInputAttachmentData();
mockAttachmentService.Setup(service => service.PostAttachmentAsync(mockInputAttachment)).ReturnsAsync(mockResponse);
var AttachmentProvider = new AttachmentsController(mockAttachmentService.Object, mockUploadService.Object);
var result = (NoContentResult) await AttachmentProvider.UpdateAttachmentAsync(AttachmentResponse);
Assert.Equal(204, result.StatusCode);
}
[Fact(DisplayName = "Put Attachment - BadRequest case")]
public async Task PutAttachmentAsync_ShouldReturnStatusCode400()
{
var mockAttachmentService = new Mock<IAttachmentsProvider>();
var mockUploadService = new Mock<IUploadService>();
var mockInputAttachment = await MockData.getInputAttachmentData();
var mockResponse = await MockData.getBadRequestResponse();
mockAttachmentService.Setup(service => service.PostAttachmentAsync(mockInputAttachment)).ReturnsAsync(mockResponse);
var AttachmentProvider = new AttachmentsController(mockAttachmentService.Object, mockUploadService.Object);
AttachmentInfo attachmentInfo = new AttachmentInfo();
var result = (BadRequestObjectResult) await AttachmentProvider.UpdateAttachmentAsync(attachmentInfo);
Assert.Equal(400, result.StatusCode);
}
[Fact(DisplayName = "Delete Attachment - Ok case")]
public async Task DeleteAttachmentAsync_ShouldReturnStatusCode200()
{
var mockAttachmentService = new Mock<IAttachmentsProvider>();
var mockUploadService = new Mock<IUploadService>();
var mockResponse = await MockData.getOkResponse(1);
mockAttachmentService.Setup(service => service.DeleteAttachmentAsync(1)).ReturnsAsync(mockResponse);
mockUploadService.Setup(service => service.Deletefile(""));
var AttachmentProvider = new AttachmentsController(mockAttachmentService.Object, mockUploadService.Object);
var result = (OkObjectResult)await AttachmentProvider.DeleteAttachment(1);
Assert.Equal(200, result.StatusCode);
}
[Fact(DisplayName = "Delete Attachment - NotFound case")]
public async Task DeleteAttachmentAsync_ShouldReturnStatusCode404()
{
var mockAttachmentService = new Mock<IAttachmentsProvider>();
var mockUploadService = new Mock<IUploadService>();
var mockResponse = await MockData.getNotFoundResponse();
mockAttachmentService.Setup(service => service.DeleteAttachmentAsync(1)).ReturnsAsync(mockResponse);
var AttachmentProvider = new AttachmentsController(mockAttachmentService.Object, mockUploadService.Object);
var result = (NotFoundResult)await AttachmentProvider.DeleteAttachment(1);
Assert.Equal(404, result.StatusCode);
}
}
}

View File

@ -0,0 +1,30 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net6.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<IsPackable>false</IsPackable>
<IsTestProject>true</IsTestProject>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.5.0" />
<PackageReference Include="Moq" Version="4.18.4" />
<PackageReference Include="xunit" Version="2.4.2" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.5">
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
<PrivateAssets>all</PrivateAssets>
</PackageReference>
<PackageReference Include="coverlet.collector" Version="3.2.0">
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
<PrivateAssets>all</PrivateAssets>
</PackageReference>
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\DamageAssesment.Api.Attachments\DamageAssesment.Api.Attachments.csproj" />
</ItemGroup>
</Project>

View File

@ -0,0 +1,84 @@
using DamageAssesment.Api.Attachments.Models;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Mail;
using System.Text;
using System.Threading.Tasks;
namespace DamageAssesment.Api.Attachments.Test
{
public class MockData
{
public static async Task<(bool, List<Attachments.Models.Attachment>, string)> getOkResponse()
{
List<Attachments.Models.Attachment> list = new List<Attachments.Models.Attachment>();
for (int i = 0; i < 10; i++)
{
list.Add(new Attachments.Models.Attachment()
{
Id = i,
AnswerId = i,
URI = Guid.NewGuid().ToString() + "@gmail.com",
ResponseId = i,
IsDeleted = false,
FileName="sample"+i
});
}
return (true, list, null);
}
public static async Task<Attachments.Models.AttachmentInfo> GetAttachmentInfo(int id)
{
List<FileModel> files = new List<FileModel>();
List<AnswerInfo> answerInfos = new List<AnswerInfo>();
files.Add(new FileModel()
{
AttachmentId = id,
FileName = "Sample1",
FileContent = "sample",
FileExtension = ".jpg"
});
answerInfos.Add(new AnswerInfo()
{
AnswerId = 1,
postedFiles = files
});
return new AttachmentInfo
{
ResponseId = 1,
Answers = answerInfos
};
}
public static async Task<(bool, Attachments.Models.Attachment, string)> getOkResponse(int Id)
{
var Attachments = await getOkResponse();
var Attachment = Attachments.Item2.FirstOrDefault(s => s.Id == Id);
return (true, Attachment, null);
}
public static async Task<(bool, List<Attachments.Models.Attachment>, string)> getBadRequestResponse()
{
return (false, null, "Bad Request");
}
public static async Task<(bool, Attachments.Models.Attachment, string)> getNotFoundResponse()
{
return (false, null, "Not Found");
}
public static async Task<(bool, IEnumerable<Attachments.Models.Attachment>, string)> getNoContentResponse()
{
IEnumerable<Attachments.Models.Attachment> list = new List<Attachments.Models.Attachment>();
return (false, list, null);
}
public static async Task<List<Attachments.Models.Attachment>> getInputAttachmentData()
{
List<Attachments.Models.Attachment> Attachments=new List<Models.Attachment>();
Attachments.Add(new Models.Attachment{ Id = 0, AnswerId = 10, ResponseId = 10, URI = "sample", IsDeleted = false,FileName="sample1" }) ;
return Attachments;
}
}
}

View File

@ -0,0 +1,230 @@
using Azure;
using DamageAssesment.Api.Attachments.Interfaces;
using DamageAssesment.Api.Attachments.Models;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using System.Net.Http.Headers;
namespace DamageAssesment.Api.Attachments.Controllers
{
[ApiController]
public class AttachmentsController : ControllerBase
{
private IAttachmentsProvider AttachmentProvider;
private IUploadService UploadService;
public AttachmentsController(IAttachmentsProvider AttachmentsProvider, IUploadService uploadService)
{
this.AttachmentProvider = AttachmentsProvider;
this.UploadService = uploadService;
}
/// <summary>
/// Get all attachments.
/// </summary>
[HttpGet("attachments")]
public async Task<ActionResult> GetAttachmentsAsync()
{
var result = await AttachmentProvider.GetAttachmentsAsync();
if (result.IsSuccess)
{
return Ok(result.Attachments);
}
return NoContent();
}
/// <summary>
/// Get all attachments by attachmentId.
/// </summary>
[HttpGet("attachments/{id}")]
public async Task<ActionResult> GetAttachmentbyIdAsync(int id)
{
var result = await AttachmentProvider.GetAttachmentByIdAsync(id);
if (result.IsSuccess)
{
return Ok(result.Attachment);
}
return NotFound();
}
////Save new Attachment
//[HttpPost("Attachments"), DisableRequestSizeLimit]
//public async Task<IActionResult> UploadAsync(int responseId, int answerId, List<IFormFile> postedFile)
//{
// try
// {
// if (postedFile.Count > 0)
// {
// //Upload logic for all files
// var Attachments= await this.AttachmentProvider.DeleteAttachmentsAsync(responseId,answerId);
// List<Db.Attachment> attachments = UploadService.UploadAttachment(responseId, answerId, Attachments.counter, postedFile);
// //inserting all uploaded files in database
// var result = await this.AttachmentProvider.PostAttachmentAsync(attachments);
// if (result.IsSuccess)
// {
// return Ok(result.Attachments);
// }
// return BadRequest(result.ErrorMessage);
// }
// return NoContent();
// }
// catch (Exception ex)
// {
// return BadRequest($"Internal server error: {ex}");
// }
//}
/// <summary>
/// Save new Attachment(s)
/// </summary>
[HttpPost("attachments"), DisableRequestSizeLimit]
public async Task<IActionResult> UploadAttachmentAsync(AttachmentInfo attachmentInfo)
{
try
{
if (attachmentInfo.Answers.Count > 0)
{
var Attachments = await this.AttachmentProvider.GetAttachmentCounter();
List<Models.Attachment> attachments = UploadService.UploadAttachment(attachmentInfo.ResponseId, Attachments.counter, attachmentInfo.Answers);
var result = await this.AttachmentProvider.PostAttachmentAsync(attachments);
if (result.IsSuccess)
{
return Ok(result.Attachments);
}
return NoContent();
}
return BadRequest();
}
catch (Exception ex)
{
return BadRequest($"Internal server error: {ex}");
}
}
/// <summary>
/// Modify an new attachment.
/// </summary>
[HttpPut("attachments"), DisableRequestSizeLimit]
public async Task<IActionResult> UpdateAttachmentAsync(AttachmentInfo attachmentInfo)
{
try
{
if (attachmentInfo.Answers.Count > 0)
{
var res = await this.AttachmentProvider.GetAttachmentInfo(attachmentInfo.Answers);
if (res.IsSuccess)
{
List<Models.Attachment> attachments = UploadService.UpdateAttachments(attachmentInfo.ResponseId, attachmentInfo.Answers, res.Attachments);
var result = await this.AttachmentProvider.PutAttachmentAsync(attachments);
if (result.IsSuccess)
{
return Ok(result.Attachments);
}
return NoContent();
}
return NoContent();
}
return BadRequest();
}
catch (Exception ex)
{
return BadRequest($"Internal server error: {ex}");
}
}
/// <summary>
/// download an existing attachment.
/// </summary>
[HttpGet("attachments/download/{id}")]
public async Task<IActionResult> downloadfile(int id)
{
try
{
var result = await this.AttachmentProvider.GetDownloadAttachmentAsync(id);
if (!result.IsSuccess)
return NotFound();
string path = await UploadService.GetFile(result.Attachment.URI);
if (path == null)
return NotFound();
var contentType = GetContentType(result.Attachment.FileName);
if (contentType == "application/octet-stream")
return PhysicalFile(path, contentType, result.Attachment.FileName);
return PhysicalFile(path, contentType, enableRangeProcessing: true);// result.Attachment.FileName);
}
catch (Exception ex)
{
// Handle the exception here or log it
return StatusCode(500, "An error occurred: " + ex.Message);
}
//try
//{
// var result = await this.AttachmentProvider.GetDownloadAttachmentAsync(id);
// if(!result.IsSuccess)
// return NotFound();
// byte[] fileContent = await UploadService.DownloadFile(result.Attachment.URI);
// if (fileContent == null || fileContent.Length == 0)
// return NotFound();
// var contentType = "application/octet-stream";
// return File(fileContent, contentType, result.Attachment.FileName);
//}
//catch (Exception ex)
//{
// // Handle the exception here or log it
// return StatusCode(500, "An error occurred: " + ex.Message);
//}
}
private string GetContentType(string fileName)
{
// You can add more content types based on the file extensions
switch (Path.GetExtension(fileName).ToLower())
{
//case ".txt":
// return "text/plain";
case ".jpg":
case ".jpeg":
return "image/jpeg";
case ".png":
return "image/png";
case ".gif":
return "image/gif";
case ".bmp":
return "image/bmp";
case ".webp":
return "image/webp";
case ".csv":
return "text/csv";
case ".pdf":
return "application/pdf";
case ".docx":
case ".doc":
return "application/vnd.openxmlformats-officedocument.wordprocessingml.document";
case ".xlsx":
case ".xls":
return "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet";
// Add more cases as needed
default:
return "application/octet-stream";
}
}
/// <summary>
/// Delete an existing attachment.
/// </summary>
[HttpDelete("attachments/{id}")]
public async Task<IActionResult> DeleteAttachment(int id)
{
// database soft delete
var result = await this.AttachmentProvider.DeleteAttachmentAsync(id);
if (result.IsSuccess)
{
// deleting file from folder
UploadService.Movefile(result.Attachment.URI);
return Ok(result.Attachment);
}
return NotFound();
}
}
}

View File

@ -0,0 +1,20 @@
<Project Sdk="Microsoft.NET.Sdk.Web">
<PropertyGroup>
<TargetFramework>net6.0</TargetFramework>
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
<GenerateDocumentationFile>True</GenerateDocumentationFile>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="AutoMapper.Extensions.Microsoft.DependencyInjection" Version="12.0.1" />
<PackageReference Include="Azure.Storage.Blobs" Version="12.16.0" />
<PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="6.0.21" />
<PackageReference Include="Microsoft.AspNetCore.Hosting" Version="2.2.7" />
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="7.0.5" />
<PackageReference Include="Microsoft.EntityFrameworkCore.InMemory" Version="7.0.5" />
<PackageReference Include="Swashbuckle.AspNetCore" Version="6.2.3" />
</ItemGroup>
</Project>

View File

@ -0,0 +1,21 @@
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
namespace DamageAssesment.Api.Attachments.Db
{
[Table("AnswerAttachments")]
public class Attachment
{
[Key]
public int Id { get; set; }
[Required]
public string URI { get; set; }
[ForeignKey("Answer")]
public int? AnswerId { get; set; }
[ForeignKey("SurveyResponse")]
public int ResponseId { get; set; }
public bool IsDeleted { get; set; }
public string FileName { get; set; }
}
}

View File

@ -0,0 +1,19 @@
using Microsoft.EntityFrameworkCore;
namespace DamageAssesment.Api.Attachments.Db
{
public class AttachmentsDbContext:DbContext
{
public AttachmentsDbContext(DbContextOptions options) : base(options)
{
}
public DbSet<Db.Attachment> Attachments { get; set; }
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
modelBuilder.Entity<Attachment>()
.Property(item => item.Id)
.ValueGeneratedOnAdd();
}
}
}

View File

@ -0,0 +1,18 @@
using DamageAssesment.Api.Attachments.Models;
namespace DamageAssesment.Api.Attachments.Interfaces
{
public interface IAttachmentsProvider
{
Task<(bool IsSuccess, IEnumerable<Models.Attachment> Attachments, string ErrorMessage)> GetAttachmentsAsync();
Task<(bool IsSuccess, Models.Attachment Attachment, string ErrorMessage)> GetAttachmentByIdAsync(int Id);
Task<(bool IsSuccess, IEnumerable<Models.Attachment> Attachments, string ErrorMessage)> PostAttachmentAsync(List<Models.Attachment> Attachments);
Task<(bool IsSuccess, IEnumerable<Models.Attachment> Attachments, string ErrorMessage)> PutAttachmentAsync(List<Models.Attachment> Attachments);
Task<(bool IsSuccess, Models.Attachment Attachment, string Path)> DeleteAttachmentAsync(int Id);
Task<(bool IsSuccess, Models.Attachment Attachment, string Path)> GetDownloadAttachmentAsync(int Id);
Task<(bool IsSuccess, int counter, string Path)> DeleteAttachmentsAsync(int responseId, int answerId);
Task<(bool IsSuccess, int counter, string Path)> DeleteBulkAttachmentsAsync(int responseId, List<int> answerIds);
Task<(bool IsSuccess, int counter, string message)> GetAttachmentCounter();
Task<(bool IsSuccess, IEnumerable<Models.Attachment> Attachments, string ErrorMessage)> GetAttachmentInfo(List<AnswerInfo> answers);
}
}

View File

@ -0,0 +1,10 @@
using Azure.Storage.Blobs.Models;
namespace DamageAssesment.Api.Attachments.Interfaces
{
public interface IAzureBlobService
{
Task<List<Azure.Response<BlobContentInfo>>> UploadFiles(List<IFormFile> files);
void DeleteFile(string path);
}
}

View File

@ -0,0 +1,15 @@
using DamageAssesment.Api.Attachments.Models;
namespace DamageAssesment.Api.Attachments.Interfaces
{
public interface IUploadService
{
List<Models.Attachment> UploadAttachment(int responseId,int answerId, int counter, List<IFormFile> postedFile);
List<Models.Attachment> UploadAttachment(int responseId, int counter, List<AnswerInfo> answers);
public List<Models.Attachment> UpdateAttachments(int responseId, List<AnswerInfo> answers, IEnumerable<Models.Attachment> attachments);
Task<byte[]> DownloadFile(string path);
Task<string> GetFile(string path);
void Deletefile(string path);
void Movefile(string path);
}
}

View File

@ -0,0 +1,22 @@
using System.ComponentModel.DataAnnotations;
namespace DamageAssesment.Api.Attachments.Models
{
public class Attachment
{
public int Id { get; set; }
public string URI { get; set; }
public int ResponseId { get; set; }
public int? AnswerId { get; set; }
public bool IsDeleted { get; set; }
public string FileName { get; set; }
//public Attachment(int answerId, string uri)
//{
// this.AnswerId = answerId;
// this.URI = uri;
//}
}
}

View File

@ -0,0 +1,20 @@
namespace DamageAssesment.Api.Attachments.Models
{
public class AttachmentInfo
{
public int ResponseId { get; set; }
public List<AnswerInfo> Answers { get; set; }
}
public class AnswerInfo
{
public int AnswerId { get; set; }
public List<FileModel> postedFiles { get; set; }
}
public class FileModel
{
public int? AttachmentId { get; set; }
public string? FileName { get; set; }
public string? FileContent { get; set; }
public string? FileExtension { get; set; }
}
}

View File

@ -0,0 +1,11 @@
namespace DamageAssesment.Api.Attachments.Profiles
{
public class AttachmentsProfiles:AutoMapper.Profile
{
public AttachmentsProfiles()
{
CreateMap<Db.Attachment, Models.Attachment>();
CreateMap<Models.Attachment, Db.Attachment>();
}
}
}

View File

@ -0,0 +1,54 @@
using DamageAssesment.Api.Attachments.Db;
using DamageAssesment.Api.Attachments.Interfaces;
using DamageAssesment.Api.Attachments.Providers;
using Microsoft.AspNetCore.Http.Features;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.FileProviders;
using System.Reflection;
var builder = WebApplication.CreateBuilder(args);
// Add services to the container.
builder.Services.AddControllers();
// Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle
builder.Services.AddEndpointsApiExplorer();
//builder.Services.AddSwaggerGen();
builder.Services.AddSwaggerGen(c =>
{
// Include XML comments from your assembly
var xmlFile = $"{Assembly.GetExecutingAssembly().GetName().Name}.xml";
var xmlPath = Path.Combine(AppContext.BaseDirectory, xmlFile);
c.IncludeXmlComments(xmlPath);
});
builder.Services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();
builder.Services.AddScoped<IAttachmentsProvider, AttachmentsProvider>();
builder.Services.AddScoped<IUploadService, UploadService>();
builder.Services.AddScoped<IAzureBlobService,AzureBlobService>();
builder.Services.AddAutoMapper(AppDomain.CurrentDomain.GetAssemblies()); //4/30
builder.Services.AddDbContext<AttachmentsDbContext>(option =>
{
option.UseInMemoryDatabase("Attachments");
});
builder.Services.Configure<FormOptions>(o =>
{
o.ValueLengthLimit = int.MaxValue;
o.MultipartBodyLengthLimit = int.MaxValue;
o.MemoryBufferThreshold = int.MaxValue;
});
var app = builder.Build();
// Configure the HTTP request pipeline.
if (app.Environment.IsDevelopment())
{
app.UseSwagger();
app.UseSwaggerUI();
}
app.UseAuthorization();
app.UseHttpsRedirection();
app.MapControllers();
app.UseStaticFiles();
app.Run();

View File

@ -0,0 +1,31 @@
{
"$schema": "https://json.schemastore.org/launchsettings.json",
"iisSettings": {
"windowsAuthentication": false,
"anonymousAuthentication": true,
"iisExpress": {
"applicationUrl": "http://localhost:65305",
"sslPort": 0
}
},
"profiles": {
"DamageAssesment.Api.Attachments": {
"commandName": "Project",
"dotnetRunMessages": true,
"launchBrowser": true,
"launchUrl": "swagger",
"applicationUrl": "http://localhost:5243",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
},
"IIS Express": {
"commandName": "IISExpress",
"launchBrowser": true,
"launchUrl": "swagger",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
}
}
}

View File

@ -0,0 +1,255 @@
using AutoMapper;
using DamageAssesment.Api.Attachments.Db;
using DamageAssesment.Api.Attachments.Interfaces;
using DamageAssesment.Api.Attachments.Models;
using Microsoft.EntityFrameworkCore;
using System.Drawing;
namespace DamageAssesment.Api.Attachments.Providers
{
public class AttachmentsProvider : IAttachmentsProvider
{
private AttachmentsDbContext AttachmentDbContext;
private ILogger<AttachmentsProvider> logger;
private IUploadService uploadservice;
private IMapper mapper;
private readonly IHttpContextAccessor httpContextAccessor;
private string baseUrl;
public AttachmentsProvider(AttachmentsDbContext AttachmentDbContext, ILogger<AttachmentsProvider> logger, IMapper mapper,IUploadService uploadservice, IHttpContextAccessor httpContextAccessor)
{
this.AttachmentDbContext = AttachmentDbContext;
this.logger = logger;
this.mapper = mapper;
this.uploadservice = uploadservice;
this.httpContextAccessor = httpContextAccessor;
baseUrl = $"{httpContextAccessor.HttpContext.Request.Scheme}://{httpContextAccessor.HttpContext.Request.Host}";
baseUrl = baseUrl + "/attachments/download";
SeedData();
}
public async Task<(bool IsSuccess, IEnumerable<Models.Attachment> Attachments, string ErrorMessage)> GetAttachmentsAsync()
{
try
{
logger?.LogInformation("Query Question");
var Attachment = await AttachmentDbContext.Attachments.AsNoTracking().Where(a => !a.IsDeleted).ToListAsync();
if (Attachment != null)
{
foreach (var attachment in Attachment)
{
attachment.URI = $"{baseUrl}/{attachment.Id}";
}
logger?.LogInformation($"{Attachment.Count} Attachments(s) found");
var result = mapper.Map<IEnumerable<Db.Attachment>, IEnumerable<Models.Attachment>>(Attachment);
return (true, result, null);
}
return (false, null, "Not found");
}
catch (Exception ex)
{
logger?.LogError(ex.ToString());
return (false, null, ex.Message);
}
}
public async Task<(bool IsSuccess, Models.Attachment Attachment, string ErrorMessage)> GetAttachmentByIdAsync(int Id)
{
try
{
logger?.LogInformation("Query Attachment");
var Attachment = await AttachmentDbContext.Attachments.AsNoTracking().FirstOrDefaultAsync(q => q.Id == Id & !q.IsDeleted);
if (Attachment != null)
{
logger?.LogInformation($"{Attachment} customer(s) found");
Attachment.URI = $"{baseUrl}/{Attachment.Id}";
var result = mapper.Map<Db.Attachment, Models.Attachment>(Attachment);
return (true, result, null);
}
return (false, null, "Not found");
}
catch (Exception ex)
{
logger?.LogError(ex.ToString());
return (false, null, ex.Message);
}
}
public async Task<(bool IsSuccess, IEnumerable<Models.Attachment> Attachments, string ErrorMessage)> PostAttachmentAsync(List<Models.Attachment> Attachments)
{
try
{
logger?.LogInformation("Query Attachment");
List<Db.Attachment> attachments = mapper.Map<List<Models.Attachment>, List<Db.Attachment>>(Attachments);
AttachmentDbContext.Attachments.AddRange(attachments);
await AttachmentDbContext.SaveChangesAsync();
foreach (var attachment in attachments)
{
attachment.URI = $"{baseUrl}/{attachment.Id}";
}
var result = mapper.Map<IEnumerable<Db.Attachment>, IEnumerable<Models.Attachment>>(attachments);
return (true, result, null);
}
catch (Exception ex)
{
logger?.LogError(ex.ToString());
return (false, null, ex.Message);
}
}
public async Task<(bool IsSuccess, IEnumerable<Models.Attachment> Attachments, string ErrorMessage)> PutAttachmentAsync(List<Models.Attachment> Attachments)
{
try
{
logger?.LogInformation("Query Attachment");
List<Db.Attachment> attachments = mapper.Map<List<Models.Attachment>, List<Db.Attachment>>(Attachments);
AttachmentDbContext.Attachments.UpdateRange(attachments);
await AttachmentDbContext.SaveChangesAsync();
foreach (var attachment in attachments)
{
attachment.URI = $"{baseUrl}/{attachment.Id}";
}
var result = mapper.Map<IEnumerable<Db.Attachment>, IEnumerable<Models.Attachment>>(attachments);
return (true, result, null);
}
catch (Exception ex)
{
logger?.LogError(ex.ToString());
return (false, null, ex.Message);
}
}
public async Task<(bool IsSuccess, int counter, string Path)> DeleteBulkAttachmentsAsync(int responseId, List<int> answerIds)
{
int AttachmentId = 0;
try
{
AttachmentId = AttachmentDbContext.Attachments.Max(a => a.Id);
List<Db.Attachment> Attachments = AttachmentDbContext.Attachments.Where(a => a.ResponseId == responseId && answerIds.Contains(a.AnswerId ?? 0)).AsNoTracking().ToList();
if (Attachments.Count > 0)
{
AttachmentDbContext.Attachments.RemoveRange(Attachments);
await AttachmentDbContext.SaveChangesAsync();
}
return (true, AttachmentId, "");
}
catch (Exception ex)
{
logger?.LogError(ex.ToString());
return (false, AttachmentId, "");
}
}
public async Task<(bool IsSuccess,int counter,string message)> GetAttachmentCounter()
{
try
{
int AttachmentId = AttachmentDbContext.Attachments.Max(a => a.Id);
return (true, AttachmentId, "");
}
catch(Exception ex)
{
return (false, 0, ex.Message);
}
}
public async Task<(bool IsSuccess, int counter, string Path)> DeleteAttachmentsAsync(int responseId, int answerId)
{
int AttachmentId = 0;
try
{
AttachmentId = AttachmentDbContext.Attachments.Max(a => a.Id);
List<Db.Attachment> Attachments = AttachmentDbContext.Attachments.Where(a => a.ResponseId == responseId && a.AnswerId == answerId).AsNoTracking().ToList();
if (Attachments.Count > 0)
{
AttachmentDbContext.Attachments.RemoveRange(Attachments);
await AttachmentDbContext.SaveChangesAsync();
}
return (true, AttachmentId, "");
}
catch (Exception ex)
{
logger?.LogError(ex.ToString());
return (false, AttachmentId, "");
}
}
public async Task<(bool IsSuccess, IEnumerable<Models.Attachment> Attachments, string ErrorMessage)> GetAttachmentInfo(List<AnswerInfo> answers)
{
try
{
List<int> attchmentIds = new List<int>();
foreach (AnswerInfo item in answers)
{
attchmentIds.AddRange(item.postedFiles.Select(a => a.AttachmentId ?? 0).ToList());
}
var attachments= AttachmentDbContext.Attachments.AsNoTracking().Where(a=>attchmentIds.Contains(a.Id)).ToList();
var result = mapper.Map<IEnumerable<Db.Attachment>, IEnumerable<Models.Attachment>>(attachments);
return (true, result, null);
}
catch (Exception ex)
{
return (false, null, ex.Message);
}
}
public async Task<(bool IsSuccess, Models.Attachment Attachment, string Path)> DeleteAttachmentAsync(int Id)
{
try
{
Db.Attachment Attachment = AttachmentDbContext.Attachments.Where(a => a.Id == Id).AsNoTracking().FirstOrDefault();
if (Attachment == null)
{
return (false, null, "Not Found");
}
Attachment.IsDeleted = true;
AttachmentDbContext.Attachments.Update(Attachment);
await AttachmentDbContext.SaveChangesAsync();
return (true, mapper.Map<Db.Attachment, Models.Attachment>(Attachment), $"Attachment {Id} is deleted");
}
catch (Exception ex)
{
logger?.LogError(ex.ToString());
return (false, null, ex.Message);
}
}
private bool AttachmentExists(int id)
{
return AttachmentDbContext.Attachments.AsNoTracking().Count(e => e.Id == id && !e.IsDeleted) > 0;
}
public async Task<(bool IsSuccess, Models.Attachment Attachment, string Path)> GetDownloadAttachmentAsync(int Id)
{
try
{
Db.Attachment Attachment = AttachmentDbContext.Attachments.Where(a => a.Id == Id).AsNoTracking().FirstOrDefault();
if (Attachment == null)
{
return (false, null, "Not Found");
}
return (true, mapper.Map<Db.Attachment, Models.Attachment>(Attachment), $"Attachment {Id}");
}
catch (Exception ex)
{
logger?.LogError(ex.ToString());
return (false, null, ex.Message);
}
}
private void SeedData()
{
if (!AttachmentDbContext.Attachments.Any())
{
// adding sample text file in respective folder based responseid and answer id
FileModel fileModel= new FileModel(){AttachmentId=0,FileName="Sample",FileContent= "c2FtcGxl",FileExtension=".txt"};
List<AnswerInfo> answerInfos=new List<AnswerInfo>();
answerInfos.Add(new AnswerInfo(){ AnswerId = 1,postedFiles=new List<FileModel> { fileModel }});
List<Models.Attachment> attachments = uploadservice.UploadAttachment(1, 0, answerInfos);
if (attachments.Count > 0)
{
List<Db.Attachment> Attachments = mapper.Map<List<Models.Attachment>, List<Db.Attachment>>(attachments);
AttachmentDbContext.Attachments.AddRange(Attachments);
AttachmentDbContext.SaveChanges();
}
}
}
}
}

View File

@ -0,0 +1,44 @@

using Azure.Storage.Blobs;
using Azure.Storage.Blobs.Models;
using Azure.Storage.Blobs.Specialized;
using DamageAssesment.Api.Attachments.Interfaces;
namespace DamageAssesment.Api.Attachments.Providers
{
public class AzureBlobService: IAzureBlobService
{
BlobServiceClient _blobClient;
BlobContainerClient _containerClient;
string azureConnectionString = "<Primary Connection String>";
public AzureBlobService()
{
_blobClient = new BlobServiceClient(azureConnectionString);
_containerClient = _blobClient.GetBlobContainerClient("apiimages");
}
public async Task<List<Azure.Response<BlobContentInfo>>> UploadFiles(List<IFormFile> files)
{
var azureResponse = new List<Azure.Response<BlobContentInfo>>();
foreach (var file in files)
{
string fileName = file.FileName;
using (var memoryStream = new MemoryStream())
{
file.CopyTo(memoryStream);
memoryStream.Position = 0;
var client = await _containerClient.UploadBlobAsync(fileName, memoryStream, default);
azureResponse.Add(client);
}
};
return azureResponse;
}
public void DeleteFile(string url)
{
var blob = _containerClient.GetBlockBlobClient(url);
blob.DeleteIfExists();
}
}
}

View File

@ -0,0 +1,201 @@
using AutoMapper;
using Azure;
using DamageAssesment.Api.Attachments.Db;
using DamageAssesment.Api.Attachments.Interfaces;
using DamageAssesment.Api.Attachments.Models;
using Microsoft.AspNetCore.Http;
using System.Diagnostics.Metrics;
using System.Net.Http;
using System.Security.AccessControl;
using System.Security.Principal;
namespace DamageAssesment.Api.Attachments.Providers
{
public class UploadService : IUploadService
{
private ILogger<UploadService> logger;
private IMapper mapper;
private string uploadpath = "";
private string Deletepath = "";
public UploadService(IConfiguration configuration, ILogger<UploadService> logger, IMapper mapper)
{
this.logger = logger;
this.mapper = mapper;
uploadpath = configuration.GetValue<string>("Fileupload:folderpath");
Deletepath = configuration.GetValue<string>("Fileupload:Deletepath");
}
public async Task<string> GetFile(string path)
{
try
{
if (System.IO.File.Exists(path))
{
return path;
}
return null; // File not found
}
catch (Exception ex)
{
// Handle or log the exception as needed
throw;
}
}
public async Task<byte[]> DownloadFile(string path)
{
try
{
if (System.IO.File.Exists(path))
{
return await System.IO.File.ReadAllBytesAsync(path);
}
return null; // File not found
}
catch (Exception ex)
{
// Handle or log the exception as needed
throw;
}
}
public List<Models.Attachment> UploadAttachment(int responseId,int answerId,int counter, List<IFormFile> postedFile)
{
var pathToSave = Path.Combine(Directory.GetCurrentDirectory(), uploadpath);
String responseDirectory = "Response-" + responseId;
String fullDirectoryPath = Path.Combine(pathToSave, responseDirectory);
if (!Directory.Exists(fullDirectoryPath)) //Create deirectory if does not exist
Directory.CreateDirectory(fullDirectoryPath);
fullDirectoryPath = Path.Combine(fullDirectoryPath, "Answer-" + answerId);
if (!Directory.Exists(fullDirectoryPath)) //Create deirectory if does not exist
Directory.CreateDirectory(fullDirectoryPath);
String[] searchFiles = Directory.GetFiles(fullDirectoryPath); //Search for existing answer files
if (searchFiles.Length > 0)
{
foreach (String searchFile in searchFiles)
{
Deletefile(searchFile);
}
}
List<Models.Attachment> attachments = new List<Models.Attachment>();
foreach (IFormFile item in postedFile)
{
counter++;
var UserfileName = Path.GetFileName(item.FileName);
var extension = System.IO.Path.GetExtension(UserfileName);
var fileName = String.Format("Attachment_{0}{1}", counter, extension);
var dbPath = Path.Combine(fullDirectoryPath, fileName);
using (var stream = new FileStream(dbPath, FileMode.Create, FileAccess.ReadWrite))
{
item.CopyTo(stream);
}
attachments.Add(new Models.Attachment { AnswerId = answerId, ResponseId = responseId, IsDeleted = false, FileName = UserfileName, URI = dbPath });
}
return attachments;
}
public List<Models.Attachment> UploadAttachment(int responseId, int counter,List<AnswerInfo> answers)
{
List<Models.Attachment> attachments = new List<Models.Attachment>();
try
{
foreach (var item in answers)
{
int answerId = item.AnswerId;
var pathToSave = Path.Combine(Directory.GetCurrentDirectory(), uploadpath);
String responseDirectory = "Response-" + responseId;
String fullDirectoryPath = Path.Combine(pathToSave, responseDirectory);
if (!Directory.Exists(fullDirectoryPath)) //Create deirectory if does not exist
Directory.CreateDirectory(fullDirectoryPath);
fullDirectoryPath = Path.Combine(fullDirectoryPath, "Answer-" + answerId);
if (!Directory.Exists(fullDirectoryPath)) //Create deirectory if does not exist
Directory.CreateDirectory(fullDirectoryPath);
//String[] searchFiles = Directory.GetFiles(fullDirectoryPath); //Search for existing answer files
//if (searchFiles.Length > 0)
//{
// foreach (String searchFile in searchFiles)
// {
// Deletefile(searchFile);
// }
//}
foreach (var file in item.postedFiles)
{
counter++;
var UserfileName = Path.GetFileName(file.FileName+ file.FileExtension);
var fileName = String.Format("Attachment_{0}{1}", counter, file.FileExtension);
var dbPath = Path.Combine(fullDirectoryPath, fileName);
File.WriteAllBytes(dbPath, Convert.FromBase64String(file.FileContent));
attachments.Add(new Models.Attachment { AnswerId = answerId, ResponseId = responseId, IsDeleted = false, FileName = UserfileName, URI = dbPath });
}
}
return attachments;
}
catch (Exception ex) {
return new List<Models.Attachment>();
}
}
public List<Models.Attachment> UpdateAttachments(int responseId,List<AnswerInfo> answers,IEnumerable<Models.Attachment> attachments)
{
List<Models.Attachment> Dbattachments = new List<Models.Attachment>();
foreach (Models.Attachment searchFile in attachments)
{
Deletefile(searchFile.URI);
}
foreach (var item in answers)
{
int answerId = item.AnswerId;
var pathToSave = Path.Combine(Directory.GetCurrentDirectory(), uploadpath);
String responseDirectory = "Response-" + responseId;
String fullDirectoryPath = Path.Combine(pathToSave, responseDirectory);
if (!Directory.Exists(fullDirectoryPath)) //Create deirectory if does not exist
Directory.CreateDirectory(fullDirectoryPath);
fullDirectoryPath = Path.Combine(fullDirectoryPath, "Answer-" + answerId);
if (!Directory.Exists(fullDirectoryPath)) //Create deirectory if does not exist
Directory.CreateDirectory(fullDirectoryPath);
foreach (var file in item.postedFiles)
{
Models.Attachment attachment= attachments.Where(a=>a.Id == file.AttachmentId).FirstOrDefault();
var UserfileName = Path.GetFileName(file.FileName + file.FileExtension);
var fileName = String.Format("Attachment_{0}{1}", attachment?.Id, file.FileExtension);
var dbPath = Path.Combine(fullDirectoryPath, fileName);
File.WriteAllBytes(dbPath, Convert.FromBase64String(file.FileContent));
Dbattachments.Add(new Models.Attachment { Id=attachment.Id, AnswerId = answerId, ResponseId = responseId, IsDeleted = false, FileName = UserfileName, URI = dbPath });
}
}
return Dbattachments;
}
public void Deletefile(string path)
{
if (path != "")
{
FileInfo file = new FileInfo(path);
if (file?.Exists??false)//check file exsit or not
{
file.Delete();
}
}
}
public void Movefile(string path)
{
if (path != "")
{
var pathToSave = Path.Combine(Directory.GetCurrentDirectory(), Deletepath);
if (!Directory.Exists(pathToSave)) //Create deirectory if does not exist
Directory.CreateDirectory(pathToSave);
FileInfo file = new FileInfo(path);
if (file?.Exists ?? false)//check file exsit or not
{
string filename = file.Name.Replace(file.Extension, " ") + DateTime.Now.ToShortDateString().Replace("/","_") + file.Extension;
file.MoveTo(pathToSave+"\\"+ filename);
}
}
}
}
}

View File

@ -0,0 +1,365 @@
## 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
/IMS.Identity/Migrations/20220706155644_addmultifactortable.cs
/IMS.Identity/Migrations/20220706155644_addmultifactortable.Designer.cs

View File

@ -0,0 +1,16 @@
{
"JwtSettings": {
"securitykey": "bWlhbWkgZGFkZSBzY2hvb2xzIHNlY3JldCBrZXk="
},
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft.AspNetCore": "Warning"
}
},
"AllowedHosts": "*",
"Fileupload": {
"folderpath": "DMS_Attachments/Active",
"Deletepath": "DMS_Attachments/Deleted"
}
}

View File

@ -0,0 +1,27 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net6.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<IsPackable>false</IsPackable>
<IsTestProject>true</IsTestProject>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.5.0" />
<PackageReference Include="Moq" Version="4.18.4" />
<PackageReference Include="coverlet.collector" Version="3.2.0" />
<PackageReference Include="xunit" Version="2.4.2" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.5">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\DamageAssesment.Api.DocuLinks\DamageAssesment.Api.DocuLinks.csproj" />
</ItemGroup>
</Project>

View File

@ -0,0 +1,27 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net6.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<IsPackable>false</IsPackable>
<IsTestProject>true</IsTestProject>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.5.0" />
<PackageReference Include="Moq" Version="4.18.4" />
<PackageReference Include="coverlet.collector" Version="3.2.0" />
<PackageReference Include="xunit" Version="2.4.2" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.5">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\DamageAssesment.Api.DocuLinks\DamageAssesment.Api.DocuLinks.csproj" />
</ItemGroup>
</Project>

View File

@ -0,0 +1,378 @@
using DamageAssesment.Api.DocuLinks.Controllers;
using DamageAssesment.Api.DocuLinks.Interfaces;
using DamageAssesment.Api.DocuLinks.Models;
using Microsoft.AspNetCore.Mvc;
using Moq;
using Xunit;
namespace DamageAssesment.Api.DocuLinks.Test
{
public class DocumentServiceTest
{
[Fact(DisplayName = "Get Documents - NoContent Case")]
public async Task GetDocumentsLanguageAsync_ShouldReturnStatusCode204()
{
var mockDocumentService = new Mock<IDoculinkProvider>();
var mockUploadService = new Mock<IUploadService>();
var mockResponse = await MockData.getNoContentResponse();
mockDocumentService.Setup(service => service.GetdocumentsByLinkAsync("forms","en",null)).ReturnsAsync(mockResponse);
var DocumentProvider = new DoculinkController(mockDocumentService.Object, mockUploadService.Object);
var result = (NoContentResult)await DocumentProvider.GetDocumentsAsync("", "", null);
Assert.Equal(204, result.StatusCode);
}
[Fact(DisplayName = "Get active Documents - NoContent Case")]
public async Task GetDocumentsLinkTypeAsync_ShouldReturnStatusCode204()
{
var mockDocumentService = new Mock<IDoculinkProvider>();
var mockUploadService = new Mock<IUploadService>();
var mockResponse = await MockData.getNoContentResponse();
mockDocumentService.Setup(service => service.GetdocumentsByLinkAsync("forms", "en", true)).ReturnsAsync(mockResponse);
var DocumentProvider = new DoculinkController(mockDocumentService.Object, mockUploadService.Object);
var result = (NoContentResult)await DocumentProvider.GetDocumentsByActiveAsync("", "");
Assert.Equal(204, result.StatusCode);
}
[Fact(DisplayName = "Get Documents - Ok case")]
public async Task GetDocumentsAsync_ShouldReturnStatusCode200()
{
var mockDocumentService = new Mock<IDoculinkProvider>();
var mockUploadService = new Mock<IUploadService>();
var mockResponse = await MockData.getOkResponses();
mockDocumentService.Setup(service => service.GetdocumentsByLinkAsync("forms","en", null)).ReturnsAsync(mockResponse);
var DocumentProvider = new DoculinkController(mockDocumentService.Object, mockUploadService.Object);
var result = (OkObjectResult)await DocumentProvider.GetDocumentsAsync("forms","en", null);
Assert.Equal(200, result.StatusCode);
}
[Fact(DisplayName = "Get active Documents - Ok case")]
public async Task GetActiveDocumentsAsync_ShouldReturnStatusCode200()
{
var mockDocumentService = new Mock<IDoculinkProvider>();
var mockUploadService = new Mock<IUploadService>();
var mockResponse = await MockData.getOkResponses();
mockDocumentService.Setup(service => service.GetdocumentsByLinkAsync("forms", "en", true)).ReturnsAsync(mockResponse);
var DocumentProvider = new DoculinkController(mockDocumentService.Object, mockUploadService.Object);
var result = (OkObjectResult)await DocumentProvider.GetDocumentsByActiveAsync("forms", "en");
Assert.Equal(200, result.StatusCode);
}
[Fact(DisplayName = "Get active Documents by linktypeid - Ok case")]
public async Task GetActiveDocumentsLinkTypeIdAsync_ShouldReturnStatusCode200()
{
var mockDocumentService = new Mock<IDoculinkProvider>();
var mockUploadService = new Mock<IUploadService>();
var mockResponse = await MockData.getOkResponses();
mockDocumentService.Setup(service => service.GetdocumentsByLinkTypeIdAsync(null, "en", true)).ReturnsAsync(mockResponse);
var DocumentProvider = new DoculinkController(mockDocumentService.Object, mockUploadService.Object);
var result = (OkObjectResult)await DocumentProvider.GetDocumentsByActiveLinkTypeIdAsync(null, "en");
Assert.Equal(200, result.StatusCode);
}
[Fact(DisplayName = "Get active Documents by linktypeid - NoContent Case")]
public async Task GetDocumentsLinkTypeIdAsync_ShouldReturnStatusCode204()
{
var mockDocumentService = new Mock<IDoculinkProvider>();
var mockUploadService = new Mock<IUploadService>();
var mockResponse = await MockData.getNoContentResponse();
mockDocumentService.Setup(service => service.GetdocumentsByLinkTypeIdAsync(null, "en", true)).ReturnsAsync(mockResponse);
var DocumentProvider = new DoculinkController(mockDocumentService.Object, mockUploadService.Object);
var result = (NoContentResult)await DocumentProvider.GetDocumentsByActiveLinkTypeIdAsync(null, "");
Assert.Equal(204, result.StatusCode);
}
[Fact(DisplayName = "Get Document by Id - Ok case")]
public async Task GetDocumentAsync_ShouldReturnStatusCode200()
{
var mockDocumentService = new Mock<IDoculinkProvider>();
var mockUploadService = new Mock<IUploadService>();
var mockResponse = await MockData.getOkResponse(1);
mockDocumentService.Setup(service => service.GetDocumentAsync(1,"forms","en")).ReturnsAsync(mockResponse);
var DocumentProvider = new DoculinkController(mockDocumentService.Object, mockUploadService.Object);
var result = (OkObjectResult)await DocumentProvider.GetDocumentAsync(1, "forms", "en");
Assert.Equal(200, result.StatusCode);
}
[Fact(DisplayName = "Get Document by Id - NotFound case")]
public async Task GetDocumentAsync_ShouldReturnStatusCode404()
{
var mockDocumentService = new Mock<IDoculinkProvider>();
var mockUploadService = new Mock<IUploadService>();
var mockResponse = await MockData.getNotFoundResponse();
mockDocumentService.Setup(service => service.GetDocumentAsync(99, "forms", "en")).ReturnsAsync(mockResponse);
var DocumentProvider = new DoculinkController(mockDocumentService.Object, mockUploadService.Object);
var result = (NotFoundResult)await DocumentProvider.GetDocumentAsync(99, "forms", "en");
Assert.Equal(404, result.StatusCode);
}
[Fact(DisplayName = "Post Document - Ok case")]
public async Task PostDocumentAsync_ShouldReturnStatusCode200()
{
var mockDocumentService = new Mock<IDoculinkProvider>();
var mockUploadService = new Mock<IUploadService>();
var mockResponse = await MockData.getOkResponse(1);
var mockInputDocument = await MockData.getInputDocumentData();
var DocumentResponse = await MockData.GetDocuLinksInfo(0);
mockDocumentService.Setup(service => service.PostDocumentAsync(mockInputDocument)).ReturnsAsync(mockResponse);
var DocumentProvider = new DoculinkController(mockDocumentService.Object, mockUploadService.Object);
var result = (NoContentResult)await DocumentProvider.CreateDocument(DocumentResponse);
Assert.Equal(204, result.StatusCode);
}
[Fact(DisplayName = "Post Document - BadRequest case")]
public async Task PostDocumentAsync_ShouldReturnStatusCode400()
{
var mockDocumentService = new Mock<IDoculinkProvider>();
var mockUploadService = new Mock<IUploadService>();
var mockInputDocument = await MockData.getInputDocumentData();
var mockResponse = await MockData.getBadRequestResponse();
ReqDoculink documentInfo = null;
mockDocumentService.Setup(service => service.PostDocumentAsync(mockInputDocument)).ReturnsAsync(mockResponse);
var DocumentProvider = new DoculinkController(mockDocumentService.Object, mockUploadService.Object);
var result = (BadRequestObjectResult)await DocumentProvider.CreateDocument(documentInfo);
Assert.Equal(400, result.StatusCode);
}
[Fact(DisplayName = "Put Document - Ok case")]
public async Task PutDocumentAsync_ShouldReturnStatusCode200()
{
var mockDocumentService = new Mock<IDoculinkProvider>();
var mockUploadService = new Mock<IUploadService>();
var mockResponse = await MockData.getOkResponse(1);
var mockInputDocument = await MockData.getInputDocumentData();
var DocumentResponse = await MockData.GetDocuLinksInfo(1);
mockDocumentService.Setup(service => service.UpdateDocumentAsync(1,mockInputDocument)).ReturnsAsync(mockResponse);
var DocumentProvider = new DoculinkController(mockDocumentService.Object, mockUploadService.Object);
var result = (NotFoundResult)await DocumentProvider.UpdateDocument(1,DocumentResponse);
Assert.Equal(404, result.StatusCode);
}
[Fact(DisplayName = "Put Document - BadRequest case")]
public async Task PutDocumentAsync_ShouldReturnStatusCode400()
{
var mockDocumentService = new Mock<IDoculinkProvider>();
var mockUploadService = new Mock<IUploadService>();
var mockResponse = await MockData.getBadRequestResponse();
var mockInputDocument = await MockData.getInputDocumentData();
mockDocumentService.Setup(service => service.UpdateDocumentAsync(99,mockInputDocument)).ReturnsAsync(mockResponse);
var DocumentProvider = new DoculinkController(mockDocumentService.Object, mockUploadService.Object);
var result = (BadRequestObjectResult)await DocumentProvider.UpdateDocument(99,null);
Assert.Equal(400, result.StatusCode);
}
[Fact(DisplayName = "Delete Document - Ok case")]
public async Task DeleteDocumentAsync_ShouldReturnStatusCode200()
{
var mockDocumentService = new Mock<IDoculinkProvider>();
var mockUploadService = new Mock<IUploadService>();
var mockResponse = await MockData.getOkResponse(1);
mockDocumentService.Setup(service => service.DeleteDocumentAsync(1)).ReturnsAsync(mockResponse);
var DocumentProvider = new DoculinkController(mockDocumentService.Object, mockUploadService.Object);
var result = (OkObjectResult)await DocumentProvider.DeleteDocument(1);
Assert.Equal(200, result.StatusCode);
}
[Fact(DisplayName = "Delete Document - NotFound case")]
public async Task DeleteDocumentAsync_ShouldReturnStatusCode404()
{
var mockDocumentService = new Mock<IDoculinkProvider>();
var mockUploadService = new Mock<IUploadService>();
var mockResponse = await MockData.getNotFoundResponse();
mockDocumentService.Setup(service => service.DeleteDocumentAsync(1)).ReturnsAsync(mockResponse);
var DocumentProvider = new DoculinkController(mockDocumentService.Object, mockUploadService.Object);
var result = (NotFoundResult)await DocumentProvider.DeleteDocument(1);
Assert.Equal(404, result.StatusCode);
}
[Fact(DisplayName = "Update Document IsActive- Ok case")]
public async Task UpdateDocumentAsync_ShouldReturnStatusCode200()
{
var mockDocumentService = new Mock<IDoculinkProvider>();
var mockUploadService = new Mock<IUploadService>();
var mockResponse = await MockData.getOkResponse(1);
mockDocumentService.Setup(service => service.UpdateDocumentAsync(1,true)).ReturnsAsync(mockResponse);
var DocumentProvider = new DoculinkController(mockDocumentService.Object, mockUploadService.Object);
var result = (OkObjectResult)await DocumentProvider.UpdateIsActiveDocument(1,true);
Assert.Equal(200, result.StatusCode);
}
[Fact(DisplayName = "Update Document IsActive - NotFound case")]
public async Task UpdateDocumentAsync_ShouldReturnStatusCode404()
{
var mockDocumentService = new Mock<IDoculinkProvider>();
var mockUploadService = new Mock<IUploadService>();
var mockResponse = await MockData.getNotFoundResponse();
mockDocumentService.Setup(service => service.UpdateDocumentAsync(1,true)).ReturnsAsync(mockResponse);
var DocumentProvider = new DoculinkController(mockDocumentService.Object, mockUploadService.Object);
var result = (NotFoundResult)await DocumentProvider.UpdateIsActiveDocument(1,true);
Assert.Equal(404, result.StatusCode);
}
// Link Type Test cases
[Fact(DisplayName = "Get Link types - Ok case")]
public async Task GetDocumentCategoriesAsync_ShouldReturnStatusCode200()
{
var mockDocumentService = new Mock<IDoculinkProvider>();
var mockUploadService = new Mock<IUploadService>();
var mockResponse = await LinkTypeMockData.getOkResponse();
mockDocumentService.Setup(service => service.GetLinkTypesAsync("en")).ReturnsAsync(mockResponse);
var DocumentProvider = new DoculinkController(mockDocumentService.Object, mockUploadService.Object);
var result = (OkObjectResult)await DocumentProvider.GetLinkTypesAsync("en");
Assert.Equal(200, result.StatusCode);
}
[Fact(DisplayName = "Get Link types - NoContent Case")]
public async Task GetDocumentCategoriesAsync_ShouldReturnStatusCode204()
{
var mockDocumentService = new Mock<IDoculinkProvider>();
var mockUploadService = new Mock<IUploadService>();
var mockResponse = await LinkTypeMockData.getNoContentResponse();
mockDocumentService.Setup(service => service.GetLinkTypesAsync("en")).ReturnsAsync(mockResponse);
var DocumentProvider = new DoculinkController(mockDocumentService.Object, mockUploadService.Object);
var result = (NoContentResult)await DocumentProvider.GetLinkTypesAsync("en");
Assert.Equal(204, result.StatusCode);
}
[Fact(DisplayName = "Get Link Type by Id - Ok case")]
public async Task GetDocumentcategoryAsync_ShouldReturnStatusCode200()
{
var mockDocumentService = new Mock<IDoculinkProvider>();
var mockUploadService = new Mock<IUploadService>();
var mockResponse = await LinkTypeMockData.getOkResponse(1);
mockDocumentService.Setup(service => service.GetLinkTypeAsync(1,"en")).ReturnsAsync(mockResponse);
var DocumentProvider = new DoculinkController(mockDocumentService.Object, mockUploadService.Object);
var result = (OkObjectResult)await DocumentProvider.GetLinkTypeAsync(1, "en");
Assert.Equal(200, result.StatusCode);
}
[Fact(DisplayName = "Get Link Type by Id - NotFound case")]
public async Task GetDocumentcategoryAsync_ShouldReturnStatusCode404()
{
var mockDocumentService = new Mock<IDoculinkProvider>();
var mockUploadService = new Mock<IUploadService>();
var mockResponse = await LinkTypeMockData.getNotFoundResponse();
mockDocumentService.Setup(service => service.GetLinkTypeAsync(99, "en")).ReturnsAsync(mockResponse);
var DocumentProvider = new DoculinkController(mockDocumentService.Object, mockUploadService.Object);
var result = (NotFoundResult)await DocumentProvider.GetLinkTypeAsync(99, "en");
Assert.Equal(404, result.StatusCode);
}
[Fact(DisplayName = "Post Link Type - Ok case")]
public async Task PostDocumentcategoryAsync_ShouldReturnStatusCode200()
{
var mockDocumentService = new Mock<IDoculinkProvider>();
var mockUploadService = new Mock<IUploadService>();
var mockResponse = await LinkTypeMockData.getOkResponse(1);
var mockInputDocument = await LinkTypeMockData.getInputLinkData(0);
mockDocumentService.Setup(service => service.PostLinkTypeAsync(mockInputDocument)).ReturnsAsync(mockResponse);
var DocumentProvider = new DoculinkController(mockDocumentService.Object, mockUploadService.Object);
var result = (OkObjectResult)await DocumentProvider.CreateLinkType(mockInputDocument);
Assert.Equal(200, result.StatusCode);
}
[Fact(DisplayName = "Post Link Type - BadRequest case")]
public async Task PostDocumentcategoryAsync_ShouldReturnStatusCode400()
{
var mockDocumentService = new Mock<IDoculinkProvider>();
var mockUploadService = new Mock<IUploadService>();
var mockInputDocument = await LinkTypeMockData.getInputLinkData(99);
var mockResponse = await LinkTypeMockData.getBadRequestResponse();
mockDocumentService.Setup(service => service.PostLinkTypeAsync(mockInputDocument)).ReturnsAsync(mockResponse);
var DocumentProvider = new DoculinkController(mockDocumentService.Object, mockUploadService.Object);
var result = (BadRequestObjectResult)await DocumentProvider.CreateLinkType(mockInputDocument);
Assert.Equal(400, result.StatusCode);
}
[Fact(DisplayName = "Put Document - Ok case")]
public async Task PutDocumentcategoryAsync_ShouldReturnStatusCode200()
{
var mockDocumentService = new Mock<IDoculinkProvider>();
var mockUploadService = new Mock<IUploadService>();
var mockResponse = await LinkTypeMockData.getOkResponse(1);
var mockInputDocument = await LinkTypeMockData.getInputLinkData(1);
mockDocumentService.Setup(service => service.UpdateLinkTypeAsync(1,mockInputDocument)).ReturnsAsync(mockResponse);
var DocumentProvider = new DoculinkController(mockDocumentService.Object, mockUploadService.Object);
var result = (OkObjectResult)await DocumentProvider.UpdateLinkType(1,mockInputDocument);
Assert.Equal(200, result.StatusCode);
}
[Fact(DisplayName = "Put Document - NotFound case")]
public async Task PutDocumentcategoryAsync_ShouldReturnStatusCode404()
{
var mockDocumentService = new Mock<IDoculinkProvider>();
var mockUploadService = new Mock<IUploadService>();
var mockResponse = await LinkTypeMockData.getNotFoundResponse();
var mockInputDocument = await LinkTypeMockData.getInputLinkData(99);
mockDocumentService.Setup(service => service.UpdateLinkTypeAsync(99,mockInputDocument)).ReturnsAsync(mockResponse);
var DocumentProvider = new DoculinkController(mockDocumentService.Object, mockUploadService.Object);
var result = (NotFoundObjectResult)await DocumentProvider.UpdateLinkType(99,mockInputDocument);
Assert.Equal(404, result.StatusCode);
}
[Fact(DisplayName = "Put Document - BadRequest case")]
public async Task PutDocumentcategoryAsync_ShouldReturnStatusCode400()
{
var mockDocumentService = new Mock<IDoculinkProvider>();
var mockUploadService = new Mock<IUploadService>();
var mockResponse = await LinkTypeMockData.getBadRequestResponse();
var mockInputDocument = await LinkTypeMockData.getInputLinkData(1);
mockDocumentService.Setup(service => service.UpdateLinkTypeAsync(1,mockInputDocument)).ReturnsAsync(mockResponse);
var DocumentProvider = new DoculinkController(mockDocumentService.Object, mockUploadService.Object);
var result = (BadRequestObjectResult)await DocumentProvider.UpdateLinkType(1, mockInputDocument);
Assert.Equal(400, result.StatusCode);
}
[Fact(DisplayName = "Delete Document - Ok case")]
public async Task DeleteDocumentcategoryAsync_ShouldReturnStatusCode200()
{
var mockDocumentService = new Mock<IDoculinkProvider>();
var mockUploadService = new Mock<IUploadService>();
var mockResponse = await LinkTypeMockData.getOkResponse(1);
mockDocumentService.Setup(service => service.DeleteLinkTypeAsync(1)).ReturnsAsync(mockResponse);
var DocumentProvider = new DoculinkController(mockDocumentService.Object, mockUploadService.Object);
var result = (OkObjectResult)await DocumentProvider.DeleteLinkType(1);
Assert.Equal(200, result.StatusCode);
}
[Fact(DisplayName = "Delete Document - NotFound case")]
public async Task DeleteDocumentcategoryAsync_ShouldReturnStatusCode404()
{
var mockDocumentService = new Mock<IDoculinkProvider>();
var mockUploadService = new Mock<IUploadService>();
var mockResponse = await LinkTypeMockData.getNotFoundResponse();
mockDocumentService.Setup(service => service.DeleteLinkTypeAsync(1)).ReturnsAsync(mockResponse);
var DocumentProvider = new DoculinkController(mockDocumentService.Object, mockUploadService.Object);
var result = (NotFoundResult)await DocumentProvider.DeleteLinkType(99);
Assert.Equal(404, result.StatusCode);
}
}
}

View File

@ -0,0 +1,71 @@
using DamageAssesment.Api.DocuLinks.Db;
using DamageAssesment.Api.DocuLinks.Models;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Mail;
using System.Text;
using System.Threading.Tasks;
namespace DamageAssesment.Api.DocuLinks.Test
{
public class LinkTypeMockData
{
public static async Task<(bool, List<DocuLinks.Models.ResLinkType>, string)> getOkResponse()
{
List<DocuLinks.Models.ResLinkType> list = new List<DocuLinks.Models.ResLinkType>();
Dictionary<string, string> dictdesc = new Dictionary<string, string>();
dictdesc.Add("en", "test"); dictdesc.Add("fr", "tester");
for (int i = 1; i < 4; i++)
{
list.Add(new DocuLinks.Models.ResLinkType()
{
Id = i,
titles= dictdesc,
CustomOrder=i,
IsActive = true
});
}
return (true, list, null);
}
public static async Task<(bool, DocuLinks.Models.ResLinkType, string)> getOkResponse(int Id)
{
var DocuLinks = await getOkResponse();
var Document = DocuLinks.Item2.FirstOrDefault(s => s.Id == Id);
return (true, Document, null);
}
public static async Task<(bool, DocuLinks.Models.ResLinkType, string)> getBadRequestResponse()
{
return (false, null, "Bad Request");
}
public static async Task<(bool, DocuLinks.Models.ResLinkType, string)> getNotFoundResponse()
{
return (false, null, "Not Found");
}
public static async Task<(bool, IEnumerable<DocuLinks.Models.ResLinkType>, string)> getNoContentResponse()
{
IEnumerable<DocuLinks.Models.ResLinkType> list = new List<DocuLinks.Models.ResLinkType>();
return (false, list, null);
}
public static async Task<DocuLinks.Models.LinkType> getInputLinkData(int id)
{
List<Models.LinksTranslation> DocuLinksTranslations = new List<Models.LinksTranslation>();
DocuLinksTranslations.Add(new Models.LinksTranslation()
{
Language = "en",
TypeText = "tel"
});
return new Models.LinkType
{
Id = id,
linksTranslations = DocuLinksTranslations,
CustomOrder=1,
IsActive = true
};
}
}
}

View File

@ -0,0 +1,188 @@
using DamageAssesment.Api.DocuLinks.Models;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Mail;
using System.Text;
using System.Threading.Tasks;
namespace DamageAssesment.Api.DocuLinks.Test
{
public class MockData
{
public static async Task<(bool, List<DocuLinks.Models.ResDoculink>, string)> getOkResponses()
{
List<DocuLinks.Models.ResDoculink> list = new List<DocuLinks.Models.ResDoculink>();
for (int i = 1; i < 4; i++)
{
Dictionary<string, string> dicttitle = new Dictionary<string, string>();
Dictionary<string, string> dictdesc = new Dictionary<string, string>();
dicttitle.Add("en", "test"); dicttitle.Add("fr", "tester");
dictdesc.Add("en", "test"); dictdesc.Add("fr", "tester");
List<DoculinkTranslation> DocuLinksTranslations = new List<DoculinkTranslation>();
DocuLinksTranslations.Add(new DoculinkTranslation()
{
Language = "en",
title = "tel"+i,
description = "Sample"+i
});
List<DoculinkAttachments> doclinksAttachments = new List<DoculinkAttachments>();
doclinksAttachments.Add(new DoculinkAttachments()
{
docName = "",Path="www.google.com",
Language = "en",
IsAttachments =false,CustomOrder=1
});
list.Add(new DocuLinks.Models.ResDoculink()
{
Id = i,
linkTypeId = i,
IsActive = true,
titles= dicttitle,
description=dictdesc,
CustomOrder=i,
doclinksAttachments= doclinksAttachments
});
}
// List<ResDoculinks> doculinks = list.GroupBy(a => a.linkTypeId).Select(a => new ResDoculinks() { linkTypeId = a.Key, doculinks = a.ToList() }).ToList();
return (true, list, null);
}
public static async Task<(bool, List<DocuLinks.Models.ResDoculink>, string)> getOkResponse()
{
List<DocuLinks.Models.ResDoculink> list = new List<DocuLinks.Models.ResDoculink>();
for (int i = 1; i < 4; i++)
{
Dictionary<string, string> dicttitle = new Dictionary<string, string>();
Dictionary<string, string> dictdesc = new Dictionary<string, string>();
dicttitle.Add("en", "test"); dicttitle.Add("fr", "tester");
dictdesc.Add("en", "test"); dictdesc.Add("fr", "tester");
List<DoculinkTranslation> DocuLinksTranslations = new List<DoculinkTranslation>();
DocuLinksTranslations.Add(new DoculinkTranslation()
{
Language = "en",
title = "tel" + i,
description = "Sample" + i
});
List<DoculinkAttachments> doclinksAttachments = new List<DoculinkAttachments>();
doclinksAttachments.Add(new DoculinkAttachments()
{
docName = "",
Path = "www.google.com",
IsAttachments = false,
Language = "en",
CustomOrder = 1
});
list.Add(new DocuLinks.Models.ResDoculink()
{
Id = i,
linkTypeId = i,
IsActive = true,
titles = dicttitle,
description = dictdesc,
CustomOrder = i,
doclinksAttachments = doclinksAttachments
});
}
return (true, list, null);
}
public static async Task<(bool, DocuLinks.Models.ResDoculink, string)> getOkResponse(int Id)
{
var DocuLinks = await getOkResponse();
var Document = DocuLinks.Item2.FirstOrDefault(s => s.Id == Id);
return (true, Document, null);
}
public static async Task<(bool, DocuLinks.Models.ResDoculink, string)> getBadRequestResponse()
{
return (false, null, "Bad Request");
}
public static async Task<(bool, DocuLinks.Models.ResDoculink, string)> getNotFoundResponse()
{
return (false, null, "Not Found");
}
public static async Task<(bool, IEnumerable<DocuLinks.Models.ResDoculinks>, string)> getNoContentResponses()
{
IEnumerable<DocuLinks.Models.ResDoculinks> list = new List<DocuLinks.Models.ResDoculinks>();
return (false, list, null);
}
public static async Task<(bool, IEnumerable<DocuLinks.Models.ResDoculink>, string)> getNoContentResponse()
{
IEnumerable<DocuLinks.Models.ResDoculink> list = new List<DocuLinks.Models.ResDoculink>();
return (false, list, null);
}
public static async Task<DocuLinks.Models.ReqDoculink> GetDocuLinksInfo(int id)
{
List<FileModel> fileModels = new List<FileModel>();
fileModels.Add( new FileModel() { FileName = "Sample", FileContent = "c2FtcGxl", FileExtension = ".txt",IsAttachments=true,CustomOrder=1 });
return new ReqDoculink() { Id=id, linkTypeId = 1, CustomOrder = 1, Files = fileModels };
}
public static async Task<DocuLinks.Models.Doculink> getInputDocumentData()
{
List<DoculinkTranslation> DocuLinksTranslations = new List<DoculinkTranslation>();
DocuLinksTranslations.Add(new DoculinkTranslation()
{
Language = "en",
title = "tel",
description = "Sample"
});
List<DoculinkAttachments> doclinksAttachments = new List<DoculinkAttachments>();
doclinksAttachments.Add(new DoculinkAttachments()
{
docName = "",
Path = "www.google.com",
IsAttachments = false,
Language = "en",
CustomOrder = 1
});
return new Models.Doculink
{
Id = 1,
linkTypeId = 1,
IsActive = true,
CustomOrder=1,
documentsTranslations = DocuLinksTranslations,
doclinksAttachments= doclinksAttachments
};
}
public static async Task<List<DocuLinks.Models.Doculink>> getInputDocuLinksData()
{
List<DoculinkTranslation> DocuLinksTranslations = new List<DoculinkTranslation>();
DocuLinksTranslations.Add(new DoculinkTranslation()
{
Language = "en",
title = "tel",
description = "Sample"
});
List<DoculinkAttachments> doclinksAttachments = new List<DoculinkAttachments>();
doclinksAttachments.Add(new DoculinkAttachments()
{
docName = "",
Path = "www.google.com",
IsAttachments = false,
Language = "en",
CustomOrder = 1
});
List<DocuLinks.Models.Doculink> DocuLinks = new List<Models.Doculink>();
DocuLinks.Add(new Models.Doculink
{
Id = 1,
linkTypeId = 1,
IsActive = true,
CustomOrder = 1,
documentsTranslations = DocuLinksTranslations,
doclinksAttachments = doclinksAttachments
});
return DocuLinks;
}
}
}

View File

@ -0,0 +1,332 @@
using DamageAssesment.Api.DocuLinks.Db;
using DamageAssesment.Api.DocuLinks.Interfaces;
using DamageAssesment.Api.DocuLinks.Models;
using DamageAssesment.Api.DocuLinks.Providers;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
namespace DamageAssesment.Api.DocuLinks.Controllers
{
[ApiController]
public class DoculinkController : ControllerBase
{
private readonly IDoculinkProvider documentsProvider;
private readonly IUploadService uploadService;
public DoculinkController(IDoculinkProvider documentsProvider, IUploadService uploadService)
{
this.documentsProvider = documentsProvider;
this.uploadService = uploadService;
}
/// <summary>
/// Get all Doculink type.
/// </summary>
[HttpGet]
[Route("doculinks/types")]
[Route("doculinks/types/{language:alpha}")]
public async Task<IActionResult> GetLinkTypesAsync(string? language)
{
var result = await this.documentsProvider.GetLinkTypesAsync(language);
if (result.IsSuccess)
{
return Ok(result.LinkTypes);
}
return NoContent();
}
/// <summary>
/// Get a Doculink type by id.
/// </summary>
[HttpGet]
[Route("doculinks/types/{id}")]
[Route("doculinks/types/{id}/{language:alpha}")]
public async Task<IActionResult> GetLinkTypeAsync(int id, string? language)
{
var result = await this.documentsProvider.GetLinkTypeAsync(id, language);
if (result.IsSuccess)
{
return Ok(result.LinkType);
}
return NotFound();
}
/// <summary>
/// Update a existing Doculink type.
/// </summary>
[HttpPut]
[Route("doculinks/types/{id}")]
public async Task<IActionResult> UpdateLinkType(int id, Models.LinkType linkType)
{
if (linkType != null)
{
var result = await this.documentsProvider.UpdateLinkTypeAsync(id, linkType);
if (result.IsSuccess)
{
return Ok(result.LinkType);
}
if (result.ErrorMessage == "Not Found")
return NotFound(result.ErrorMessage);
return BadRequest(result.ErrorMessage);
}
return CreatedAtRoute("DefaultApi", new { id = linkType.Id }, linkType);
}
/// <summary>
/// Create a new Doculink type.
/// </summary>
[HttpPost]
[Route("doculinks/types")]
public async Task<IActionResult> CreateLinkType(Models.LinkType linkType)
{
if (linkType != null)
{
var result = await this.documentsProvider.PostLinkTypeAsync(linkType);
if (result.IsSuccess)
{
return Ok(result.LinkType);
}
return BadRequest(result.ErrorMessage);
}
return CreatedAtRoute("DefaultApi", new { id = linkType.Id }, linkType);
}
/// <summary>
/// Delete a existing Doculink type by id.
/// </summary>
[HttpDelete]
[Route("doculinks/types/{id}")]
public async Task<IActionResult> DeleteLinkType(int id)
{
var result = await this.documentsProvider.DeleteLinkTypeAsync(id);
if (result.IsSuccess)
{
return Ok(result.LinkType);
}
return NotFound();
}
/// <summary>
/// download an existing attachment.
/// </summary>
[HttpGet("doculinks/download/{id}")]
public async Task<IActionResult> downloadfile(int id)
{
try
{
var result = await this.documentsProvider.GetDownloadAttachmentAsync(id);
if (!result.IsSuccess)
return NotFound();
string path = await uploadService.GetFile(result.DoculinkAttachments.Path);
if (path == null)
return NotFound();
var contentType = GetContentType(result.DoculinkAttachments.docName);
if (contentType == "application/octet-stream")
return PhysicalFile(path, contentType, result.DoculinkAttachments.docName);
return PhysicalFile(path, contentType, enableRangeProcessing: true);
}
catch (Exception ex)
{
// Handle the exception here or log it
return StatusCode(500, "An error occurred: " + ex.Message);
}
//try
//{
// var result = await this.documentsProvider.GetDownloadAttachmentAsync(id);
// if (!result.IsSuccess)
// return NotFound();
// byte[] fileContent = await uploadService.DownloadFile(result.DoculinkAttachments.Path);
// if (fileContent == null || fileContent.Length == 0)
// return NotFound();
// var contentType = "application/octet-stream";
// return File(fileContent, contentType, result.DoculinkAttachments.docName);
//}
//catch (Exception ex)
//{
// // Handle the exception here or log it
// return StatusCode(500, "An error occurred: " + ex.Message);
//}
}
private string GetContentType(string fileName)
{
// You can add more content types based on the file extensions
switch (Path.GetExtension(fileName).ToLower())
{
//case ".txt":
// return "text/plain";
case ".jpg":
case ".jpeg":
return "image/jpeg";
case ".png":
return "image/png";
case ".gif":
return "image/gif";
case ".bmp":
return "image/bmp";
case ".webp":
return "image/webp";
case ".csv":
return "text/csv";
case ".pdf":
return "application/pdf";
case ".docx":
case ".doc":
return "application/vnd.openxmlformats-officedocument.wordprocessingml.document";
case ".xlsx":
case ".xls":
return "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet";
// Add more cases as needed
default:
return "application/octet-stream";
}
}
/// <summary>
/// Get all Doculink.
/// </summary>
///
[Route("doculinks")]
[Route("doculinks/{linktype:alpha}")]
[Route("doculinks/{linktype:alpha}/{language:alpha}")]
[HttpGet]
public async Task<IActionResult> GetDocumentsAsync(string? linktype, string? language, bool? isactive)
{
var result = await this.documentsProvider.GetdocumentsByLinkAsync(linktype, language, isactive);
if (result.IsSuccess)
{
return Ok(result.documents);
}
return NoContent();
}
/// <summary>
/// Get all active Doculink.
/// </summary>
[Route("doculinks/active")]
[Route("doculinks/active/{linktype:alpha}")]
[Route("doculinks/active/{linktype:alpha}/{language:alpha}")]
[HttpGet]
public async Task<IActionResult> GetDocumentsByActiveAsync(string? linktype, string? language)
{
var result = await this.documentsProvider.GetdocumentsByLinkAsync(linktype, language, true);
if (result.IsSuccess)
{
return Ok(result.documents);
}
return NoContent();
}
/// <summary>
/// Get all active Doculink.
/// </summary>
[Route("doculinks/active/{linktypeid:int}")]
[Route("doculinks/active/{linktypeid:int}/{language:alpha}")]
[HttpGet]
public async Task<IActionResult> GetDocumentsByActiveLinkTypeIdAsync(int? linktypeid, string? language)
{
var result = await this.documentsProvider.GetdocumentsByLinkTypeIdAsync(linktypeid, language, true);
if (result.IsSuccess)
{
return Ok(result.documents);
}
return NoContent();
}
/// <summary>
/// Get a Doculink by id.
/// </summary>
[HttpGet]
[Route("doculinks/{id}")]
[Route("doculinks/{id}/{linktype:alpha}")]
[Route("doculinks/{id}/{linktype:alpha}/{language:alpha}")]
public async Task<IActionResult> GetDocumentAsync(int id, string? linktype, string? language)
{
var result = await this.documentsProvider.GetDocumentAsync(id, linktype, language);
if (result.IsSuccess)
{
return Ok(result.Document);
}
return NotFound();
}
/// <summary>
/// update existing doclink.
/// </summary>
[HttpPut]
[Route("doculinks/{id}")]
public async Task<IActionResult> UpdateDocument(int id, ReqDoculink documentInfo)
{
if (documentInfo != null)
{
var dbdoc = await this.documentsProvider.GetDocumentByidAsync(id);
if (dbdoc.IsSuccess)
{
var documents = await this.documentsProvider.GetDocumentCounter();
Models.Doculink DocuLink = uploadService.UpdateDocuments(documents.counter, dbdoc.Document, documentInfo);
var result = await this.documentsProvider.UpdateDocumentAsync(id, DocuLink);
if (result.IsSuccess)
{
return Ok(result.Document);
}
return NoContent();
}
return NotFound();
}
return BadRequest(documentInfo);
}
/// <summary>
/// update existing doclink isactive field.
/// </summary>
[HttpPut]
[Route("doculinks/{id}/{isactive}")]
public async Task<IActionResult> UpdateIsActiveDocument(int id, bool isactive)
{
var result = await this.documentsProvider.UpdateDocumentAsync(id, isactive);
if (result.IsSuccess)
{
return Ok(result.Document);
}
return NotFound();
}
/// <summary>
/// Create new doclink.
/// </summary>
[HttpPost]
[Route("doculinks")]
public async Task<IActionResult> CreateDocument(ReqDoculink documentInfo)
{
try
{
if (documentInfo != null)
{
var documents = await this.documentsProvider.GetDocumentCounter();
Models.Doculink DocuLink = uploadService.UploadDocument(documents.counter, documentInfo);
var result = await this.documentsProvider.PostDocumentAsync(DocuLink);
if (result.IsSuccess)
{
return Ok(result.Document);
}
return NoContent();
}
return BadRequest(documentInfo);
}
catch (Exception ex)
{
return BadRequest($"Internal server error: {ex}");
}
}
/// <summary>
/// Delete Doculink by id.
/// </summary>
[HttpDelete]
[Route("doculinks/{id}")]
public async Task<IActionResult> DeleteDocument(int id)
{
// database soft delete
var result = await this.documentsProvider.DeleteDocumentAsync(id);
if (result.IsSuccess)
{
// deleting file from folder
foreach (var item in result.Document.doclinksAttachments)
{
uploadService.Movefile(item.Path);
}
return Ok(result.Document);
}
return NotFound();
}
}
}

View File

@ -0,0 +1,28 @@
<Project Sdk="Microsoft.NET.Sdk.Web">
<PropertyGroup>
<TargetFramework>net6.0</TargetFramework>
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
<GenerateDocumentationFile>True</GenerateDocumentationFile>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="AutoMapper.Extensions.Microsoft.DependencyInjection" Version="12.0.1" />
<PackageReference Include="Azure.Storage.Blobs" Version="12.16.0" />
<PackageReference Include="Microsoft.AspNetCore.Hosting" Version="2.2.7" />
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="7.0.9" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="7.0.9">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="Microsoft.EntityFrameworkCore.InMemory" Version="7.0.5" />
<PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="7.0.9" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="7.0.9">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="Swashbuckle.AspNetCore" Version="6.2.3" />
</ItemGroup>
</Project>

View File

@ -0,0 +1,22 @@
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
namespace DamageAssesment.Api.DocuLinks.Db
{
[Table("Doculinks")]
public class Doculink
{
[Key]
public int Id { get; set; }
[ForeignKey("LinkType")]
public int linkTypeId { get; set; }
public bool IsActive { get; set; }
public bool IsDeleted { get; set; }
public int CustomOrder { get; set; }
//public bool IsAttachments { get; set; }
//public bool IsUrl { get; set; }
public DateTime dateCreated { get; set; }
public DateTime dateUpdated { get; set; }
}
}

View File

@ -0,0 +1,20 @@
using System.ComponentModel.DataAnnotations.Schema;
using System.ComponentModel.DataAnnotations;
namespace DamageAssesment.Api.DocuLinks.Db
{
[Table("DoculinkAttachments")]
public class DoculinkAttachments
{
[Key]
public int Id { get; set; }
[ForeignKey("Document")]
public int DocumentId { get; set; }
public string docName { get; set; }
public string Path { get; set; }
public bool IsAttachments { get; set; }
public int CustomOrder { get; set; }
public string Language { get; set; }
}
}

View File

@ -0,0 +1,38 @@
using Microsoft.AspNetCore.Identity;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Configuration;
using System.ComponentModel.DataAnnotations;
namespace DamageAssesment.Api.DocuLinks.Db
{
public class DoculinkDbContext : DbContext
{
public DoculinkDbContext(DbContextOptions options) : base(options)
{
}
public DbSet<Db.Doculink> Documents { get; set; }
public DbSet<Db.LinkType> LinkTypes { get; set; }
public DbSet<Db.DoculinkTranslation> DocumentsTranslations { get; set; }
public DbSet<Db.LinksTranslation> LinksTranslations { get; set; }
public DbSet<Db.DoculinkAttachments> DoclinksAttachments { get; set; }
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
modelBuilder.Entity<Doculink>()
.Property(item => item.Id)
.ValueGeneratedOnAdd();
modelBuilder.Entity<LinkType>()
.Property(item => item.Id)
.ValueGeneratedOnAdd();
modelBuilder.Entity<DoculinkTranslation>()
.Property(item => item.Id)
.ValueGeneratedOnAdd();
modelBuilder.Entity<LinksTranslation>()
.Property(item => item.Id)
.ValueGeneratedOnAdd();
modelBuilder.Entity<DoculinkAttachments>()
.Property(item => item.Id)
.ValueGeneratedOnAdd();
}
}
}

View File

@ -0,0 +1,17 @@
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
namespace DamageAssesment.Api.DocuLinks.Db
{
[Table("DoculinkTrans")]
public class DoculinkTranslation
{
[Key]
public int Id { get; set; }
[ForeignKey("Document")]
public int DocumentId { get; set; }
public string title { get; set; }
public string description { get; set; }
public string Language { get; set; }
}
}

View File

@ -0,0 +1,14 @@
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
namespace DamageAssesment.Api.DocuLinks.Db
{
[Table("DoculinkTypes")]
public class LinkType
{
[Key]
public int Id { get; set; }
public bool IsActive { get; set; }
public int CustomOrder { get; set; }
}
}

View File

@ -0,0 +1,16 @@
using System.ComponentModel.DataAnnotations.Schema;
using System.ComponentModel.DataAnnotations;
namespace DamageAssesment.Api.DocuLinks.Db
{
[Table("DoculinkTypeTrans")]
public class LinksTranslation
{
[Key]
public int Id { get; set; }
[ForeignKey("LinkType")]
public int LinkTypeId { get; set; }
public string TypeText { get; set; }
public string Language { get; set; }
}
}

View File

@ -0,0 +1,10 @@
using Azure.Storage.Blobs.Models;
namespace DamageAssesment.Api.DocuLinks.Interfaces
{
public interface IAzureBlobService
{
Task<List<Azure.Response<BlobContentInfo>>> UploadFiles(List<IFormFile> files);
void DeleteFile(string path);
}
}

View File

@ -0,0 +1,21 @@
using DamageAssesment.Api.DocuLinks.Models;
namespace DamageAssesment.Api.DocuLinks.Interfaces
{
public interface IDoculinkProvider : ILinkTypesProvider
{
Task<(bool IsSuccess, Models.ResDoculink Document, string ErrorMessage)> GetDocumentAsync(int id, string? linktype, string? language);
Task<(bool IsSuccess, Models.Doculink Document, string ErrorMessage)> GetDocumentByidAsync(int id);
// Task<(bool IsSuccess, IEnumerable<Models.ResDoculink> documents, string ErrorMessage)> GetDocumnetsAsync(string? language);
Task<(bool IsSuccess, IEnumerable<Models.ResDoculink> documents, string ErrorMessage)> GetdocumentsByLinkAsync(string? linkType, string? language, bool? isactive);
Task<(bool IsSuccess, IEnumerable<Models.ResDoculink> documents, string ErrorMessage)> GetdocumentsByLinkTypeIdAsync(int? linkTypeId, string? language, bool? isactive);
Task<(bool IsSuccess, Models.ResDoculink Document, string ErrorMessage)> PostDocumentAsync(Models.Doculink Document);
Task<(bool IsSuccess, Models.ResDoculink Document, string ErrorMessage)> UpdateDocumentAsync(int id, Models.Doculink Document);
Task<(bool IsSuccess, Models.ResDoculink Document, string ErrorMessage)> UpdateDocumentAsync(int id, bool isactive);
Task<(bool IsSuccess, Models.ResDoculink Document, string ErrorMessage)> DeleteDocumentAsync(int id);
Task<(bool IsSuccess, Models.DoculinkAttachments DoculinkAttachments, string Path)> GetDownloadAttachmentAsync(int id);
Task<(bool IsSuccess, int counter, string message)> GetDocumentCounter();
}
}

View File

@ -0,0 +1,11 @@
namespace DamageAssesment.Api.DocuLinks.Interfaces
{
public interface ILinkTypesProvider
{
Task<(bool IsSuccess, Models.ResLinkType LinkType, string ErrorMessage)> GetLinkTypeAsync(int id,string? language);
Task<(bool IsSuccess, IEnumerable<Models.ResLinkType> LinkTypes, string ErrorMessage)> GetLinkTypesAsync(string? language);
Task<(bool IsSuccess, Models.ResLinkType LinkType, string ErrorMessage)> PostLinkTypeAsync(Models.LinkType LinkType);
Task<(bool IsSuccess, Models.ResLinkType LinkType, string ErrorMessage)> UpdateLinkTypeAsync(int id,Models.LinkType LinkType);
Task<(bool IsSuccess, Models.ResLinkType LinkType, string ErrorMessage)> DeleteLinkTypeAsync(int id);
}
}

View File

@ -0,0 +1,14 @@
using DamageAssesment.Api.DocuLinks.Models;
namespace DamageAssesment.Api.DocuLinks.Interfaces
{
public interface IUploadService
{
Models.Doculink UploadDocument( int counter, ReqDoculink documentInfo);
public Models.Doculink UpdateDocuments(int counter, Models.Doculink document, ReqDoculink documentInfo);
void Deletefile(string path);
Task<byte[]> DownloadFile(string path);
Task<string> GetFile(string path);
void Movefile(string path);
}
}

View File

@ -0,0 +1,30 @@
using DamageAssesment.Api.DocuLinks.Models;
using System.ComponentModel.DataAnnotations;
namespace DamageAssesment.Api.DocuLinks.Models
{
public class Doculink : BaseDoculink
{
public List<DoculinkTranslation> documentsTranslations { get; set; }
}
public class ResDoculinks
{
public int linkTypeId { get; set; }
public List<ResDoculink> doculinks { get; set; }
}
public class ResDoculink:BaseDoculink
{
public object titles { get; set; }
public object description { get; set; }
public object linktypes { get; set; }
}
public class BaseDoculink
{
public int Id { get; set; }
public int linkTypeId { get; set; }
public bool IsActive { get; set; }
public bool IsDeleted { get; set; }
public List<DoculinkAttachments> doclinksAttachments { get; set; }
public int CustomOrder { get; set; }
}
}

View File

@ -0,0 +1,14 @@
using System.ComponentModel.DataAnnotations.Schema;
using System.ComponentModel.DataAnnotations;
namespace DamageAssesment.Api.DocuLinks.Models
{
public class DoculinkAttachments
{
public string docName { get; set; }
public string Path { get; set; }
public bool IsAttachments { get; set; }
public string Language { get; set; }
public int CustomOrder { get; set; }
}
}

View File

@ -0,0 +1,12 @@
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
namespace DamageAssesment.Api.DocuLinks.Models
{
public class DoculinkTranslation
{
public string title { get; set; }
public string description { get; set; }
public string Language { get; set; }
}
}

View File

@ -0,0 +1,20 @@
using System.ComponentModel.DataAnnotations;
namespace DamageAssesment.Api.DocuLinks.Models
{
public class LinkType : BaseLinkType
{
public List<LinksTranslation> linksTranslations { get; set; }
}
public class BaseLinkType
{
public int Id { get; set; }
public bool IsActive { get; set; }
public int CustomOrder { get; set; }
}
public class ResLinkType : BaseLinkType
{
public object titles { get; set; }
}
}

View File

@ -0,0 +1,11 @@
using System.ComponentModel.DataAnnotations.Schema;
using System.ComponentModel.DataAnnotations;
namespace DamageAssesment.Api.DocuLinks.Models
{
public class LinksTranslation
{
public string TypeText { get; set; }
public string Language { get; set; }
}
}

View File

@ -0,0 +1,24 @@
using System.ComponentModel.DataAnnotations.Schema;
namespace DamageAssesment.Api.DocuLinks.Models
{
public class ReqDoculink
{
public int Id { get; set; }
public int linkTypeId { get; set; }
public List<DoculinkTranslation> documentsTranslations { get; set; }
public bool IsActive { get; set; }
public int CustomOrder { get; set; }
public List<FileModel>? Files { get; set; }
}
public class FileModel
{
public string? FileName { get; set; }
public string? FileContent { get; set; }
public string? FileExtension { get; set; }
public int CustomOrder { get; set; }
public string url { get;set; }
public bool IsAttachments { get; set; }
public string Language { get; set; }
}
}

View File

@ -0,0 +1,22 @@
using AutoMapper;
namespace DamageAssesment.Api.DocuLinks.Profiles
{
public class DoculinkProfile : AutoMapper.Profile
{
public DoculinkProfile()
{
CreateMap<Db.Doculink, Models.ResDoculink>() ;
CreateMap<Db.Doculink, Models.Doculink>();
CreateMap<Models.Doculink, Db.Doculink>();
CreateMap<Db.LinkType, Models.ResLinkType>();
CreateMap<Models.LinkType, Db.LinkType>();
CreateMap<Db.DoculinkTranslation, Models.DoculinkTranslation>();
CreateMap<Models.DoculinkTranslation, Db.DoculinkTranslation>();
CreateMap<Db.LinksTranslation, Models.LinksTranslation>();
CreateMap<Models.LinksTranslation, Db.LinksTranslation>();
CreateMap<Db.DoculinkAttachments, Models.DoculinkAttachments>();
CreateMap<Models.DoculinkAttachments, Db.DoculinkAttachments>();
}
}
}

View File

@ -0,0 +1,44 @@
using DamageAssesment.Api.DocuLinks.Db;
using DamageAssesment.Api.DocuLinks.Interfaces;
using DamageAssesment.Api.DocuLinks.Providers;
using Microsoft.EntityFrameworkCore;
using System.Reflection;
var builder = WebApplication.CreateBuilder(args);
// Add services to the container.
builder.Services.AddControllers();
builder.Services.AddSwaggerGen(c =>
{
// Include XML comments from your assembly
var xmlFile = $"{Assembly.GetExecutingAssembly().GetName().Name}.xml";
var xmlPath = Path.Combine(AppContext.BaseDirectory, xmlFile);
c.IncludeXmlComments(xmlPath);
});
// Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();
builder.Services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();
builder.Services.AddScoped<IDoculinkProvider, DoculinkProvider>();
builder.Services.AddScoped<IUploadService, UploadService>();
builder.Services.AddScoped<IAzureBlobService, AzureBlobService>();
builder.Services.AddAutoMapper(AppDomain.CurrentDomain.GetAssemblies()); //4/30
builder.Services.AddDbContext<DoculinkDbContext>(option =>
{
option.UseInMemoryDatabase("DocumentConnection");
});
var app = builder.Build();
// Configure the HTTP request pipeline.
if (app.Environment.IsDevelopment())
{
app.UseSwagger();
app.UseSwaggerUI();
}
app.UseAuthorization();
app.MapControllers();
app.Run();

View File

@ -0,0 +1,31 @@
{
"$schema": "https://json.schemastore.org/launchsettings.json",
"iisSettings": {
"windowsAuthentication": false,
"anonymousAuthentication": true,
"iisExpress": {
"applicationUrl": "http://localhost:60754",
"sslPort": 0
}
},
"profiles": {
"DamageAssesment.Api.Questions": {
"commandName": "Project",
"dotnetRunMessages": true,
"launchBrowser": true,
"launchUrl": "swagger",
"applicationUrl": "http://localhost:5133",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
},
"IIS Express": {
"commandName": "IISExpress",
"launchBrowser": true,
"launchUrl": "swagger",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
}
}
}

View File

@ -0,0 +1,44 @@

using Azure.Storage.Blobs;
using Azure.Storage.Blobs.Models;
using Azure.Storage.Blobs.Specialized;
using DamageAssesment.Api.DocuLinks.Interfaces;
namespace DamageAssesment.Api.DocuLinks.Providers
{
public class AzureBlobService: IAzureBlobService
{
BlobServiceClient _blobClient;
BlobContainerClient _containerClient;
string azureConnectionString = "<Primary Connection String>";
public AzureBlobService()
{
_blobClient = new BlobServiceClient(azureConnectionString);
_containerClient = _blobClient.GetBlobContainerClient("apiimages");
}
public async Task<List<Azure.Response<BlobContentInfo>>> UploadFiles(List<IFormFile> files)
{
var azureResponse = new List<Azure.Response<BlobContentInfo>>();
foreach (var file in files)
{
string fileName = file.FileName;
using (var memoryStream = new MemoryStream())
{
file.CopyTo(memoryStream);
memoryStream.Position = 0;
var client = await _containerClient.UploadBlobAsync(fileName, memoryStream, default);
azureResponse.Add(client);
}
};
return azureResponse;
}
public void DeleteFile(string url)
{
var blob = _containerClient.GetBlockBlobClient(url);
blob.DeleteIfExists();
}
}
}

View File

@ -0,0 +1,674 @@
using AutoMapper;
using DamageAssesment.Api.DocuLinks.Db;
using DamageAssesment.Api.DocuLinks.Interfaces;
using DamageAssesment.Api.DocuLinks.Models;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Metadata.Internal;
using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Diagnostics.Eventing.Reader;
using System.Reflection.Metadata;
using System.Runtime.CompilerServices;
using System.Xml;
using System.Xml.Linq;
namespace DamageAssesment.Api.DocuLinks.Providers
{
public class DoculinkProvider : IDoculinkProvider
{
private DoculinkDbContext DocumentDbContext;
private ILogger<DoculinkProvider> logger;
private IUploadService uploadservice;
private IMapper mapper;
private readonly IHttpContextAccessor httpContextAccessor;
private string baseUrl;
public DoculinkProvider(DoculinkDbContext DocumentDbContext, ILogger<DoculinkProvider> logger, IMapper mapper, IUploadService uploadservice, IHttpContextAccessor httpContextAccessor)
{
this.DocumentDbContext = DocumentDbContext;
this.logger = logger;
this.mapper = mapper;
this.uploadservice = uploadservice;
this.httpContextAccessor = httpContextAccessor;
baseUrl = $"{httpContextAccessor.HttpContext.Request.Scheme}://{httpContextAccessor.HttpContext.Request.Host}";
baseUrl = baseUrl + "/doculinks/download";
SeedData();
}
private void SeedData()
{
if (!DocumentDbContext.LinkTypes.Any())
{
DocumentDbContext.LinkTypes.Add(new Db.LinkType() { IsActive = true, CustomOrder = 1 });
DocumentDbContext.LinkTypes.Add(new Db.LinkType() { IsActive = true, CustomOrder = 2 });
DocumentDbContext.LinkTypes.Add(new Db.LinkType() { IsActive = true, CustomOrder = 3 });
DocumentDbContext.LinkTypes.Add(new Db.LinkType() { IsActive = true, CustomOrder = 4 });
DocumentDbContext.SaveChanges();
}
if (!DocumentDbContext.LinksTranslations.Any())
{
DocumentDbContext.LinksTranslations.Add(new Db.LinksTranslation() { TypeText = "Forms", Language = "en", LinkTypeId = 1 });
DocumentDbContext.LinksTranslations.Add(new Db.LinksTranslation() { TypeText = "Communiques", Language = "en", LinkTypeId = 2 });
DocumentDbContext.LinksTranslations.Add(new Db.LinksTranslation() { TypeText = "Memos", Language = "en", LinkTypeId = 3 });
DocumentDbContext.LinksTranslations.Add(new Db.LinksTranslation() { TypeText = "Trainings", Language = "en", LinkTypeId = 4 });
DocumentDbContext.LinksTranslations.Add(new Db.LinksTranslation() { TypeText = "Formularios", Language = "es", LinkTypeId = 1 });
DocumentDbContext.LinksTranslations.Add(new Db.LinksTranslation() { TypeText = "Comunicados", Language = "es", LinkTypeId = 2 });
DocumentDbContext.LinksTranslations.Add(new Db.LinksTranslation() { TypeText = "notas", Language = "es", LinkTypeId = 3 });
DocumentDbContext.LinksTranslations.Add(new Db.LinksTranslation() { TypeText = "Entrenamientos", Language = "es", LinkTypeId = 4 });
DocumentDbContext.LinksTranslations.Add(new Db.LinksTranslation() { TypeText = "Formes", Language = "fr", LinkTypeId = 1 });
DocumentDbContext.LinksTranslations.Add(new Db.LinksTranslation() { TypeText = "Communiqués", Language = "fr", LinkTypeId = 2 });
DocumentDbContext.LinksTranslations.Add(new Db.LinksTranslation() { TypeText = "Mémos", Language = "fr", LinkTypeId = 3 });
DocumentDbContext.LinksTranslations.Add(new Db.LinksTranslation() { TypeText = "Formations", Language = "fr", LinkTypeId = 4 });
DocumentDbContext.SaveChanges();
}
if (!DocumentDbContext.Documents.Any())
{
int counter = 0;
for (int i = 1; i <= 4; i++)
{
int linkTypeId = 2;
FileModel fileModel = new FileModel();
if (i < 3)
{
linkTypeId = 1;
fileModel = new FileModel() { FileName = "Sample" + i, FileExtension = ".txt", FileContent = "c2FtcGxl", IsAttachments = true, CustomOrder = 1, Language = "en" };
}
else
fileModel = new FileModel() { url = "www.google" + i + ".com", IsAttachments = false, CustomOrder = 1,Language="en" };
ReqDoculink documentInfo = new ReqDoculink() { linkTypeId = i, CustomOrder = i, Files = new List<FileModel>() { fileModel } };
Models.Doculink document = uploadservice.UploadDocument(counter, documentInfo);
DocumentDbContext.Documents.Add(mapper.Map<Models.Doculink, Db.Doculink>(document));
DocumentDbContext.SaveChanges();
var dbattachments = mapper.Map<List<Models.DoculinkAttachments>, List<Db.DoculinkAttachments>>(document.doclinksAttachments);
dbattachments.ForEach(a => a.DocumentId = i);
DocumentDbContext.DoclinksAttachments.AddRange(dbattachments);
DocumentDbContext.SaveChanges();
counter++;
}
}
if (!DocumentDbContext.DocumentsTranslations.Any())
{
string[] titles = {
"Mobile App Damage Assessment Instructions",
"PC Damage Assessment Instructions",
"Emergency Evacuation centers",
"Mobile App Damage Assessment Instructions" };
string[] esTranslations = {
"Instrucciones de Evaluación de Daños de la Aplicación Móvil",
"Instrucciones de Evaluación de Daños del PC",
"Centros de Evacuación de Emergencia",
"Instrucciones de Evaluación de Daños de la Aplicación Móvil" };
string[] frTranslations = {
"Instructions d'Évaluation des Dommages de l'Application Mobile",
"Instructions d'Évaluation des Dommages du PC",
"Centres d'Évacuation d'Urgence",
"Instructions d'Évaluation des Dommages de l'Application Mobile" };
List<Db.DoculinkTranslation> documents = new List<Db.DoculinkTranslation>();
for (int i = 0; i < 4; i++)
{
documents.Add(new Db.DoculinkTranslation { DocumentId = i + 1, title = titles[i], description = titles[i], Language = "en" });
documents.Add(new Db.DoculinkTranslation { DocumentId = i + 1, title = esTranslations[i], description = esTranslations[i], Language = "es" });
documents.Add(new Db.DoculinkTranslation { DocumentId = i + 1, title = frTranslations[i], description = frTranslations[i], Language = "fr" });
}
DocumentDbContext.DocumentsTranslations.AddRange(documents);
DocumentDbContext.SaveChanges();
}
}
public List<Models.DoculinkTranslation> GetDocumentTranslations(int id, string? language)
{
List<Models.DoculinkTranslation> QuestionTranslations;
if (string.IsNullOrEmpty(language))
{
QuestionTranslations = mapper.Map<List<Db.DoculinkTranslation>, List<Models.DoculinkTranslation>>(
DocumentDbContext.DocumentsTranslations.AsNoTracking().Where(a => a.DocumentId == id).ToList());
}
else
{
QuestionTranslations = mapper.Map<List<Db.DoculinkTranslation>, List<Models.DoculinkTranslation>>(
DocumentDbContext.DocumentsTranslations.AsNoTracking().Where(a => a.DocumentId == id && a.Language == language).ToList());
}
return QuestionTranslations;
}
public ResDoculink CreateMultiLanguageObject(List<Models.DoculinkTranslation> questions)
{
ResDoculink MultiLanguage = new ResDoculink();
Dictionary<string, string> dicttitle = new Dictionary<string, string>();
Dictionary<string, string> dictdesc = new Dictionary<string, string>();
foreach (Models.DoculinkTranslation item in questions)
{
dicttitle.Add(item.Language, item.title);
dictdesc.Add(item.Language, item.description);
}
MultiLanguage.titles = dicttitle;
MultiLanguage.description = dictdesc;
return MultiLanguage;
}
public List<Models.LinksTranslation> GetLinkTypeTranslations(int id, string? language)
{
List<Models.LinksTranslation> linksTranslations;
if (string.IsNullOrEmpty(language))
{
linksTranslations = mapper.Map<List<Db.LinksTranslation>, List<Models.LinksTranslation>>(
DocumentDbContext.LinksTranslations.AsNoTracking().Where(a => a.LinkTypeId == id).ToList());
}
else
{
linksTranslations = mapper.Map<List<Db.LinksTranslation>, List<Models.LinksTranslation>>(
DocumentDbContext.LinksTranslations.AsNoTracking().Where(a => a.LinkTypeId == id && a.Language == language).ToList());
}
return linksTranslations;
}
public object CreateMultiLanguageLinkTypeObject(List<Models.LinksTranslation> links)
{
object MultiLanguage = new object();
Dictionary<string, string> dicttitle = new Dictionary<string, string>();
foreach (Models.LinksTranslation item in links)
{
dicttitle.Add(item.Language, item.TypeText);
}
MultiLanguage = dicttitle;
return MultiLanguage;
}
private List<Models.DoculinkAttachments> GetDocumentAttachment(int id,string? language)
{
List<Db.DoculinkAttachments> doculinkAttachments = null;
if (string.IsNullOrEmpty(language))
{
doculinkAttachments = DocumentDbContext.DoclinksAttachments.AsNoTracking().Where(a => a.DocumentId == id).ToList();
}
else
{
doculinkAttachments = DocumentDbContext.DoclinksAttachments.AsNoTracking().Where(a => a.DocumentId == id && a.Language == language).ToList();
}
foreach (var attachment in doculinkAttachments)
{
if (attachment.IsAttachments)
attachment.Path = $"{baseUrl}/{attachment.Id}";
}
return mapper.Map<List<Db.DoculinkAttachments>, List<Models.DoculinkAttachments>>(doculinkAttachments);
}
public async Task<(bool IsSuccess, Models.DoculinkAttachments DoculinkAttachments, string Path)> GetDownloadAttachmentAsync(int id)
{
try
{
Db.DoculinkAttachments Attachment = DocumentDbContext.DoclinksAttachments.AsNoTracking().Where(a => a.Id == id).AsNoTracking().FirstOrDefault();
if (Attachment == null)
{
return (false, null, "Not Found");
}
return (true, mapper.Map<Db.DoculinkAttachments, Models.DoculinkAttachments>(Attachment), $"Attachment {id}");
}
catch (Exception ex)
{
logger?.LogError(ex.ToString());
return (false, null, ex.Message);
}
}
public async Task<(bool IsSuccess, IEnumerable<Models.ResDoculink> documents, string ErrorMessage)> GetdocumentsByLinkTypeIdAsync(int? linkTypeId, string? language, bool? isactive)
{
try
{
logger?.LogInformation("Query Question");
var documents = new List<Db.Doculink>();
if (linkTypeId==null)
documents = await DocumentDbContext.Documents.AsNoTracking().Where(q => (isactive == null || q.IsActive == isactive.Value)).ToListAsync();
else
documents = await DocumentDbContext.Documents.AsNoTracking().Where(q => (isactive == null || q.IsActive == isactive.Value) &&
q.linkTypeId == linkTypeId.Value).ToListAsync();
if (documents != null)
{
var result = mapper.Map<List<Db.Doculink>, List<Models.ResDoculink>>(documents);
foreach (var item in result)
{
var multilan = CreateMultiLanguageObject(GetDocumentTranslations(item.Id, language));
item.titles = multilan.titles;
item.description = multilan.description;
item.linktypes = CreateMultiLanguageLinkTypeObject(GetLinkTypeTranslations(item.linkTypeId, language));
item.doclinksAttachments = GetDocumentAttachment(item.Id,language);
}
// List<ResDoculinks> doculinks = result.GroupBy(a => a.linkTypeId).Select(a => new ResDoculinks() { linkTypeId = a.Key, doculinks = a.ToList() }).ToList();
return (true, result, null);
}
return (false, null, "Not found");
}
catch (Exception ex)
{
logger?.LogError(ex.ToString());
return (false, null, ex.Message);
}
}
public async Task<(bool IsSuccess, IEnumerable<Models.ResDoculink> documents, string ErrorMessage)> GetdocumentsByLinkAsync(string? linkType, string? language, bool? isactive)
{
try
{
logger?.LogInformation("Query Question");
var documents = new List<Db.Doculink>();
if (String.IsNullOrEmpty(linkType))
documents = await DocumentDbContext.Documents.AsNoTracking().Where(q => (isactive == null || q.IsActive == isactive.Value)).ToListAsync();
else
documents = await DocumentDbContext.Documents.AsNoTracking().Where(q => (isactive == null || q.IsActive == isactive.Value) &&
q.linkTypeId == (DocumentDbContext.LinksTranslations.AsNoTracking().Where(a => a.TypeText.ToLower() == linkType.ToLower()).Select(a => a.Id).FirstOrDefault())).ToListAsync();
if (documents != null)
{
var result = mapper.Map<List<Db.Doculink>, List<Models.ResDoculink>>(documents);
foreach (var item in result)
{
var multilan = CreateMultiLanguageObject(GetDocumentTranslations(item.Id, language));
item.titles = multilan.titles;
item.description = multilan.description;
item.linktypes = CreateMultiLanguageLinkTypeObject(GetLinkTypeTranslations(item.linkTypeId, language));
item.doclinksAttachments = GetDocumentAttachment(item.Id, language);
}
//List<ResDoculinks> doculinks = result.GroupBy(a => a.linkTypeId).Select(a => new ResDoculinks() { linkTypeId = a.Key, doculinks = a.ToList() }).ToList();
return (true, result, null);
}
return (false, null, "Not found");
}
catch (Exception ex)
{
logger?.LogError(ex.ToString());
return (false, null, ex.Message);
}
}
//public async Task<(bool IsSuccess, IEnumerable<Models.ResDoculink> documents, string ErrorMessage)> GetDocumnetsAsync(string? language)
//{
// try
// {
// logger?.LogInformation("Query Question");
// var documents = await DocumentDbContext.Documents.Include(a => a.LinkType).AsNoTracking().Where(q => q.IsActive).ToListAsync();
// if (documents != null)
// {
// logger?.LogInformation($"{documents.Count} Document(s) found");
// var result = mapper.Map<List<Db.Document>, List<Models.ResDoculink>>(documents);
// foreach (var item in result)
// {
// var multilan = CreateMultiLanguageObject(GetDocumentTranslations(item.Id, language));
// item.titles = multilan.titles;
// item.description = multilan.description;
// }
// return (true, result, null);
// }
// return (false, null, "Not found");
// }
// catch (Exception ex)
// {
// logger?.LogError(ex.ToString());
// return (false, null, ex.Message);
// }
//}
public async Task<(bool IsSuccess, Models.Doculink Document, string ErrorMessage)> GetDocumentByidAsync(int id)
{
try
{
logger?.LogInformation("Query LinkType");
var Document = await DocumentDbContext.Documents.AsNoTracking().FirstOrDefaultAsync(q => q.Id == id && q.IsActive);
if (Document != null)
{
logger?.LogInformation($"{Document} customer(s) found");
var result = mapper.Map<Db.Doculink, Models.Doculink>(Document);
result.documentsTranslations = mapper.Map<List<Db.DoculinkTranslation>, List<Models.DoculinkTranslation>>(
DocumentDbContext.DocumentsTranslations.Where(a => a.DocumentId == result.Id).ToList());
result.doclinksAttachments = GetDocumentAttachment(id, "");
return (true, result, null);
}
return (false, null, "Not found");
}
catch (Exception ex)
{
logger?.LogError(ex.ToString());
return (false, null, ex.Message);
}
}
//added linktype filter
public async Task<(bool IsSuccess, Models.ResDoculink Document, string ErrorMessage)> GetDocumentAsync(int id, string? linkType, string? language)
{
try
{
logger?.LogInformation("Query LinkType");
//var Document = await DocumentDbContext.Documents.Include(a => a.LinkType).AsNoTracking().FirstOrDefaultAsync(q => q.Id == id && q.IsActive);
var Document = new Db.Doculink();
if (String.IsNullOrEmpty(linkType))
Document = await DocumentDbContext.Documents.AsNoTracking().Where(q => q.IsActive && q.Id == id).FirstOrDefaultAsync();
else
Document = await DocumentDbContext.Documents.AsNoTracking().Where(q => q.IsActive && q.Id == id &&
q.linkTypeId == (DocumentDbContext.LinksTranslations.AsNoTracking().Where(a => a.TypeText.ToLower() == linkType.ToLower()).Select(a => a.Id).FirstOrDefault())).FirstOrDefaultAsync();
if (Document != null)
{
logger?.LogInformation($"{Document} customer(s) found");
var result = mapper.Map<Db.Doculink, Models.ResDoculink>(Document);
var multilan = CreateMultiLanguageObject(GetDocumentTranslations(result.Id, language));
result.linktypes = CreateMultiLanguageLinkTypeObject(GetLinkTypeTranslations(result.linkTypeId, language));
result.titles = multilan.titles;
result.description = multilan.description;
result.doclinksAttachments = GetDocumentAttachment(id, language);
return (true, result, null);
}
return (false, null, "Not found");
}
catch (Exception ex)
{
logger?.LogError(ex.ToString());
return (false, null, ex.Message);
}
}
public async Task<(bool IsSuccess, Models.ResDoculink Document, string ErrorMessage)> PostDocumentAsync(Models.Doculink Document)
{
try
{
var document = mapper.Map<Models.Doculink, Db.Doculink>(Document);
document.dateCreated = DateTime.Now; document.dateUpdated = DateTime.Now;
DocumentDbContext.Documents.Add(document);
DocumentDbContext.SaveChanges();
var dbtranslation = mapper.Map<List<Models.DoculinkTranslation>, List<Db.DoculinkTranslation>>(Document.documentsTranslations);
dbtranslation.ForEach(i => i.DocumentId = document.Id);
DocumentDbContext.DocumentsTranslations.AddRange(dbtranslation);
var dbattachments = mapper.Map<List<Models.DoculinkAttachments>, List<Db.DoculinkAttachments>>(Document.doclinksAttachments);
dbattachments.ForEach(i => i.DocumentId = document.Id);
DocumentDbContext.DoclinksAttachments.AddRange(dbattachments);
DocumentDbContext.SaveChanges();
var result = mapper.Map<Db.Doculink, Models.ResDoculink>(document);
var multilan = CreateMultiLanguageObject(GetDocumentTranslations(document.Id, ""));
result.linktypes = CreateMultiLanguageLinkTypeObject(GetLinkTypeTranslations(Document.linkTypeId, ""));
result.titles = multilan.titles;
result.description = multilan.description;
result.doclinksAttachments = GetDocumentAttachment(document.Id,"");
return (true, result, null);
}
catch (Exception ex)
{
logger?.LogError(ex.ToString());
return (false, null, ex.Message);
}
}
public async Task<(bool IsSuccess, Models.ResDoculink Document, string ErrorMessage)> UpdateDocumentAsync(int id, Models.Doculink Document)
{
try
{
if (Document != null)
{
var existing = DocumentDbContext.Documents.AsNoTracking().FirstOrDefault(x => x.Id == id);
if (existing != null)
{
Document.Id = existing.Id;
var document = mapper.Map<Models.Doculink, Db.Doculink>(Document);
document.dateUpdated = DateTime.Now;
DocumentDbContext.Documents.Update(document);
DocumentDbContext.SaveChanges();
var oldtranslations = DocumentDbContext.DocumentsTranslations.Where(a => a.DocumentId == id).ToList();
if (oldtranslations != null)
DocumentDbContext.DocumentsTranslations.RemoveRange(oldtranslations);
var oldattachments = DocumentDbContext.DoclinksAttachments.Where(a => a.DocumentId == id).ToList();
if (oldattachments != null)
DocumentDbContext.DoclinksAttachments.RemoveRange(oldattachments);
var dbtranslation = mapper.Map<List<Models.DoculinkTranslation>, List<Db.DoculinkTranslation>>(Document.documentsTranslations);
dbtranslation.ForEach(i => i.DocumentId = Document.Id);
DocumentDbContext.DocumentsTranslations.AddRange(dbtranslation);
var dbattachments = mapper.Map<List<Models.DoculinkAttachments>, List<Db.DoculinkAttachments>>(Document.doclinksAttachments);
dbattachments.ForEach(i => i.DocumentId = document.Id);
DocumentDbContext.DoclinksAttachments.AddRange(dbattachments);
DocumentDbContext.SaveChanges();
var result = mapper.Map<Db.Doculink, Models.ResDoculink>(document);
var multilan = CreateMultiLanguageObject(GetDocumentTranslations(document.Id, ""));
result.linktypes = CreateMultiLanguageLinkTypeObject(GetLinkTypeTranslations(document.linkTypeId, ""));
result.titles = multilan.titles;
result.description = multilan.description;
result.doclinksAttachments = GetDocumentAttachment(document.Id, "");
return (true, result, "Successful");
}
else
{
logger?.LogInformation($"{Document} Not found");
return (false, null, "Not Found");
}
}
else
{
logger?.LogInformation($"{Document} Bad Request");
return (false, null, "Bad request");
}
}
catch (Exception ex)
{
logger?.LogError(ex.ToString());
return (false, null, ex.Message);
}
}
public async Task<(bool IsSuccess, Models.ResDoculink Document, string ErrorMessage)> UpdateDocumentAsync(int id,bool isactive)
{
try
{
Db.Doculink Document = DocumentDbContext.Documents.AsNoTracking().Where(a => a.Id == id).FirstOrDefault();
if (Document == null)
{
return (false, null, "Not Found");
}
Document.IsActive = isactive;
DocumentDbContext.Documents.Update(Document);
DocumentDbContext.SaveChanges();
var result = mapper.Map<Db.Doculink, Models.ResDoculink>(Document);
var multilan = CreateMultiLanguageObject(GetDocumentTranslations(Document.Id, ""));
result.titles = multilan.titles;
result.description = multilan.description;
result.linktypes = CreateMultiLanguageLinkTypeObject(GetLinkTypeTranslations(result.linkTypeId, ""));
result.doclinksAttachments = mapper.Map<List<Db.DoculinkAttachments>, List<Models.DoculinkAttachments>>(
DocumentDbContext.DoclinksAttachments.AsNoTracking().Where(a => a.DocumentId == id).ToList());
return (true, result, $"DocumentId {id} deleted Successfuly");
}
catch (Exception ex)
{
logger?.LogError(ex.ToString());
return (false, null, ex.Message);
}
}
public async Task<(bool IsSuccess, Models.ResDoculink Document, string ErrorMessage)> DeleteDocumentAsync(int id)
{
try
{
Db.Doculink Document = DocumentDbContext.Documents.AsNoTracking().Where(a => a.Id == id).FirstOrDefault();
if (Document == null)
{
return (false, null, "Not Found");
}
var result = mapper.Map<Db.Doculink, Models.ResDoculink>(Document);
var multilan = CreateMultiLanguageObject(GetDocumentTranslations(Document.Id, ""));
result.titles = multilan.titles;
result.description = multilan.description;
result.linktypes = CreateMultiLanguageLinkTypeObject(GetLinkTypeTranslations(result.linkTypeId, ""));
result.doclinksAttachments = mapper.Map<List<Db.DoculinkAttachments>, List<Models.DoculinkAttachments>>(
DocumentDbContext.DoclinksAttachments.AsNoTracking().Where(a => a.DocumentId == id).ToList());
Document.IsActive = false;
DocumentDbContext.Documents.Update(Document);
DocumentDbContext.SaveChanges();
return (true, result, $"DocumentId {id} deleted Successfuly");
}
catch (Exception ex)
{
logger?.LogError(ex.ToString());
return (false, null, ex.Message);
}
}
public async Task<(bool IsSuccess, int counter, string message)> GetDocumentCounter()
{
try
{
int AttachmentId = DocumentDbContext.DoclinksAttachments.Max(a => a.Id);
return (true, AttachmentId, "");
}
catch (Exception ex)
{
return (false, 0, ex.Message);
}
}
//Link Type methods
public async Task<(bool IsSuccess, IEnumerable<Models.ResLinkType> LinkTypes, string ErrorMessage)> GetLinkTypesAsync(string? language)
{
try
{
logger?.LogInformation("Query Question");
var LinkType = await DocumentDbContext.LinkTypes.AsNoTracking().Where(q => q.IsActive).ToListAsync();
if (LinkType != null)
{
logger?.LogInformation($"{LinkType.Count} LinkTypes(s) found");
var result = mapper.Map<IEnumerable<Db.LinkType>, IEnumerable<Models.ResLinkType>>(LinkType);
foreach (var item in result)
{
item.titles = CreateMultiLanguageLinkTypeObject(GetLinkTypeTranslations(item.Id, language));
}
return (true, result, null);
}
return (false, null, "Not found");
}
catch (Exception ex)
{
logger?.LogError(ex.ToString());
return (false, null, ex.Message);
}
}
public async Task<(bool IsSuccess, Models.ResLinkType LinkType, string ErrorMessage)> GetLinkTypeAsync(int Id, string? language)
{
try
{
logger?.LogInformation("Query LinkType");
var LinkType = await DocumentDbContext.LinkTypes.AsNoTracking().FirstOrDefaultAsync(q => q.Id == Id && q.IsActive);
if (LinkType != null)
{
logger?.LogInformation($"{LinkType} customer(s) found");
var result = mapper.Map<Db.LinkType, Models.ResLinkType>(LinkType);
result.titles = CreateMultiLanguageLinkTypeObject(GetLinkTypeTranslations(result.Id, language));
return (true, result, null);
}
return (false, null, "Not found");
}
catch (Exception ex)
{
logger?.LogError(ex.ToString());
return (false, null, ex.Message);
}
}
public async Task<(bool IsSuccess, Models.ResLinkType LinkType, string ErrorMessage)> PostLinkTypeAsync(Models.LinkType LinkType)
{
try
{
logger?.LogInformation("Query LinkType");
if (!LinkTypeExists(LinkType.Id))
{
var dbLink = mapper.Map<Models.LinkType, Db.LinkType>(LinkType);
DocumentDbContext.LinkTypes.Add(dbLink);
DocumentDbContext.SaveChanges();
var dbtranslation = mapper.Map<List<Models.LinksTranslation>, List<Db.LinksTranslation>>(LinkType.linksTranslations);
dbtranslation.ForEach(i => i.LinkTypeId = dbLink.Id);
DocumentDbContext.LinksTranslations.AddRange(dbtranslation);
DocumentDbContext.SaveChanges();
var result = mapper.Map<Db.LinkType, Models.ResLinkType>(dbLink);
result.titles = CreateMultiLanguageLinkTypeObject(GetLinkTypeTranslations(result.Id, ""));
return (true, result, null);
}
return (false, null, "LinkType is already exits");
}
catch (Exception ex)
{
logger?.LogError(ex.ToString());
return (false, null, ex.Message);
}
}
public async Task<(bool IsSuccess, Models.ResLinkType LinkType, string ErrorMessage)> UpdateLinkTypeAsync(int id, Models.LinkType LinkType)
{
try
{
if (LinkType != null)
{
var existing = DocumentDbContext.LinkTypes.AsNoTracking().FirstOrDefault(x => x.Id == id);
if (existing != null)
{
var dbLink = mapper.Map<Models.LinkType, Db.LinkType>(LinkType);
DocumentDbContext.LinkTypes.Update(dbLink);
DocumentDbContext.SaveChanges();
var oldtranslations = DocumentDbContext.LinksTranslations.Where(a => a.LinkTypeId == id).ToList();
if (oldtranslations != null)
DocumentDbContext.LinksTranslations.RemoveRange(oldtranslations);
var dbtranslation = mapper.Map<List<Models.LinksTranslation>, List<Db.LinksTranslation>>(LinkType.linksTranslations);
dbtranslation.ForEach(i => i.LinkTypeId = dbLink.Id);
DocumentDbContext.LinksTranslations.AddRange(dbtranslation);
DocumentDbContext.SaveChanges();
var result = mapper.Map<Db.LinkType, Models.ResLinkType>(dbLink);
result.titles = CreateMultiLanguageLinkTypeObject(GetLinkTypeTranslations(result.Id, ""));
return (true, result, "Successful");
}
else
{
logger?.LogInformation($"{LinkType} Not found");
return (false, null, "Not Found");
}
}
else
{
logger?.LogInformation($"{LinkType} Bad Request");
return (false, null, "Bad request");
}
}
catch (Exception ex)
{
logger?.LogError(ex.ToString());
return (false, null, ex.Message);
}
}
public async Task<(bool IsSuccess, Models.ResLinkType LinkType, string ErrorMessage)> DeleteLinkTypeAsync(int id)
{
try
{
Db.LinkType LinkType = DocumentDbContext.LinkTypes.AsNoTracking().Where(a => a.Id == id).FirstOrDefault();
if (LinkType == null)
{
return (false, null, "Not Found");
}
LinkType.IsActive = false;
var result = mapper.Map<Db.LinkType, Models.ResLinkType>(LinkType);
result.titles = CreateMultiLanguageLinkTypeObject(GetLinkTypeTranslations(result.Id, ""));
DocumentDbContext.LinkTypes.Update(LinkType);
DocumentDbContext.SaveChanges();
return (true, result, $"LinkTypeId {id} deleted Successfuly");
}
catch (Exception ex)
{
logger?.LogError(ex.ToString());
return (false, null, ex.Message);
}
}
private bool LinkTypeExists(int id)
{
return DocumentDbContext.LinkTypes.AsNoTracking().Count(e => e.Id == id) > 0;
}
}
}

View File

@ -0,0 +1,178 @@
using AutoMapper;
using Azure;
using DamageAssesment.Api.DocuLinks.Db;
using DamageAssesment.Api.DocuLinks.Interfaces;
using DamageAssesment.Api.DocuLinks.Models;
using Microsoft.AspNetCore.Http;
using Microsoft.EntityFrameworkCore.Metadata.Internal;
using System.Diagnostics.Metrics;
using System.Net.Http;
using System.Security.AccessControl;
using System.Security.Principal;
namespace DamageAssesment.Api.DocuLinks.Providers
{
public class UploadService : IUploadService
{
private ILogger<UploadService> logger;
private IMapper mapper;
private string uploadpath = "";
private string Deletepath = "";
public UploadService(IConfiguration configuration, ILogger<UploadService> logger, IMapper mapper)
{
this.logger = logger;
this.mapper = mapper;
uploadpath = configuration.GetValue<string>("Fileupload:folderpath");
Deletepath = configuration.GetValue<string>("Fileupload:Deletepath");
}
public async Task<string> GetFile(string path)
{
try
{
if (System.IO.File.Exists(path))
{
return path;
}
return null; // File not found
}
catch (Exception ex)
{
// Handle or log the exception as needed
throw;
}
}
public async Task<byte[]> DownloadFile(string path)
{
try
{
if (System.IO.File.Exists(path))
{
return await System.IO.File.ReadAllBytesAsync(path);
}
return null; // File not found
}
catch (Exception ex)
{
// Handle or log the exception as needed
throw;
}
}
public Models.Doculink UploadDocument(int counter, ReqDoculink documentInfo)
{
Models.Doculink Documents = new Models.Doculink();
List<Models.DoculinkAttachments> attachments = new List<Models.DoculinkAttachments>();
try
{
string path = "", UserfileName="";
var fullDirectoryPath = Path.Combine(Directory.GetCurrentDirectory(), uploadpath);
if (!Directory.Exists(fullDirectoryPath)) //Create deirectory if does not exist
Directory.CreateDirectory(fullDirectoryPath);
if (documentInfo.Files != null)
{
foreach (var item in documentInfo.Files)
{
counter++;
if (item.IsAttachments)
{
UserfileName = Path.GetFileName(item.FileName + item.FileExtension);
var fileName = String.Format("Document_{0}{1}", counter, item.FileExtension);
path = Path.Combine(fullDirectoryPath, fileName);
File.WriteAllBytes(path, Convert.FromBase64String(item.FileContent));
}
else
path = item.url;
attachments.Add(new Models.DoculinkAttachments { docName=UserfileName,Path=path,IsAttachments=item.IsAttachments,CustomOrder=item.CustomOrder,Language=item.Language });
}
}
Documents=new Models.Doculink (){ linkTypeId = documentInfo.linkTypeId,
documentsTranslations = documentInfo.documentsTranslations,doclinksAttachments=attachments,
IsDeleted=false,CustomOrder=documentInfo.CustomOrder, IsActive =documentInfo.IsActive
};
return Documents;
}
catch (Exception ex) {
return new Models.Doculink();
}
}
public Models.Doculink UpdateDocuments(int counter, Models.Doculink document, ReqDoculink documentInfo)
{
try
{
foreach (var item in document.doclinksAttachments)
{
Movefile(item.Path);
}
var fullDirectoryPath = Path.Combine(Directory.GetCurrentDirectory(), uploadpath);
if (!Directory.Exists(fullDirectoryPath)) //Create deirectory if does not exist
Directory.CreateDirectory(fullDirectoryPath);
string path = "", UserfileName = "";
List<Models.DoculinkAttachments> attachments = new List<Models.DoculinkAttachments>();
foreach (var item in documentInfo.Files)
{
counter++;
if (item.IsAttachments)
{
UserfileName = Path.GetFileName(item.FileName+item.FileExtension);
var fileName = String.Format("Document_{0}{1}", counter, item.FileExtension);
path = Path.Combine(fullDirectoryPath, fileName);
File.WriteAllBytes(path, Convert.FromBase64String(item.FileContent));
}
else
path = item.url;
attachments.Add(new Models.DoculinkAttachments { docName = UserfileName, Path = path,IsAttachments=item.IsAttachments,CustomOrder=item.CustomOrder,Language=item.Language });
}
Models.Doculink Documents = new Models.Doculink()
{
Id = documentInfo.Id,
linkTypeId = documentInfo.linkTypeId,
documentsTranslations=documentInfo.documentsTranslations,
IsActive = documentInfo.IsActive,
IsDeleted=false,
CustomOrder = documentInfo.CustomOrder,
doclinksAttachments = attachments
};
return Documents;
}
catch (Exception ex) {
return new Models.Doculink();
}
}
public void Deletefile(string path)
{
if (path != "")
{
FileInfo file = new FileInfo(path);
if (file?.Exists??false)//check file exsit or not
{
file.Delete();
}
}
}
public void Movefile(string path)
{
if (path != "")
{
var pathToSave = Path.Combine(Directory.GetCurrentDirectory(), Deletepath);
if (!Directory.Exists(pathToSave)) //Create deirectory if does not exist
Directory.CreateDirectory(pathToSave);
FileInfo file = new FileInfo(path);
if (file?.Exists ?? false)//check file exsit or not
{
string filename = file.Name.Replace(file.Extension, " ") + DateTime.Now.ToShortDateString().Replace("/","_") + file.Extension;
file.MoveTo(pathToSave+"\\"+ filename);
}
}
}
}
}

View File

@ -0,0 +1,13 @@
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft.AspNetCore": "Warning"
}
},
"AllowedHosts": "*",
"Fileupload": {
"folderpath": "DASA_Documents/Active",
"Deletepath": "DASA_Documents/Deleted"
}
}

View File

@ -0,0 +1,30 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net6.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<IsPackable>false</IsPackable>
<IsTestProject>true</IsTestProject>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.5.0" />
<PackageReference Include="Moq" Version="4.18.4" />
<PackageReference Include="xunit" Version="2.4.2" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.5">
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
<PrivateAssets>all</PrivateAssets>
</PackageReference>
<PackageReference Include="coverlet.collector" Version="3.2.0">
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
<PrivateAssets>all</PrivateAssets>
</PackageReference>
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\DamageAssesment.Api.Employees\DamageAssesment.Api.Employees.csproj" />
</ItemGroup>
</Project>

View File

@ -0,0 +1,164 @@
using AutoMapper;
using DamageAssesment.Api.Employees.Controllers;
using DamageAssesment.Api.Employees.Db;
using DamageAssesment.Api.Employees.Interfaces;
using DamageAssesment.Api.Employees.Profiles;
using DamageAssesment.Api.Employees.Providers;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using Moq;
using Xunit;
namespace DamageAssesment.Api.Employees.Test
{
public class EmployeeServiceTest
{
[Fact(DisplayName = "Get Employees - Ok case")]
public async Task GetEmployeesAsync_ShouldReturnStatusCode200()
{
var mockEmployeeService = new Mock<IEmployeesProvider>();
var mockResponse = await MockData.getOkResponse();
mockEmployeeService.Setup(service => service.GetEmployeesAsync()).ReturnsAsync(mockResponse);
var EmployeeProvider = new EmployeesController(mockEmployeeService.Object);
var result = (OkObjectResult)await EmployeeProvider.GetEmployeesAsync();
Assert.Equal(200, result.StatusCode);
}
[Fact(DisplayName = "Get Employees - NoContent Case")]
public async Task GetEmployeesAsync_ShouldReturnStatusCode204()
{
var mockEmployeeService = new Mock<IEmployeesProvider>();
var mockResponse = await MockData.getNoContentResponse();
mockEmployeeService.Setup(service => service.GetEmployeesAsync()).ReturnsAsync(mockResponse);
var EmployeeProvider = new EmployeesController(mockEmployeeService.Object);
var result = (NoContentResult)await EmployeeProvider.GetEmployeesAsync();
Assert.Equal(204, result.StatusCode);
}
[Fact(DisplayName = "Get Employee by Id - Ok case")]
public async Task GetEmployeeAsync_ShouldReturnStatusCode200()
{
var mockEmployeeService = new Mock<IEmployeesProvider>();
var mockResponse = await MockData.getOkResponse(1);
mockEmployeeService.Setup(service => service.GetEmployeeByIdAsync(1)).ReturnsAsync(mockResponse);
var EmployeeProvider = new EmployeesController(mockEmployeeService.Object);
var result = (OkObjectResult)await EmployeeProvider.GetEmployeeByIdAsync(1);
Assert.Equal(200, result.StatusCode);
}
[Fact(DisplayName = "Get Employee by Id - NotFound case")]
public async Task GetEmployeeAsync_ShouldReturnStatusCode404()
{
var mockEmployeeService = new Mock<IEmployeesProvider>();
var mockResponse = await MockData.getNotFoundResponse();
mockEmployeeService.Setup(service => service.GetEmployeeByIdAsync(99999)).ReturnsAsync(mockResponse);
var EmployeeProvider = new EmployeesController(mockEmployeeService.Object);
var result = (NotFoundResult)await EmployeeProvider.GetEmployeeByIdAsync(99999);
Assert.Equal(404, result.StatusCode);
}
[Fact(DisplayName = "Post Employee - Ok case")]
public async Task PostEmployeeAsync_ShouldReturnStatusCode200()
{
var mockEmployeeService = new Mock<IEmployeesProvider>();
var mockResponse = await MockData.getOkResponse(1);
var mockInputEmployee = await MockData.getInputEmployeeData();
mockEmployeeService.Setup(service => service.PostEmployeeAsync(mockInputEmployee)).ReturnsAsync(mockResponse);
var EmployeeProvider = new EmployeesController(mockEmployeeService.Object);
var result = (OkObjectResult)await EmployeeProvider.CreateEmployee(mockInputEmployee);
Assert.Equal(200, result.StatusCode);
}
[Fact(DisplayName = "Post Employee - BadRequest case")]
public async Task PostEmployeeAsync_ShouldReturnStatusCode400()
{
var mockEmployeeService = new Mock<IEmployeesProvider>();
var mockInputEmployee = await MockData.getInputEmployeeData();
var mockResponse = await MockData.getBadRequestResponse();
mockEmployeeService.Setup(service => service.PostEmployeeAsync(mockInputEmployee)).ReturnsAsync(mockResponse);
var EmployeeProvider = new EmployeesController(mockEmployeeService.Object);
var result = (BadRequestObjectResult)await EmployeeProvider.CreateEmployee(mockInputEmployee);
Assert.Equal(400, result.StatusCode);
}
[Fact(DisplayName = "Put Employee - Ok case")]
public async Task PutEmployeeAsync_ShouldReturnStatusCode200()
{
var mockEmployeeService = new Mock<IEmployeesProvider>();
var mockResponse = await MockData.getOkResponse(1);
var mockInputEmployee = await MockData.getInputEmployeeData();
mockEmployeeService.Setup(service => service.UpdateEmployeeAsync(1,mockInputEmployee)).ReturnsAsync(mockResponse);
var EmployeeProvider = new EmployeesController(mockEmployeeService.Object);
var result = (OkObjectResult)await EmployeeProvider.UpdateEmployee(1,mockInputEmployee);
Assert.Equal(200, result.StatusCode);
}
[Fact(DisplayName = "Put Employee - NotFound case")]
public async Task PutEmployeeAsync_ShouldReturnStatusCode404()
{
var mockEmployeeService = new Mock<IEmployeesProvider>();
var mockResponse = await MockData.getNotFoundResponse();
var mockInputEmployee = await MockData.getInputEmployeeData();
mockEmployeeService.Setup(service => service.UpdateEmployeeAsync(1, mockInputEmployee)).ReturnsAsync(mockResponse);
var EmployeeProvider = new EmployeesController(mockEmployeeService.Object);
var result = (NotFoundObjectResult)await EmployeeProvider.UpdateEmployee(1, mockInputEmployee);
Assert.Equal(404, result.StatusCode);
}
[Fact(DisplayName = "Put Employee - BadRequest case")]
public async Task PutEmployeeAsync_ShouldReturnStatusCode400()
{
var mockEmployeeService = new Mock<IEmployeesProvider>();
var mockResponse = await MockData.getBadRequestResponse();
var mockInputEmployee = await MockData.getInputEmployeeData();
mockEmployeeService.Setup(service => service.UpdateEmployeeAsync(1, mockInputEmployee)).ReturnsAsync(mockResponse);
var EmployeeProvider = new EmployeesController(mockEmployeeService.Object);
var result = (BadRequestObjectResult)await EmployeeProvider.UpdateEmployee(1, mockInputEmployee);
Assert.Equal(400, result.StatusCode);
}
[Fact(DisplayName = "Delete Employee - Ok case")]
public async Task DeleteEmployeeAsync_ShouldReturnStatusCode200()
{
var mockEmployeeService = new Mock<IEmployeesProvider>();
var mockResponse = await MockData.getOkResponse(1);
mockEmployeeService.Setup(service => service.DeleteEmployeeAsync(1)).ReturnsAsync(mockResponse);
var EmployeeProvider = new EmployeesController(mockEmployeeService.Object);
var result = (OkObjectResult)await EmployeeProvider.DeleteEmployee(1);
Assert.Equal(200, result.StatusCode);
}
[Fact(DisplayName = "Delete Employee - NotFound case")]
public async Task DeleteEmployeeAsync_ShouldReturnStatusCode404()
{
var mockEmployeeService = new Mock<IEmployeesProvider>();
var mockResponse = await MockData.getNotFoundResponse();
mockEmployeeService.Setup(service => service.DeleteEmployeeAsync(1)).ReturnsAsync(mockResponse);
var EmployeeProvider = new EmployeesController(mockEmployeeService.Object);
var result = (NotFoundResult)await EmployeeProvider.DeleteEmployee(1);
Assert.Equal(404, result.StatusCode);
}
}
}

View File

@ -0,0 +1,49 @@
using System.Text;
namespace DamageAssesment.Api.Employees.Test
{
public class MockData
{
public static async Task<(bool, IEnumerable<Employees.Models.Employee>, string)> getOkResponse()
{
IEnumerable<Employees.Models.Employee> list = new List<Employees.Models.Employee>();
for (int i = 0; i < 10; i++)
{
list.Append(new Employees.Models.Employee { Id = i, Name = "Emoployee"+i, Email = "abc"+i+"@gmail.com", OfficePhoneNumber = "12345678", BirthDate = DateTime.Now.AddYears(-18-i), IsActive = true, PreferredLanguage = "en" });
}
return (true, list, null);
}
public static async Task<(bool, Employees.Models.Employee, string)> getOkResponse(int Id)
{
var Employees = await getOkResponse();
var Employee = Employees.Item2.FirstOrDefault(s => s.Id == Id);
return (true, Employee, null);
}
public static async Task<(bool, Employees.Models.Employee, string)> getBadRequestResponse()
{
return (false, null, "Bad Request");
}
public static async Task<(bool, Models.Employee, string)> getNotFoundResponse()
{
return (false, null, "Not Found");
}
public static async Task<(bool, IEnumerable<Models.Employee>, string)> getNoContentResponse()
{
IEnumerable<Employees.Models.Employee> list = new List<Employees.Models.Employee>();
return (false, list, null);
}
public static async Task<Models.Employee> getInputEmployeeData()
{
return new Models.Employee { Id = 1, Name = "ABC1", Email = "abc1@gmail.com", OfficePhoneNumber = "12345678", BirthDate = DateTime.Now.AddYears(-18), IsActive = true, PreferredLanguage = "en" };
}
}
}

View File

@ -0,0 +1,107 @@
using DamageAssesment.Api.Employees.Interfaces;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
namespace DamageAssesment.Api.Employees.Controllers
{
[ApiController]
public class EmployeesController : ControllerBase
{
private IEmployeesProvider EmployeeProvider;
public EmployeesController(IEmployeesProvider EmployeesProvider)
{
this.EmployeeProvider = EmployeesProvider;
}
/// <summary>
/// GET request for retrieving employees.
/// </summary>
[HttpGet("employees")]
public async Task<ActionResult> GetEmployeesAsync()
{
var result = await EmployeeProvider.GetEmployeesAsync();
if (result.IsSuccess)
{
return Ok(result.Employees);
}
return NoContent();
}
/// <summary>
/// GET request for retrieving an employee by ID.
/// </summary>
[HttpGet("employees/{id}")]
public async Task<ActionResult> GetEmployeeByIdAsync(int id)
{
var result = await EmployeeProvider.GetEmployeeByIdAsync(id);
if (result.IsSuccess)
{
return Ok(result.Employee);
}
return NotFound();
}
/// <summary>
/// PUT request for updating an existing employee.
/// </summary>
/// <param name="Employee">The updated employee object.</param>
[HttpPut("employees/{id}")]
public async Task<IActionResult> UpdateEmployee(int id, Models.Employee Employee)
{
if (Employee != null)
{
var result = await this.EmployeeProvider.UpdateEmployeeAsync(id,Employee);
if (result.IsSuccess)
{
return Ok(result.Employee);
}
if (result.ErrorMessage == "Not Found")
return NotFound(result.ErrorMessage);
return BadRequest(result.ErrorMessage);
}
return NotFound();
}
/// <summary>
/// POST request for creating a new employee.
/// </summary>
/// <param name="Employee">The employee information for creating a new employee.</param>
[HttpPost("employees")]
public async Task<IActionResult> CreateEmployee(Models.Employee Employee)
{
if (Employee != null)
{
var result = await this.EmployeeProvider.PostEmployeeAsync(Employee);
if (result.IsSuccess)
{
return Ok(result.Employee);
}
return BadRequest(result.ErrorMessage);
}
return CreatedAtRoute("DefaultApi", new { Id = Employee.Id }, Employee);
}
/// <summary>
/// DELETE request for deleting an existing employee.
/// </summary>
/// <param name="id">The ID of the employee to be deleted.</param>
[HttpDelete("employees/{id}")]
public async Task<IActionResult> DeleteEmployee(int id)
{
var result = await this.EmployeeProvider.DeleteEmployeeAsync(id);
if (result.IsSuccess)
{
return Ok(result.Employee);
}
return NotFound();
}
}
}

View File

@ -0,0 +1,18 @@
<Project Sdk="Microsoft.NET.Sdk.Web">
<PropertyGroup>
<TargetFramework>net6.0</TargetFramework>
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
<GenerateDocumentationFile>True</GenerateDocumentationFile>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="AutoMapper.Extensions.Microsoft.DependencyInjection" Version="12.0.1" />
<PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="6.0.21" />
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="7.0.5" />
<PackageReference Include="Microsoft.EntityFrameworkCore.InMemory" Version="7.0.5" />
<PackageReference Include="Swashbuckle.AspNetCore" Version="6.2.3" />
</ItemGroup>
</Project>

View File

@ -0,0 +1,27 @@
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
namespace DamageAssesment.Api.Employees.Db
{
[Table("Employees")]
public class Employee
{
[Key]
public int Id { get; set; }
[StringLength(50)]
public string EmployeeCode { get; set; }
[StringLength(50)]
public string Name { get; set; }
public DateTime BirthDate { get; set; }
[StringLength(50)]
public string OfficePhoneNumber { get; set; }
[StringLength(50)]
public string Email { get; set; }
public bool IsActive { get; set; }
public string? PreferredLanguage { get; set; } = "en";
}
}

View File

@ -0,0 +1,21 @@
using Microsoft.EntityFrameworkCore;
namespace DamageAssesment.Api.Employees.Db
{
public class EmployeeDbContext: DbContext
{
public DbSet<Db.Employee> Employees { get; set; }
public EmployeeDbContext(DbContextOptions options) : base(options)
{
}
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
modelBuilder.Entity<Employee>()
.Property(item => item.Id)
.ValueGeneratedOnAdd();
}
}
}

View File

@ -0,0 +1,12 @@
namespace DamageAssesment.Api.Employees.Interfaces
{
public interface IEmployeesProvider
{
Task<(bool IsSuccess, IEnumerable<Models.Employee> Employees, string ErrorMessage)> GetEmployeesAsync();
Task<(bool IsSuccess, Models.Employee Employee, string ErrorMessage)> GetEmployeeByIdAsync(int Id);
Task<(bool IsSuccess, Models.Employee Employee, string ErrorMessage)> PostEmployeeAsync(Models.Employee Employee);
Task<(bool IsSuccess, Models.Employee Employee, string ErrorMessage)> UpdateEmployeeAsync(int Id, Models.Employee Employee);
Task<(bool IsSuccess, Models.Employee Employee, string ErrorMessage)> DeleteEmployeeAsync(int Id);
void SeedData();
}
}

View File

@ -0,0 +1,16 @@
using System.ComponentModel.DataAnnotations;
namespace DamageAssesment.Api.Employees.Models
{
public class Employee
{
public int Id { get; set; }
public string EmployeeCode { get; set; }
public string Name { get; set; }
public DateTime BirthDate { get; set; }
public string OfficePhoneNumber { get; set; }
public string Email { get; set; }
public bool IsActive { get; set; }
public string? PreferredLanguage { get; set; } = "en";
}
}

View File

@ -0,0 +1,13 @@
using AutoMapper;
namespace DamageAssesment.Api.Employees.Profiles
{
public class EmployeesProfile:AutoMapper.Profile
{
public EmployeesProfile()
{
CreateMap<Db.Employee, Models.Employee>();
CreateMap<Models.Employee, Db.Employee>();
}
}
}

View File

@ -0,0 +1,50 @@
using DamageAssesment.Api.Employees.Db;
using DamageAssesment.Api.Employees.Interfaces;
using DamageAssesment.Api.Employees.Providers;
using Microsoft.EntityFrameworkCore;
using System.Reflection;
var builder = WebApplication.CreateBuilder(args);
// Add services to the container.
builder.Services.AddControllers();
// Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle
builder.Services.AddEndpointsApiExplorer();
//builder.Services.AddSwaggerGen();
builder.Services.AddSwaggerGen(c =>
{
// Include XML comments from your assembly
var xmlFile = $"{Assembly.GetExecutingAssembly().GetName().Name}.xml";
var xmlPath = Path.Combine(AppContext.BaseDirectory, xmlFile);
c.IncludeXmlComments(xmlPath);
});
builder.Services.AddScoped<IEmployeesProvider, EmployeesProvider>();
builder.Services.AddAutoMapper(AppDomain.CurrentDomain.GetAssemblies()); //4/30
builder.Services.AddDbContext<EmployeeDbContext>(option =>
{
option.UseInMemoryDatabase("Employees");
});
var app = builder.Build();
// Configure the HTTP request pipeline.
if (app.Environment.IsDevelopment())
{
app.UseSwagger();
app.UseSwaggerUI();
using (var serviceScope = app.Services.CreateScope())
{
var services = serviceScope.ServiceProvider;
var employeesProvider = services.GetRequiredService<IEmployeesProvider>();
employeesProvider.SeedData();
}
}
app.UseAuthorization();
app.MapControllers();
app.Run();

View File

@ -0,0 +1,31 @@
{
"$schema": "https://json.schemastore.org/launchsettings.json",
"iisSettings": {
"windowsAuthentication": false,
"anonymousAuthentication": true,
"iisExpress": {
"applicationUrl": "http://localhost:14425",
"sslPort": 0
}
},
"profiles": {
"DamageAssesment.Api.Employees": {
"commandName": "Project",
"dotnetRunMessages": true,
"launchBrowser": true,
"launchUrl": "swagger",
"applicationUrl": "http://localhost:5135",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
},
"IIS Express": {
"commandName": "IISExpress",
"launchBrowser": true,
"launchUrl": "swagger",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
}
}
}

View File

@ -0,0 +1,174 @@
using AutoMapper;
using DamageAssesment.Api.Employees.Db;
using DamageAssesment.Api.Employees.Interfaces;
using DamageAssesment.Api.Employees.Models;
using Microsoft.EntityFrameworkCore;
using System.Xml.Linq;
namespace DamageAssesment.Api.Employees.Providers
{
public class EmployeesProvider : IEmployeesProvider
{
private EmployeeDbContext EmployeeDbContext;
private ILogger<EmployeesProvider> logger;
private IMapper mapper;
public EmployeesProvider(EmployeeDbContext EmployeeDbContext, ILogger<EmployeesProvider> logger, IMapper mapper)
{
this.EmployeeDbContext = EmployeeDbContext;
this.logger = logger;
this.mapper = mapper;
// SeedData();
}
public async Task<(bool IsSuccess, IEnumerable<Models.Employee> Employees, string ErrorMessage)> GetEmployeesAsync()
{
try
{
logger?.LogInformation("Query Question");
var Employee = await EmployeeDbContext.Employees.AsNoTracking().ToListAsync();
if (Employee != null)
{
logger?.LogInformation($"{Employee.Count} Employees(s) found");
var result = mapper.Map<IEnumerable<Db.Employee>, IEnumerable<Models.Employee>>(Employee);
return (true, result, null);
}
return (false, null, "Not found");
}
catch (Exception ex)
{
logger?.LogError(ex.ToString());
return (false, null, ex.Message);
}
}
public async Task<(bool IsSuccess, Models.Employee Employee, string ErrorMessage)> GetEmployeeByIdAsync(int Id)
{
try
{
logger?.LogInformation("Query Employee");
var Employee = await EmployeeDbContext.Employees.AsNoTracking().FirstOrDefaultAsync(q => q.Id == Id);
if (Employee != null)
{
logger?.LogInformation($"{Employee} customer(s) found");
var result = mapper.Map<Db.Employee, Models.Employee>(Employee);
return (true, result, null);
}
return (false, null, "Not found");
}
catch (Exception ex)
{
logger?.LogError(ex.ToString());
return (false, null, ex.Message);
}
}
public async Task<(bool IsSuccess, Models.Employee Employee, string ErrorMessage)> PostEmployeeAsync(Models.Employee Employee)
{
try
{
Db.Employee _employee = mapper.Map<Models.Employee, Db.Employee>(Employee);
logger?.LogInformation("Query Employee");
if (!EmployeeCodeExists(Employee.EmployeeCode))
{
EmployeeDbContext.Employees.Add(_employee);
Employee.Id = _employee.Id;
EmployeeDbContext.SaveChanges();
//return (true, Employee, null);
return (true, mapper.Map<Db.Employee, Models.Employee>(_employee), null);
}
return (false, null, "Employee code is already exits");
}
catch (Exception ex)
{
logger?.LogError(ex.ToString());
return (false, null, ex.Message);
}
}
public async Task<(bool IsSuccess, Models.Employee Employee, string ErrorMessage)> UpdateEmployeeAsync(int Id, Models.Employee Employee)
{
try
{
if (Employee != null)
{
var _employee = await EmployeeDbContext.Employees.AsNoTracking().Where(s => s.Id == Id).FirstOrDefaultAsync();
if (_employee != null)
{
Db.Employee vEmployee = mapper.Map<Models.Employee, Db.Employee>(Employee);
EmployeeDbContext.Employees.Update(vEmployee);
EmployeeDbContext.SaveChanges();
Employee.Id = Id;
return (true, Employee, "Successful");
}
else
{
logger?.LogInformation($"{Employee} Not found");
return (false, null, "Not Found");
}
}
else
{
logger?.LogInformation($"{Employee} Bad Request");
return (false, null, "Bad request");
}
}
catch (Exception ex)
{
logger?.LogError(ex.ToString());
return (false, null, ex.Message);
}
}
public async Task<(bool IsSuccess, Models.Employee Employee, string ErrorMessage)> DeleteEmployeeAsync(int Id)
{
try
{
Db.Employee Employee = EmployeeDbContext.Employees.AsNoTracking().Where(a => a.Id == Id).FirstOrDefault();
if (Employee == null)
{
return (false, null, "Not Found");
}
EmployeeDbContext.Employees.Remove(Employee);
EmployeeDbContext.SaveChanges();
return (true, mapper.Map<Db.Employee, Models.Employee>(Employee), $"EmployeeId {Id} deleted Successfuly");
}
catch (Exception ex)
{
logger?.LogError(ex.ToString());
return (false, null, ex.Message);
}
}
private bool EmployeeExists(int id)
{
return EmployeeDbContext.Employees.AsNoTracking().Count(e => e.Id == id) > 0;
}
private bool EmployeeCodeExists(string employeeCode)
{
return EmployeeDbContext.Employees.AsNoTracking().Count(e => e.EmployeeCode.ToLower() == employeeCode.ToLower()) > 0;
}
public void SeedData()
{
if (!EmployeeDbContext.Employees.Any())
{
EmployeeDbContext.Employees.Add(new Db.Employee() { EmployeeCode = "10101", Name = "David", Email = "david@gmail.com", OfficePhoneNumber = "12345678", BirthDate = DateTime.Now.AddYears(-18), IsActive = true, PreferredLanguage = "en" });
EmployeeDbContext.Employees.Add(new Db.Employee() { EmployeeCode = "20202", Name = "Smith", Email = "smith@gmail.com", OfficePhoneNumber = "12345678", BirthDate = DateTime.Now.AddYears(-22), IsActive = true, PreferredLanguage = "fr" });
//EmployeeDbContext.Employees.Add(new Db.Employee() { Id = 3, EmployeeCode = "Emp3", Name = "ABC3", Email = "abc3@gmail.com", OfficePhoneNumber = "12345678", BirthDate = DateTime.Now.AddYears(-30), IsActive = true, PreferredLanguage = "fr" });
//EmployeeDbContext.Employees.Add(new Db.Employee() { Id = 4, EmployeeCode = "Emp4", Name = "ABC4", Email = "abc4@gmail.com", OfficePhoneNumber = "12345678", BirthDate = DateTime.Now.AddYears(-20), IsActive = true, PreferredLanguage = "en" });
//EmployeeDbContext.Employees.Add(new Db.Employee() { Id = 5, EmployeeCode = "Emp5", Name = "ABC5", Email = "abc5@gmail.com", OfficePhoneNumber = "12345678", BirthDate = DateTime.Now.AddYears(-23), IsActive = true, PreferredLanguage = "es" });
//EmployeeDbContext.Employees.Add(new Db.Employee() { Id = 6, EmployeeCode = "Emp6", Name = "ABC6", Email = "abc6@gmail.com", OfficePhoneNumber = "12345678", BirthDate = DateTime.Now.AddYears(-32), IsActive = true, PreferredLanguage = "es" });
EmployeeDbContext.SaveChanges();
}
}
}
}

View File

@ -0,0 +1,17 @@
{
"JwtSettings": {
"securitykey": "bWlhbWkgZGFkZSBzY2hvb2xzIHNlY3JldCBrZXk="
},
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft.AspNetCore": "Warning"
}
},
"AllowedHosts": "*",
"settings": {
"endpoint1": "xxx",
"endpoint2": "xxx",
"endpoint3": "xxx"
}
}

View File

@ -0,0 +1,30 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net6.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<IsPackable>false</IsPackable>
<IsTestProject>true</IsTestProject>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.5.0" />
<PackageReference Include="Moq" Version="4.18.4" />
<PackageReference Include="xunit" Version="2.4.2" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.5">
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
<PrivateAssets>all</PrivateAssets>
</PackageReference>
<PackageReference Include="coverlet.collector" Version="3.2.0">
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
<PrivateAssets>all</PrivateAssets>
</PackageReference>
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\DamageAssesment.Api.Locations\DamageAssesment.Api.Locations.csproj" />
</ItemGroup>
</Project>

View File

@ -0,0 +1,302 @@
using DamageAssesment.Api.Locations.Controllers;
using DamageAssesment.Api.Locations.Interfaces;
using Microsoft.AspNetCore.Mvc;
using Moq;
using Xunit;
namespace DamageAssesment.Api.Locations.Test
{
public class LocationsServiceTest
{
//Test for locations
[Fact(DisplayName = "Get Locations - Ok case")]
public async Task GetLocationsAsync_ShouldReturnStatusCode200()
{
var mockLocationService = new Mock<ILocationsProvider>();
var mockResponse = await MockData.getOkResponseLocation();
mockLocationService.Setup(service => service.GetLocationsAsync()).ReturnsAsync(mockResponse);
var locationProvider = new LocationsController(mockLocationService.Object);
var result = (OkObjectResult)await locationProvider.GetLocationsAsync();
Assert.Equal(200, result.StatusCode);
}
[Fact(DisplayName = "Get Locations - NoContent Case")]
public async Task GetLocationsAsync_ShouldReturnStatusCode204()
{
var mockLocationService = new Mock<ILocationsProvider>();
var mockResponse = await MockData.getNotFoundResponseLocation();
mockLocationService.Setup(service => service.GetLocationsAsync()).ReturnsAsync(mockResponse);
var locationProvider = new LocationsController(mockLocationService.Object);
var result = (NoContentResult)await locationProvider.GetLocationsAsync();
Assert.Equal(204, result.StatusCode);
}
[Fact(DisplayName = "Get Locations by Id- Ok case")]
public async Task GetLocationsByIdAsync_ShouldReturnStatusCode200()
{
var mockLocationService = new Mock<ILocationsProvider>();
var mockResponse = await MockData.getOkResponseLocation(1);
mockLocationService.Setup(service => service.GetLocationByIdAsync(1)).ReturnsAsync(mockResponse);
var locationProvider = new LocationsController(mockLocationService.Object);
var result = (OkObjectResult)await locationProvider.GetLocationByIdAsync(1);
Assert.Equal(200, result.StatusCode);
}
[Fact(DisplayName = "Get Locations By Id - NoFound Case")]
public async Task GetLocationsByIdAsync_ShouldReturnStatusCode404()
{
var mockLocationService = new Mock<ILocationsProvider>();
var mockResponse = await MockData.getLocationNotFoundResponse();
mockLocationService.Setup(service => service.GetLocationByIdAsync(1)).ReturnsAsync(mockResponse);
var locationProvider = new LocationsController(mockLocationService.Object);
var result = (NotFoundResult)await locationProvider.GetLocationByIdAsync(1);
Assert.Equal(404, result.StatusCode);
}
[Fact(DisplayName = "Post Location - Ok case")]
public async Task PostLocationAsync_ShouldReturnStatusCode200()
{
var mockLocationService = new Mock<ILocationsProvider>();
var mockResponse = await MockData.getOkResponseLocation(1);
var mockInputLocation = new Models.Location { Id = 1, RegionId = 1, Name = "Location 1", SchoolType = "US", MaintenanceCenter = "1" };
mockLocationService.Setup(service => service.PostLocationAsync(mockInputLocation)).ReturnsAsync(mockResponse);
var locationProvider = new LocationsController(mockLocationService.Object);
var result = (OkObjectResult)await locationProvider.CreateLocation(mockInputLocation);
Assert.Equal(200, result.StatusCode);
}
[Fact(DisplayName = "Post Location - BadRequest case")]
public async Task PostLocationAsync_ShouldReturnStatusCode400()
{
var mockLocationService = new Mock<ILocationsProvider>();
var mockResponse = await MockData.getLocationNotFoundResponse();
var mockInputLocation = new Models.Location { Id = 1, RegionId = 1, Name = "Location 1", SchoolType = "US", MaintenanceCenter = "1" };
mockLocationService.Setup(service => service.PostLocationAsync(mockInputLocation)).ReturnsAsync(mockResponse);
var locationProvider = new LocationsController(mockLocationService.Object);
var result = (BadRequestObjectResult)await locationProvider.CreateLocation(mockInputLocation);
Assert.Equal(400, result.StatusCode);
}
[Fact(DisplayName = "Put Location - Ok case")]
public async Task PutLocationAsync_ShouldReturnStatusCode200()
{
var mockLocationService = new Mock<ILocationsProvider>();
var mockResponse = await MockData.getLocation(true, "update success");
var mockInputLocation = new Models.Location { Id = 1, LocationCode ="Loc1", RegionId = 1, Name = "Location 1", SchoolType = "US", MaintenanceCenter = "1" };
mockLocationService.Setup(service => service.UpdateLocationAsync(1,mockInputLocation)).ReturnsAsync(mockResponse);
var locationProvider = new LocationsController(mockLocationService.Object);
var result = (OkObjectResult)await locationProvider.UpdateLocation(1,mockInputLocation);
Assert.Equal(200, result.StatusCode);
}
[Fact(DisplayName = "Put Location - NotFound case")]
public async Task PutLocationAsync_ShouldReturnStatusCode404()
{
var mockLocationService = new Mock<ILocationsProvider>();
var mockResponse = await MockData.getLocation(false, null);
var mockInputLocation = new Models.Location { Id = 1, RegionId = 1, Name = "Location 1", SchoolType = "US", MaintenanceCenter = "1" };
mockLocationService.Setup(service => service.UpdateLocationAsync(1,mockInputLocation)).ReturnsAsync(mockResponse);
var locationProvider = new LocationsController(mockLocationService.Object);
var result = (NotFoundResult)await locationProvider.UpdateLocation(1,mockInputLocation);
Assert.Equal(404, result.StatusCode);
}
[Fact(DisplayName = "Delete Location - Ok case")]
public async Task DeleteLocationAsync_ShouldReturnStatusCode200()
{
var mockLocationService = new Mock<ILocationsProvider>();
var mockResponse = await MockData.getLocation(true, "delete success");
mockLocationService.Setup(service => service.DeleteLocationAsync(1)).ReturnsAsync(mockResponse);
var locationProvider = new LocationsController(mockLocationService.Object);
var result = (OkObjectResult)await locationProvider.DeleteLocation(1);
Assert.Equal(200, result.StatusCode);
}
[Fact(DisplayName = "Delete Location - NotFound case")]
public async Task DeleteLocationAsync_ShouldReturnStatusCode404()
{
var mockLocationService = new Mock<ILocationsProvider>();
var mockResponse = await MockData.getLocation(false, null);
mockLocationService.Setup(service => service.DeleteLocationAsync(1)).ReturnsAsync(mockResponse);
var locationProvider = new LocationsController(mockLocationService.Object);
var result = (NotFoundResult)await locationProvider.DeleteLocation(1);
Assert.Equal(404, result.StatusCode);
}
//Tests for regions
[Fact(DisplayName = "Get Regions - Ok case")]
public async Task GetRegionsAsync_ShouldReturnStatusCode200()
{
var mockRegionService = new Mock<IRegionsProvider>();
var mockResponse = await MockData.getOkResponse();
mockRegionService.Setup(service => service.GetRegionsAsync()).ReturnsAsync(mockResponse);
var regionProvider = new RegionsController(mockRegionService.Object);
var result = (OkObjectResult)await regionProvider.GetRegionsAsync();
Assert.Equal(200, result.StatusCode);
}
[Fact(DisplayName = "Get Regions - NoContent Case")]
public async Task GetRegionsAsync_ShouldReturnStatusCode204()
{
var mockRegionService = new Mock<IRegionsProvider>();
var mockResponse = await MockData.getNoContentResponse();
mockRegionService.Setup(service => service.GetRegionsAsync()).ReturnsAsync(mockResponse);
var regionProvider = new RegionsController(mockRegionService.Object);
var result = (NoContentResult)await regionProvider.GetRegionsAsync();
Assert.Equal(204, result.StatusCode);
}
[Fact(DisplayName = "Get Region by Id - Ok case")]
public async Task GetRegionAsync_ShouldReturnStatusCode200()
{
var mockRegionService = new Mock<IRegionsProvider>();
var mockResponse = await MockData.getOkResponse(1);
mockRegionService.Setup(service => service.GetRegionByIdAsync(1)).ReturnsAsync(mockResponse);
var regionProvider = new RegionsController(mockRegionService.Object);
var result = (OkObjectResult)await regionProvider.GetRegionAsync(1);
Assert.Equal(200, result.StatusCode);
}
[Fact(DisplayName = "Get Region by Id - NotFound case")]
public async Task GetRegionAsync_ShouldReturnStatusCode404()
{
var mockRegionService = new Mock<IRegionsProvider>();
var mockResponse = await MockData.getNotFoundResponse();
mockRegionService.Setup(service => service.GetRegionByIdAsync(99999)).ReturnsAsync(mockResponse);
var regionProvider = new RegionsController(mockRegionService.Object);
var result = (NotFoundResult)await regionProvider.GetRegionAsync(99);
Assert.Equal(404, result.StatusCode);
}
[Fact(DisplayName = "Post Region - Ok case")]
public async Task PostRegionAsync_ShouldReturnStatusCode200()
{
var mockRegionService = new Mock<IRegionsProvider>();
var mockResponse = await MockData.getOkResponse(1);
var mockInputRegion = await MockData.getInputRegionData();
mockRegionService.Setup(service => service.PostRegionAsync(mockInputRegion)).ReturnsAsync(mockResponse);
var regionProvider = new RegionsController(mockRegionService.Object);
var result = (OkObjectResult)await regionProvider.PostRegionAsync(mockInputRegion);
Assert.Equal(200, result.StatusCode);
}
[Fact(DisplayName = "Post Region - BadRequest case")]
public async Task PostRegionAsync_ShouldReturnStatusCode400()
{
var mockRegionService = new Mock<IRegionsProvider>();
var mockResponse = await MockData.getBadRequestResponse();
var mockInputRegion = await MockData.getInputRegionData();
mockRegionService.Setup(service => service.PostRegionAsync(mockInputRegion)).ReturnsAsync(mockResponse);
var regionProvider = new RegionsController(mockRegionService.Object);
var result = (BadRequestObjectResult)await regionProvider.PostRegionAsync(mockInputRegion);
Assert.Equal(400, result.StatusCode);
}
[Fact(DisplayName = "Put Region - Ok case")]
public async Task PutRegionAsync_ShouldReturnStatusCode200()
{
var mockRegionService = new Mock<IRegionsProvider>();
var mockResponse = await MockData.getOkResponse(1);
var mockInputRegion = await MockData.getInputRegionData();
mockRegionService.Setup(service => service.PutRegionAsync(1,mockInputRegion)).ReturnsAsync(mockResponse);
var regionProvider = new RegionsController(mockRegionService.Object);
var result = (OkObjectResult)await regionProvider.PutRegionAsync(1,mockInputRegion);
Assert.Equal(200, result.StatusCode);
}
[Fact(DisplayName = "Put Region - NotFound case")]
public async Task PutRegionAsync_ShouldReturnStatusCode404()
{
var mockRegionService = new Mock<IRegionsProvider>();
var mockResponse = await MockData.getNotFoundResponse();
var mockInputRegion = await MockData.getInputRegionData();
mockRegionService.Setup(service => service.PutRegionAsync(1, mockInputRegion)).ReturnsAsync(mockResponse);
var regionProvider = new RegionsController(mockRegionService.Object);
var result = (NotFoundObjectResult)await regionProvider.PutRegionAsync(1,mockInputRegion);
Assert.Equal(404, result.StatusCode);
}
[Fact(DisplayName = "Put Region - BadRequest case")]
public async Task PutRegionyAsync_ShouldReturnStatusCode400()
{
var mockRegionService = new Mock<IRegionsProvider>();
var mockResponse = await MockData.getBadRequestResponse();
var mockInputRegion = await MockData.getInputRegionData();
mockRegionService.Setup(service => service.PutRegionAsync(1, mockInputRegion)).ReturnsAsync(mockResponse);
var regionProvider = new RegionsController(mockRegionService.Object);
var result = (BadRequestObjectResult)await regionProvider.PutRegionAsync(1, mockInputRegion);
Assert.Equal(400, result.StatusCode);
}
[Fact(DisplayName = "Delete Region - Ok case")]
public async Task DeleteRegionAsync_ShouldReturnStatusCode200()
{
var mockRegionService = new Mock<IRegionsProvider>();
var mockResponse = await MockData.getOkResponse(1);
mockRegionService.Setup(service => service.DeleteRegionAsync(1)).ReturnsAsync(mockResponse);
var regionProvider = new RegionsController(mockRegionService.Object);
var result = (OkObjectResult)await regionProvider.DeleteRegionAsync(1);
Assert.Equal(200, result.StatusCode);
}
[Fact(DisplayName = "Delete Region - NotFound case")]
public async Task DeleteRegionAsync_ShouldReturnStatusCode404()
{
var mockRegionService = new Mock<IRegionsProvider>();
var mockResponse = await MockData.getNotFoundResponse();
mockRegionService.Setup(service => service.DeleteRegionAsync(1)).ReturnsAsync(mockResponse);
var regionProvider = new RegionsController(mockRegionService.Object);
var result = (NotFoundResult)await regionProvider.DeleteRegionAsync(1);
Assert.Equal(404, result.StatusCode);
}
}
}

View File

@ -0,0 +1,80 @@
using System.Text;
namespace DamageAssesment.Api.Locations.Test
{
public class MockData
{
public static async Task<(bool, IEnumerable<Locations.Models.Region>, string)> getOkResponse()
{
IEnumerable<Locations.Models.Region> list = new List<Locations.Models.Region>();
for (int i = 0; i < 10; i++)
{
list.Append(new Locations.Models.Region { Id = i, Abbreviation = "AB" + i, Name = "Region " + i });
}
return (true, list, null);
}
public static async Task<(bool, Locations.Models.Region, string)> getOkResponse(int Id)
{
var regions = await getOkResponse();
var region = regions.Item2.FirstOrDefault(s => s.Id == Id);
return (true, region, null);
}
public static async Task<(bool, IEnumerable<Models.Location>, string)> getOkResponseLocation()
{
IEnumerable<Locations.Models.Location> list = new List<Models.Location>();
for (int i = 0; i < 10; i++)
{
list.Append(new Locations.Models.Location { Id = i, RegionId = i, Name = "Location" });
}
return (true, list, null);
}
public static async Task<(bool, IEnumerable<Models.Location>, string)> getNotFoundResponseLocation()
{
return (false, null, null);
}
public static async Task<(bool, Models.Location, string)> getOkResponseLocation(int Id)
{
var locations = await getOkResponseLocation();
var location = locations.Item2.FirstOrDefault(s => s.Id == Id);
return (true, location, null);
}
public static async Task<(bool, Models.Location, string)> getLocation(bool value, string message)
{
var location = new Models.Location { Id = 1, LocationCode = "Loc1", RegionId = 1, Name = "Location 1", SchoolType = "US", MaintenanceCenter = "1" };
return (value, location, message);
}
public static async Task<(bool, Locations.Models.Location, string)> getLocationNotFoundResponse()
{
return (false, null, "Not Found");
}
public static async Task<(bool, Locations.Models.Region, string)> getBadRequestResponse()
{
return (false, null, "Bad Request");
}
public static async Task<(bool, Locations.Models.Region, string)> getNotFoundResponse()
{
return (false, null, "Not Found");
}
public static async Task<(bool, IEnumerable<Locations.Models.Region>, string)> getNoContentResponse()
{
IEnumerable<Locations.Models.Region> list = new List<Locations.Models.Region>();
return (false, list, null);
}
public static async Task<Locations.Models.Region> getInputRegionData()
{
return new Locations.Models.Region { Id = 99999, Name = "Region 99", Abbreviation = "A99" };
}
}
}

View File

@ -0,0 +1,98 @@
using DamageAssesment.Api.Locations.Interfaces;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
namespace DamageAssesment.Api.Locations.Controllers
{
[ApiController]
public class LocationsController : ControllerBase
{
private ILocationsProvider LocationProvider;
public LocationsController(ILocationsProvider LocationsProvider)
{
this.LocationProvider = LocationsProvider;
}
/// <summary>
/// Get all locations.
/// </summary>
[HttpGet("locations")]
public async Task<ActionResult> GetLocationsAsync()
{
var result = await LocationProvider.GetLocationsAsync();
if (result.IsSuccess)
{
return Ok(result.Locations);
}
return NoContent();
}
/// <summary>
/// Get all locations based on locationdId.
/// </summary>
[HttpGet("locations/{id}")]
public async Task<ActionResult> GetLocationByIdAsync(int id)
{
var result = await LocationProvider.GetLocationByIdAsync(id);
if (result.IsSuccess)
{
return Ok(result.Location);
}
return NotFound();
}
/// <summary>
/// Update a Location.
/// </summary>
[HttpPut("locations/{id}")]
public async Task<IActionResult> UpdateLocation(int id, Models.Location Location)
{
if (Location != null)
{
var result = await this.LocationProvider.UpdateLocationAsync(id, Location);
if (result.IsSuccess)
{
return Ok(result.Location);
}
return NotFound();
}
return NotFound();
}
/// <summary>
/// Save a new location.
/// </summary>
[HttpPost("locations")]
public async Task<IActionResult> CreateLocation(Models.Location Location)
{
if (Location != null)
{
var result = await this.LocationProvider.PostLocationAsync(Location);
if (result.IsSuccess)
{
return Ok(result.Location);
}
return BadRequest(result.ErrorMessage);
}
return BadRequest();
}
/// <summary>
/// Delete an existing location.
/// </summary>
[HttpDelete("locations/{id}")]
public async Task<IActionResult> DeleteLocation(int id)
{
var result = await this.LocationProvider.DeleteLocationAsync(id);
if (result.IsSuccess)
{
return Ok(result.Location);
}
return NotFound();
}
}
}

View File

@ -0,0 +1,90 @@
using DamageAssesment.Api.Locations.Interfaces;
using Microsoft.AspNetCore.Mvc;
namespace DamageAssesment.Api.Locations.Controllers
{
[ApiController]
public class RegionsController : ControllerBase
{
private readonly IRegionsProvider regionProvider;
public RegionsController(IRegionsProvider regionProvider)
{
this.regionProvider = regionProvider;
}
/// <summary>
/// Get all regions.2
/// </summary>
[HttpGet("regions")]
public async Task<ActionResult> GetRegionsAsync()
{
var result = await regionProvider.GetRegionsAsync();
if (result.IsSuccess)
{
return Ok(result.Regions);
}
return NoContent();
}
/// <summary>
/// GET request for retrieving a region by its ID.
/// </summary>
[HttpGet("regions/{id}")]
public async Task<ActionResult> GetRegionAsync(int id)
{
var result = await this.regionProvider.GetRegionByIdAsync(id);
if (result.IsSuccess)
{
return Ok(result.Region);
}
return NotFound();
}
/// <summary>
/// POST request for creating a new region.
/// </summary>
[HttpPost("regions")]
public async Task<ActionResult> PostRegionAsync(Models.Region region)
{
var result = await this.regionProvider.PostRegionAsync(region);
if (result.IsSuccess)
{
return Ok(result.Region);
}
return BadRequest(result.ErrorMessage);
}
/// <summary>
/// PUT request for updating an existing region.
/// </summary>
[HttpPut("regions/{id}")]
public async Task<ActionResult> PutRegionAsync(int id, Models.Region region)
{
var result = await this.regionProvider.PutRegionAsync(id,region);
if (result.IsSuccess)
{
return Ok(result.Region);
}
if (result.ErrorMessage.Equals("Not Found"))
return NotFound(result.ErrorMessage);
return BadRequest(result.ErrorMessage);
}
/// <summary>
/// DELETE request for deleting a region based on ID.
/// </summary>
[HttpDelete("regions/{id}")]
public async Task<ActionResult> DeleteRegionAsync(int id)
{
var result = await this.regionProvider.DeleteRegionAsync(id);
if (result.IsSuccess)
{
return Ok(result.Region);
}
return NotFound();
}
}
}

View File

@ -0,0 +1,18 @@
<Project Sdk="Microsoft.NET.Sdk.Web">
<PropertyGroup>
<TargetFramework>net6.0</TargetFramework>
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
<GenerateDocumentationFile>True</GenerateDocumentationFile>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="AutoMapper.Extensions.Microsoft.DependencyInjection" Version="12.0.1" />
<PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="6.0.21" />
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="7.0.5" />
<PackageReference Include="Microsoft.EntityFrameworkCore.InMemory" Version="7.0.5" />
<PackageReference Include="Swashbuckle.AspNetCore" Version="6.2.3" />
</ItemGroup>
</Project>

View File

@ -0,0 +1,30 @@
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
namespace DamageAssesment.Api.Locations.Db
{
[Table("Locations")]
public class Location
{
[Key]
public int Id { get; set; }
[ForeignKey("Region")]
public int RegionId { get; set; }
[StringLength(4)]
public string LocationCode { get; set; }
[StringLength(50)]
public string Name { get; set; }
[StringLength(4)]
public string MaintenanceCenter { get; set; }
[StringLength(2)]
public string SchoolType { get; set; }
public int? DataValue { get; set; }
public int? Enrollment { get; set; }
public double? Longitute { get; set; }
public double? Latitude { get; set; }
}
}

View File

@ -0,0 +1,26 @@
using Microsoft.EntityFrameworkCore;
namespace DamageAssesment.Api.Locations.Db
{
public class LocationDbContext : DbContext
{
public DbSet<Db.Location> Locations { get; set; }
public DbSet<Db.Region> Regions { get; set; }
public LocationDbContext(DbContextOptions options) : base(options)
{
}
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
modelBuilder.Entity<Location>()
.Property(item => item.Id)
.ValueGeneratedOnAdd();
modelBuilder.Entity<Region>()
.Property(item => item.Id)
.ValueGeneratedOnAdd();
}
}
}

View File

@ -0,0 +1,18 @@
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
namespace DamageAssesment.Api.Locations.Db
{
[Table("Regions")]
public class Region
{
[Key]
public int Id { get; set; }
[StringLength(50)]
public string Name { get; set; }
[StringLength(5)]
public string Abbreviation { get; set; }
}
}

View File

@ -0,0 +1,14 @@
using DamageAssesment.Api.Locations.Db;
namespace DamageAssesment.Api.Locations.Interfaces
{
public interface ILocationsProvider
{
Task<(bool IsSuccess, IEnumerable<Models.Location> Locations, string ErrorMessage)> GetLocationsAsync();
Task<(bool IsSuccess, Models.Location Location, string ErrorMessage)> GetLocationByIdAsync(int Id);
Task<(bool IsSuccess, Models.Location Location, string ErrorMessage)> PostLocationAsync(Models.Location Location);
Task<(bool IsSuccess, Models.Location Location, string ErrorMessage)> UpdateLocationAsync(int Id, Models.Location Location);
Task<(bool IsSuccess, Models.Location Location, string ErrorMessage)> DeleteLocationAsync(int Id);
void SeedData();
}
}

View File

@ -0,0 +1,12 @@
namespace DamageAssesment.Api.Locations.Interfaces
{
public interface IRegionsProvider
{
Task<(bool IsSuccess, IEnumerable<Models.Region> Regions, string ErrorMessage)> GetRegionsAsync();
Task<(bool IsSuccess, Models.Region Region, string ErrorMessage)> GetRegionByIdAsync(int Id);
Task<(bool IsSuccess, Models.Region Region, string ErrorMessage)> PostRegionAsync(Models.Region region);
Task<(bool IsSuccess, Models.Region Region, string ErrorMessage)> PutRegionAsync(int Id, Models.Region region);
Task<(bool IsSuccess, Models.Region Region, string ErrorMessage)> DeleteRegionAsync(int Id);
void SeedData();
}
}

View File

@ -0,0 +1,19 @@
using System.ComponentModel.DataAnnotations;
namespace DamageAssesment.Api.Locations.Models
{
public class Location
{
[Key]
public int Id { get; set; }
public int RegionId { get; set; }
public string LocationCode { get; set; }
public string Name { get; set; }
public string MaintenanceCenter { get; set; }
public string SchoolType { get; set; }
public int? DataValue { get; set; }
public int? Enrollment { get; set; }
public double? Longitute { get; set; }
public double? Latitude { get; set; }
}
}

View File

@ -0,0 +1,11 @@
using System.ComponentModel.DataAnnotations;
namespace DamageAssesment.Api.Locations.Models
{
public class Region
{
public int Id { get; set; }
public string Name { get; set; }
public string Abbreviation { get; set; }
}
}

View File

@ -0,0 +1,11 @@
namespace DamageAssesment.Api.Locations.Profiles
{
public class LocationProfile : AutoMapper.Profile
{
public LocationProfile()
{
CreateMap<Db.Location, Models.Location>();
CreateMap<Models.Location, Db.Location>();
}
}
}

View File

@ -0,0 +1,11 @@
namespace DamageAssesment.Api.Locations.Profiles
{
public class RegionProfile : AutoMapper.Profile
{
public RegionProfile()
{
CreateMap<Db.Region, Models.Region>();
CreateMap<Models.Region, Db.Region>();
}
}
}

View File

@ -0,0 +1,51 @@
using DamageAssesment.Api.Locations.Db;
using DamageAssesment.Api.Locations.Interfaces;
using DamageAssesment.Api.Locations.Providers;
using Microsoft.EntityFrameworkCore;
using System.Reflection;
var builder = WebApplication.CreateBuilder(args);
// Add services to the container.
builder.Services.AddControllers();
// Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle
builder.Services.AddEndpointsApiExplorer();
//builder.Services.AddSwaggerGen();
builder.Services.AddSwaggerGen(c =>
{
// Include XML comments from your assembly
var xmlFile = $"{Assembly.GetExecutingAssembly().GetName().Name}.xml";
var xmlPath = Path.Combine(AppContext.BaseDirectory, xmlFile);
c.IncludeXmlComments(xmlPath);
});
builder.Services.AddScoped<ILocationsProvider, LocationsProvider>();
builder.Services.AddScoped<IRegionsProvider, RegionsProvider>();
builder.Services.AddAutoMapper(AppDomain.CurrentDomain.GetAssemblies()); //4/30
builder.Services.AddDbContext<LocationDbContext>(option =>
{
option.UseInMemoryDatabase("Locations");
});
var app = builder.Build();
// Configure the HTTP request pipeline.
if (app.Environment.IsDevelopment())
{
app.UseSwagger();
app.UseSwaggerUI();
using (var serviceScope = app.Services.CreateScope())
{
var services = serviceScope.ServiceProvider;
var locationProvider = services.GetRequiredService<ILocationsProvider>();
var regionProvider = services.GetRequiredService<IRegionsProvider>();
locationProvider.SeedData();
regionProvider.SeedData();
}
}
app.UseAuthorization();
app.MapControllers();
app.Run();

View File

@ -0,0 +1,31 @@
{
"$schema": "https://json.schemastore.org/launchsettings.json",
"iisSettings": {
"windowsAuthentication": false,
"anonymousAuthentication": true,
"iisExpress": {
"applicationUrl": "http://localhost:20458",
"sslPort": 0
}
},
"profiles": {
"DamageAssesment.Api.Locations": {
"commandName": "Project",
"dotnetRunMessages": true,
"launchBrowser": true,
"launchUrl": "swagger",
"applicationUrl": "http://localhost:5213",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
},
"IIS Express": {
"commandName": "IISExpress",
"launchBrowser": true,
"launchUrl": "swagger",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
}
}
}

View File

@ -0,0 +1,166 @@
using AutoMapper;
using DamageAssesment.Api.Locations.Db;
using DamageAssesment.Api.Locations.Interfaces;
using DamageAssesment.Api.Locations.Models;
using Microsoft.EntityFrameworkCore;
namespace DamageAssesment.Api.Locations.Providers
{
public class LocationsProvider : ILocationsProvider
{
private LocationDbContext locationDbContext;
private ILogger<LocationsProvider> logger;
private IMapper mapper;
public LocationsProvider(LocationDbContext locationDbContext, ILogger<LocationsProvider> logger, IMapper mapper)
{
this.locationDbContext = locationDbContext;
this.logger = logger;
this.mapper = mapper;
// SeedData();
}
public async Task<(bool IsSuccess, IEnumerable<Models.Location> Locations, string ErrorMessage)> GetLocationsAsync()
{
try
{
logger?.LogInformation("Query Location");
var locations = await locationDbContext.Locations.AsNoTracking().ToListAsync();
if (locations != null)
{
int maxenrollment = (int)locations.Max(a => a.Enrollment);
foreach (Db.Location item in locations) { item.DataValue = GetHeatmapdata(item.Enrollment, maxenrollment); }
logger?.LogInformation($"{locations.Count} Locations(s) found");
var result = mapper.Map<IEnumerable<Db.Location>, IEnumerable<Models.Location>>(locations);
return (true, result, null);
}
return (false, null, "Not found");
}
catch (Exception ex)
{
logger?.LogError(ex.ToString());
return (false, null, ex.Message);
}
}
public async Task<(bool IsSuccess, Models.Location Location, string ErrorMessage)> GetLocationByIdAsync(int Id)
{
try
{
logger?.LogInformation("Query Location");
int maxenrollment = (int)await locationDbContext.Locations.AsNoTracking().MaxAsync(a => a.Enrollment);
var location = await locationDbContext.Locations.AsNoTracking().FirstOrDefaultAsync(q => q.Id == Id);
if (location != null)
{if(maxenrollment>0)
location.DataValue = GetHeatmapdata(location.Enrollment, maxenrollment);
logger?.LogInformation($"{location} found");
var result = mapper.Map<Db.Location, Models.Location>(location);
return (true, result, null);
}
return (false, null, "Not found");
}
catch (Exception ex)
{
logger?.LogError(ex.ToString());
return (false, null, ex.Message);
}
}
private int GetHeatmapdata(int? enrollment,int maxenrollment)
{
return (enrollment != null ? enrollment.Value : 0) * 100 / maxenrollment;
}
public async Task<(bool IsSuccess, Models.Location Location, string ErrorMessage)> PostLocationAsync(Models.Location location)
{
try
{
if (!LocationCodeExists(location.LocationCode))
{
Db.Location _location = mapper.Map<Models.Location, Db.Location>(location);
locationDbContext.Locations.Add(_location);
await locationDbContext.SaveChangesAsync();
location.Id = _location.Id;
return (true, location, null);
}
else
{
return (false, null, "Location code is already exists");
}
}
catch (Exception ex)
{
logger?.LogError(ex.ToString());
return (false, null, ex.Message);
}
}
public async Task<(bool IsSuccess, Models.Location Location, string ErrorMessage)> UpdateLocationAsync(int Id, Models.Location location)
{
try
{
if (LocationExists(Id))
{
Db.Location _location = mapper.Map<Models.Location, Db.Location>(location);
locationDbContext.Entry(_location).State = EntityState.Modified;
await locationDbContext.SaveChangesAsync();
return (true, location, "Record updated successfully");
}
else
{
return (false, null, "Location is not exists");
}
}
catch (Exception ex)
{
logger?.LogError(ex.ToString());
return (false, null, ex.Message);
}
}
public async Task<(bool IsSuccess, Models.Location Location, string ErrorMessage)> DeleteLocationAsync(int Id)
{
try
{
Db.Location location = locationDbContext.Locations.AsNoTracking().Where(a => a.Id == Id).FirstOrDefault();
if (location == null)
{
return (false, null, "record not found");
}
locationDbContext.Locations.Remove(location);
await locationDbContext.SaveChangesAsync();
return (true, mapper.Map<Db.Location, Models.Location>(location), "Record deleted successfully");
}
catch (Exception ex)
{
logger?.LogError(ex.ToString());
return (false, null, ex.Message);
}
}
private bool LocationExists(int id)
{
return locationDbContext.Locations.AsNoTracking().Count(e => e.Id == id) > 0;
}
private bool LocationCodeExists(string locationCode)
{
return locationDbContext.Locations.AsNoTracking().Count(e => e.LocationCode.ToLower() == locationCode.ToLower()) > 0;
}
public void SeedData()
{
if (!locationDbContext.Locations.Any())
{
locationDbContext.Locations.Add(new Db.Location() { LocationCode = "0091", RegionId = 5, Name = "BOB GRAHAM EDUCATION CENTER", MaintenanceCenter = "1", SchoolType = "K8", DataValue = 25,Enrollment=780,Latitude= 25.83604,Longitute= -80.21618 });
locationDbContext.Locations.Add(new Db.Location() { LocationCode = "0092", RegionId = 1, Name = "NORMAN S. EDELCUP/SUNNY ISLES BEACH K-8", MaintenanceCenter = "1", SchoolType = "K8", DataValue = 46, Enrollment = 650, Latitude = 20.83604, Longitute = -40.21618 });
locationDbContext.Locations.Add(new Db.Location() { LocationCode = "7511", RegionId = 4, Name = "MIAMI SPRINGS SHS", MaintenanceCenter = "2", SchoolType = "S", DataValue = 12, Enrollment = 500, Latitude = 53.83604, Longitute = -60.21618 });
//locationDbContext.Locations.Add(new Db.Location() { Id = 3, LocationCode = "Loc3", RegionId = 3, Name = "BOB GRAHAM EDUCATION CENTER 3", MaintenanceCenter = "1", SchoolType = "US" });
//locationDbContext.Locations.Add(new Db.Location() { Id = 4, LocationCode = "Loc4", RegionId = 1, Name = "BOB GRAHAM EDUCATION CENTER 4", MaintenanceCenter = "1", SchoolType = "US" });
//locationDbContext.Locations.Add(new Db.Location() { Id = 5, LocationCode = "Loc5", RegionId = 2, Name = "BOB GRAHAM EDUCATION CENTER 5", MaintenanceCenter = "1", SchoolType = "US" });
//locationDbContext.Locations.Add(new Db.Location() { Id = 6, LocationCode = "Loc6", RegionId = 3, Name = "BOB GRAHAM EDUCATION CENTER 6", MaintenanceCenter = "1", SchoolType = "US" });
locationDbContext.SaveChanges();
}
}
}
}

View File

@ -0,0 +1,177 @@
using AutoMapper;
using DamageAssesment.Api.Locations.Db;
using DamageAssesment.Api.Locations.Interfaces;
using Microsoft.EntityFrameworkCore;
namespace DamageAssesment.Api.Locations.Providers
{
public class RegionsProvider : IRegionsProvider
{
private LocationDbContext locationDbContext;
private ILogger<RegionsProvider> logger;
private IMapper mapper;
public RegionsProvider(LocationDbContext regionDbContext, ILogger<RegionsProvider> logger, IMapper mapper)
{
this.locationDbContext = regionDbContext;
this.logger = logger;
this.mapper = mapper;
// SeedData();
}
public async Task<(bool IsSuccess, Models.Region Region, string ErrorMessage)> GetRegionByIdAsync(int Id)
{
try
{
logger?.LogInformation("Get Regions from DB");
var region = await locationDbContext.Regions.AsNoTracking().FirstOrDefaultAsync(s => s.Id == Id);
if (region != null)
{
logger?.LogInformation($"RegionId: {region.Id} Items found");
var result = mapper.Map<Db.Region, Models.Region>(region);
return (true, result, null);
}
return (false, null, "Not found");
}
catch (Exception ex)
{
logger?.LogError(ex.ToString());
return (false, null, ex.Message);
}
}
public async Task<(bool IsSuccess, IEnumerable<Models.Region> Regions, string ErrorMessage)> GetRegionsAsync()
{
try
{
logger?.LogInformation("Get all Regions from DB");
var regions = await locationDbContext.Regions.AsNoTracking().ToListAsync();
if (regions != null)
{
logger?.LogInformation($"{regions.Count} Items(s) found");
var result = mapper.Map<IEnumerable<Db.Region>, IEnumerable<Models.Region>>(regions);
return (true, result, null);
}
return (false, null, "Not found");
}
catch (Exception ex)
{
logger?.LogError(ex.ToString());
return (false, null, ex.Message);
}
}
public async Task<(bool IsSuccess, Models.Region Region, string ErrorMessage)> PostRegionAsync(Models.Region region)
{
try
{
if (region != null)
{
var _region = mapper.Map<Models.Region, Db.Region>(region);
locationDbContext.Regions.Add(_region);
await locationDbContext.SaveChangesAsync();
region.Id = _region.Id;
logger?.LogInformation($"{region} added successfuly");
return (true, region, "Successful");
}
else
{
logger?.LogInformation($"{region} cannot be added");
return (false, null, "Region cannot be added");
}
}
catch (Exception ex)
{
logger?.LogError(ex.ToString());
return (false, null, ex.Message);
}
}
public async Task<(bool IsSuccess, Models.Region Region, string ErrorMessage)> PutRegionAsync(int Id, Models.Region region)
{
try
{
if (region != null)
{
var _region = await locationDbContext.Regions.AsNoTracking().Where(s => s.Id == Id).FirstOrDefaultAsync();
if (_region != null)
{
if (RegionExists(region.Id))
{
locationDbContext.Regions.Update(mapper.Map<Models.Region, Db.Region>(region));
locationDbContext.SaveChanges();
return (true, region, "Region updated Successfuly");
}
else
{
logger?.LogInformation($"RegionID: {Id} Not exists");
return (false, null, "Region not exists");
}
}
else
{
logger?.LogInformation($"RegionID: {Id} Not found");
return (false, null, "Not Found");
}
}
else
{
logger?.LogInformation($"RegionID: {Id} Bad Request");
return (false, null, "Bad request");
}
}
catch (Exception ex)
{
logger?.LogError(ex.ToString());
return (false, null, ex.Message);
}
}
public async Task<(bool IsSuccess, Models.Region Region, string ErrorMessage)> DeleteRegionAsync(int Id)
{
try
{
var region = await locationDbContext.Regions.AsNoTracking().Where(x => x.Id == Id).FirstOrDefaultAsync();
if (region != null)
{
locationDbContext.Regions.Remove(region);
locationDbContext.SaveChanges();
return (true, mapper.Map<Db.Region, Models.Region>(region), $"RegionId {Id} deleted Successfuly");
}
else
{
logger?.LogInformation($"RegionID: {Id} Not found");
return (false, null, "Not Found");
}
}
catch (Exception ex)
{
logger?.LogError(ex.ToString());
return (false, null, ex.Message);
}
}
private bool RegionExists(int id)
{
return locationDbContext.Regions.AsNoTracking().Count(e => e.Id == id) > 0;
}
public void SeedData()
{
if (!locationDbContext.Regions.Any())
{
locationDbContext.Regions.Add(new Db.Region() { Name = "North", Abbreviation = "N" });
locationDbContext.Regions.Add(new Db.Region() { Name = "Central", Abbreviation = "C" });
locationDbContext.Regions.Add(new Db.Region() { Name = "South", Abbreviation = "S" });
locationDbContext.Regions.Add(new Db.Region() { Name = "Charter Schools", Abbreviation = "CS" });
locationDbContext.Regions.Add(new Db.Region() { Name = "Alternate and Special Centers", Abbreviation = "AC" });
locationDbContext.SaveChanges();
}
}
}
}

View File

@ -0,0 +1,12 @@
{
"JwtSettings": {
"securitykey": "bWlhbWkgZGFkZSBzY2hvb2xzIHNlY3JldCBrZXk="
},
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft.AspNetCore": "Warning"
}
},
"AllowedHosts": "*"
}

View File

@ -0,0 +1,251 @@
using DamageAssesment.Api.Questions.Interfaces;
using DamageAssesment.Api.Questions.Models;
using Microsoft.AspNetCore.Mvc;
namespace DamageAssesment.Api.Questions.Controllers
{
[ApiController]
public class QuestionsController : ControllerBase
{
private readonly IQuestionsProvider questionsProvider;
public QuestionsController(IQuestionsProvider questionsProvider)
{
this.questionsProvider = questionsProvider;
}
/// <summary>
/// GET request for retrieving questions.
/// </summary>
// get all questions
[Route("questions")]
[Route("questions/{language:alpha}")]
[HttpGet]
public async Task<IActionResult> GetQuestionsAsync(string? language)
{
var result = await this.questionsProvider.GetQuestionsAsync(language);
if (result.IsSuccess)
{
return Ok(result.Questions);
}
return NoContent();
}
//Get questions based on question id
/// <summary>
/// GET request for retrieving a question by ID.
/// </summary>
[Route("questions/{id}/{language:alpha}")]
[Route("questions/{id:int}")]
[HttpGet]
public async Task<IActionResult> GetQuestionByIdAsync(int id, string? language)
{
var result = await this.questionsProvider.GetQuestionAsync(id, language);
if (result.IsSuccess)
{
return Ok(result.Question);
}
return NotFound();
}
//get all questions based on survey id
/// <summary>
/// GET request for retrieving survey questions based on a survey ID.
/// Uri: {Optional language}/GetSurveyQuestions/{surveyId} :Default returns question in all languages
/// </summary>
[Route("questions/bysurvey/{surveyId:int}")]
[Route("questions/bysurvey/{surveyId:int}/{language:alpha}")]
[HttpGet]
public async Task<IActionResult> GetSurveyQuestions(int surveyId,string? language)
{
var result = await this.questionsProvider.GetSurveyQuestionAsync(surveyId, language);
if (result.IsSuccess)
{
return Ok(result.SurveyQuestions);
}
return NotFound();
}
/// <summary>
/// PUT request for updating a question (multilingual).
/// </summary>
[HttpPut("questions")]
public async Task<IActionResult> UpdateQuestion(Models.Question question)
{
if (question != null)
{
var result = await this.questionsProvider.UpdateQuestionAsync(question);
if (result.IsSuccess)
{
return Ok(result.Question);
}
if (result.ErrorMessage == "Not Found")
return NotFound(result.ErrorMessage);
return BadRequest(result.ErrorMessage);
}
return CreatedAtRoute("DefaultApi", new { id = question.Id }, question);
}
/// <summary>
/// POST request for creating a multiple question (multilingual).
/// </summary>
[HttpPost("questions/multiple")]
public async Task<IActionResult> CreateQuestions(List<Models.Question> questions)
{
if (questions != null)
{
var result = await this.questionsProvider.PostQuestionsAsync(questions);
if (result.IsSuccess)
{
return Ok(result.Question);
}
if (result.ErrorMessage == "Not Found")
return NotFound(result.ErrorMessage);
return BadRequest(result.ErrorMessage);
}
return CreatedAtRoute("DefaultApi",questions);
}
/// <summary>
/// PUT request for update a multiple question (multilingual) for survey.
/// </summary>
[HttpPut("questions/multiple/{surveyid}")]
public async Task<IActionResult> CreateQuestions(int surveyid, List<Models.Question> questions)
{
if (questions != null)
{
var result = await this.questionsProvider.PutQuestionsAsync(surveyid,questions);
if (result.IsSuccess)
{
return Ok(result.Question);
}
if (result.ErrorMessage == "Not Found")
return NotFound(result.ErrorMessage);
return BadRequest(result.ErrorMessage);
}
return CreatedAtRoute("DefaultApi", questions);
}
/// <summary>
/// POST request for creating a new question (multilingual).
/// </summary>
[HttpPost("questions")]
public async Task<IActionResult> CreateQuestion(Models.Question question)
{
if (question != null)
{
var result = await this.questionsProvider.PostQuestionAsync(question);
if (result.IsSuccess)
{
return Ok(result.Question);
}
return BadRequest(result.ErrorMessage);
}
return CreatedAtRoute("DefaultApi", new { id = question.Id }, question);
}
/// <summary>
/// DELETE request for deleting a question based on ID.
/// </summary>
[HttpDelete("questions/{id}")]
public async Task<IActionResult> DeleteQuestion(int id)
{
var result = await this.questionsProvider.DeleteQuestionAsync(id);
if (result.IsSuccess)
{
return Ok(result.Question);
}
return NotFound();
}
/// <summary>
/// GET request for retrieving question categories.
/// </summary>
[HttpGet("questions/categories")]
[HttpGet("questions/categories/{language:alpha}")]
public async Task<IActionResult> GetQuestionCategoriesAsync(string? language)
{
var result = await this.questionsProvider.GetQuestionCategoriesAsync(language);
if (result.IsSuccess)
{
return Ok(result.QuestionCategories);
}
return NoContent();
}
/// <summary>
/// GET request for retrieving a question category by ID.
/// </summary>
[HttpGet("questions/categories/{id:int}")]
[HttpGet("questions/categories/{id:int}/{language:alpha}")]
public async Task<IActionResult> GetQuestionCategoryAsync(int id,string? language)
{
var result = await this.questionsProvider.GetQuestionCategoryAsync(id, language);
if (result.IsSuccess)
{
return Ok(result.QuestionCategory);
}
return NotFound();
}
/// <summary>
/// PUT request for updating a question category.
/// </summary>
[HttpPut("questions/categories")]
public async Task<IActionResult> UpdateQuestionCategory(Models.QuestionCategory questionCategory)
{
if (questionCategory != null)
{
var result = await this.questionsProvider.UpdateQuestionCategoryAsync(questionCategory);
if (result.IsSuccess)
{
return Ok(result.QuestionCategory);
}
if (result.ErrorMessage == "Not Found")
return NotFound(result.ErrorMessage);
return BadRequest(result.ErrorMessage);
}
return CreatedAtRoute("DefaultApi", new { id = questionCategory.Id }, questionCategory);
}
/// <summary>
/// POST request for creating a new question category.
/// </summary>
[HttpPost("questions/categories")]
public async Task<IActionResult> CreateQuestionCategory(Models.QuestionCategory questionCategory)
{
if (questionCategory != null)
{
var result = await this.questionsProvider.PostQuestionCategoryAsync(questionCategory);
if (result.IsSuccess)
{
return Ok(result.QuestionCategory);
}
return BadRequest(result.ErrorMessage);
}
return CreatedAtRoute("DefaultApi", new { id = questionCategory.Id }, questionCategory);
}
/// <summary>
/// DELETE request for deleting a question category based on ID.
/// </summary>
[HttpDelete("questions/categories/{id}")]
public async Task<IActionResult> DeleteQuestionCategory(int id)
{
var result = await this.questionsProvider.DeleteQuestionCategoryAsync(id);
if (result.IsSuccess)
{
return Ok(result.QuestionCategory);
}
return NotFound();
}
}
}

Some files were not shown because too many files have changed in this diff Show More