diff --git a/DamageAssesmentApi/.gitignore b/DamageAssesmentApi/.gitignore new file mode 100644 index 0000000..8dd4607 --- /dev/null +++ b/DamageAssesmentApi/.gitignore @@ -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 \ No newline at end of file diff --git a/DamageAssesmentApi/DamageAssesment.Api.Answers.Test/AnswersServiceTest.cs b/DamageAssesmentApi/DamageAssesment.Api.Answers.Test/AnswersServiceTest.cs new file mode 100644 index 0000000..3b114f7 --- /dev/null +++ b/DamageAssesmentApi/DamageAssesment.Api.Answers.Test/AnswersServiceTest.cs @@ -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(); + 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(); + 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(); + 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(); + 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(); + 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(); + 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(); + 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(); + 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(); + 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(); + 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(); + 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(); + 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(); + 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); + } + } +} \ No newline at end of file diff --git a/DamageAssesmentApi/DamageAssesment.Api.Answers.Test/DamageAssesment.Api.Answers.Test.csproj b/DamageAssesmentApi/DamageAssesment.Api.Answers.Test/DamageAssesment.Api.Answers.Test.csproj new file mode 100644 index 0000000..8a8a535 --- /dev/null +++ b/DamageAssesmentApi/DamageAssesment.Api.Answers.Test/DamageAssesment.Api.Answers.Test.csproj @@ -0,0 +1,30 @@ + + + + net6.0 + enable + enable + + false + true + + + + + + + + runtime; build; native; contentfiles; analyzers; buildtransitive + all + + + runtime; build; native; contentfiles; analyzers; buildtransitive + all + + + + + + + + diff --git a/DamageAssesmentApi/DamageAssesment.Api.Answers.Test/MocData.cs b/DamageAssesmentApi/DamageAssesment.Api.Answers.Test/MocData.cs new file mode 100644 index 0000000..e65d4f4 --- /dev/null +++ b/DamageAssesmentApi/DamageAssesment.Api.Answers.Test/MocData.cs @@ -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, string)> getOkResponse() + { + IEnumerable list = new List(); + + 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, string)> getNoContentResponse() + { + IEnumerable list = new List(); + return (false, list, null); + } + + public static async Task getInputAnswerData() + { + return new Answers.Db.Answer { Id = 1, AnswerText = "Yes", Comment = "", QuestionId = 1, SurveyResponseId = 1 }; + + } + + } +} diff --git a/DamageAssesmentApi/DamageAssesment.Api.Answers/Controllers/AnswersController.cs b/DamageAssesmentApi/DamageAssesment.Api.Answers/Controllers/AnswersController.cs new file mode 100644 index 0000000..27f5c3c --- /dev/null +++ b/DamageAssesmentApi/DamageAssesment.Api.Answers/Controllers/AnswersController.cs @@ -0,0 +1,111 @@ +using DamageAssesment.Api.Answers.Interfaces; +using Microsoft.AspNetCore.Mvc; +using Microsoft.EntityFrameworkCore; +using Microsoft.OpenApi.Any; + +namespace DamageAssesment.Api.Answers.Controllers +{ + [Route("api")] + [ApiController] + public class AnswersController: ControllerBase + { + private IAnswersProvider answerProvider; + + public AnswersController(IAnswersProvider answersProvider) { + this.answerProvider=answersProvider; + } + //get all answers + [HttpGet("Answers")] + public async Task GetAnswersAsync() { + + var result = await answerProvider.GetAnswersAsync(); + if(result.IsSuccess) + { + return Ok(result.Answers); + } + return NoContent(); + + } + //get answer based on answerid + [HttpGet("Answers/{Id}")] + public async Task GetAnswerByIdAsync(int Id) + { + + var result = await answerProvider.GetAnswerByIdAsync(Id); + if (result.IsSuccess) + { + return Ok(result.Answer); + } + return NotFound(); + + } + // get all answers based on response id + [HttpGet("AnswersByResponse/{ResponseId}")] + public async Task GetAnswersByResponseId(int ResponseId) + { + var result = await this.answerProvider.GetAnswersAsync(ResponseId); + if(result.IsSuccess) + { + return Ok(result.Answers); + } + return NoContent(); + } + // get all answers based on question id + [HttpGet("AnswersByQuestion/{QuestionId}")] + public async Task AnswersByQuestionId(int QuestionId) + { + var result = await this.answerProvider.GetAnswersByQuestionAsync(QuestionId); + if (result.IsSuccess) + { + return Ok(result.Answers); + } + return NotFound(); + } + //update existing answer + + [HttpPut("Answers")] + public async Task UpdateAnswer(Db.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(); + } + //save new answer + [HttpPost("Answers")] + public async Task CreateAnswer(Db.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); + } + //delete existing answer + [HttpDelete("Answers/{id}")] + public async Task DeleteAnswer(int id) + { + var result = await this.answerProvider.DeleteAnswerAsync(id); + if (result.IsSuccess) + { + return Ok(result.Answer); + } + return NotFound(); + } + + } +} diff --git a/DamageAssesmentApi/DamageAssesment.Api.Answers/DamageAssesment.Api.Answers.csproj b/DamageAssesmentApi/DamageAssesment.Api.Answers/DamageAssesment.Api.Answers.csproj new file mode 100644 index 0000000..ca5ee38 --- /dev/null +++ b/DamageAssesmentApi/DamageAssesment.Api.Answers/DamageAssesment.Api.Answers.csproj @@ -0,0 +1,16 @@ + + + + net6.0 + enable + enable + + + + + + + + + + diff --git a/DamageAssesmentApi/DamageAssesment.Api.Answers/Db/Answer.cs b/DamageAssesmentApi/DamageAssesment.Api.Answers/Db/Answer.cs new file mode 100644 index 0000000..50553f5 --- /dev/null +++ b/DamageAssesmentApi/DamageAssesment.Api.Answers/Db/Answer.cs @@ -0,0 +1,20 @@ +using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations.Schema; + +namespace DamageAssesment.Api.Answers.Db +{ + 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; } + + } +} diff --git a/DamageAssesmentApi/DamageAssesment.Api.Answers/Db/AnswerDbContext.cs b/DamageAssesmentApi/DamageAssesment.Api.Answers/Db/AnswerDbContext.cs new file mode 100644 index 0000000..8d3a8ef --- /dev/null +++ b/DamageAssesmentApi/DamageAssesment.Api.Answers/Db/AnswerDbContext.cs @@ -0,0 +1,16 @@ +using Microsoft.EntityFrameworkCore; + +namespace DamageAssesment.Api.Answers.Db +{ + public class AnswerDbContext:DbContext + { + + public AnswerDbContext(DbContextOptions options):base(options) + { + + } + public DbSet Answers { get; set; } + + } + +} diff --git a/DamageAssesmentApi/DamageAssesment.Api.Answers/Interfaces/IAnswersProvider.cs b/DamageAssesmentApi/DamageAssesment.Api.Answers/Interfaces/IAnswersProvider.cs new file mode 100644 index 0000000..4a202f1 --- /dev/null +++ b/DamageAssesmentApi/DamageAssesment.Api.Answers/Interfaces/IAnswersProvider.cs @@ -0,0 +1,13 @@ +namespace DamageAssesment.Api.Answers.Interfaces +{ + public interface IAnswersProvider + { + Task<(bool IsSuccess,IEnumerable< Models.Answer> Answers, string ErrorMessage)> GetAnswersAsync(); + Task<(bool IsSuccess, IEnumerable Answers, string ErrorMessage)> GetAnswersByQuestionAsync(int questionId); + Task<(bool IsSuccess, Models.Answer Answer, string ErrorMessage)> GetAnswerByIdAsync(int Id); + Task<(bool IsSuccess, IEnumerable Answers, string ErrorMessage)> GetAnswersAsync(int responseId); + Task<(bool IsSuccess, Models.Answer Answer, string ErrorMessage)> PostAnswerAsync(Db.Answer Answer); + Task<(bool IsSuccess, Models.Answer Answer, string ErrorMessage)> UpdateAnswerAsync(Db.Answer Answer); + Task<(bool IsSuccess, Models.Answer Answer, string ErrorMessage)> DeleteAnswerAsync(int Id); + } +} diff --git a/DamageAssesmentApi/DamageAssesment.Api.Answers/Models/Answer.cs b/DamageAssesmentApi/DamageAssesment.Api.Answers/Models/Answer.cs new file mode 100644 index 0000000..f6d72a3 --- /dev/null +++ b/DamageAssesmentApi/DamageAssesment.Api.Answers/Models/Answer.cs @@ -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; } + } +} diff --git a/DamageAssesmentApi/DamageAssesment.Api.Answers/Profiles/AnswersProfile.cs b/DamageAssesmentApi/DamageAssesment.Api.Answers/Profiles/AnswersProfile.cs new file mode 100644 index 0000000..0a5e6ae --- /dev/null +++ b/DamageAssesmentApi/DamageAssesment.Api.Answers/Profiles/AnswersProfile.cs @@ -0,0 +1,12 @@ +using AutoMapper; + +namespace DamageAssesment.Api.Answers.Profiles +{ + public class AnswersProfile : AutoMapper.Profile + { + public AnswersProfile() + { + CreateMap(); + } + } +} diff --git a/DamageAssesmentApi/DamageAssesment.Api.Answers/Program.cs b/DamageAssesmentApi/DamageAssesment.Api.Answers/Program.cs new file mode 100644 index 0000000..7630089 --- /dev/null +++ b/DamageAssesmentApi/DamageAssesment.Api.Answers/Program.cs @@ -0,0 +1,33 @@ +using DamageAssesment.Api.Answers.Db; +using DamageAssesment.Api.Answers.Interfaces; +using DamageAssesment.Api.Answers.Providers; +using Microsoft.EntityFrameworkCore; + +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.AddScoped(); +builder.Services.AddAutoMapper(AppDomain.CurrentDomain.GetAssemblies()); //4/30 +builder.Services.AddDbContext(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(); diff --git a/DamageAssesmentApi/DamageAssesment.Api.Answers/Properties/launchSettings.json b/DamageAssesmentApi/DamageAssesment.Api.Answers/Properties/launchSettings.json new file mode 100644 index 0000000..822163a --- /dev/null +++ b/DamageAssesmentApi/DamageAssesment.Api.Answers/Properties/launchSettings.json @@ -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" + } + } + } +} diff --git a/DamageAssesmentApi/DamageAssesment.Api.Answers/Providers/AnswerProvider.cs b/DamageAssesmentApi/DamageAssesment.Api.Answers/Providers/AnswerProvider.cs new file mode 100644 index 0000000..b1851d8 --- /dev/null +++ b/DamageAssesmentApi/DamageAssesment.Api.Answers/Providers/AnswerProvider.cs @@ -0,0 +1,208 @@ +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 logger; + private IMapper mapper; + + public AnswersProvider(AnswerDbContext answerDbContext, ILogger logger, IMapper mapper) + { + this.answerDbContext = answerDbContext; + this.logger = logger; + this.mapper = mapper; + SeedData(); + } + + public async Task<(bool IsSuccess, IEnumerable 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>(answer); + 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.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(answer); + 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 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>(respAnswers); + 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 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>(respAnswers); + 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.Answer Answer, string ErrorMessage)> PostAnswerAsync(Db.Answer Answer) + { + try + { + logger?.LogInformation("Query Answer"); + if (!AnswerExists(Answer.Id)) + { + answerDbContext.Answers.Add(Answer); + answerDbContext.SaveChanges(); + var result = mapper.Map(Answer); + return (true, result, null); + } + return (false, null, "Answer is already exits"); + } + catch (Exception ex) + { + logger?.LogError(ex.ToString()); + return (false, null, ex.Message); + } + } + public async Task<(bool IsSuccess, Models.Answer Answer, string ErrorMessage)> UpdateAnswerAsync(Db.Answer Answer) + { + try + { + if (Answer != null) + { + var existing = answerDbContext.Answers.AsNoTracking().FirstOrDefault(x => x.Id == Answer.Id); + if (existing != null) + { + answerDbContext.Answers.Update(Answer); + answerDbContext.SaveChanges(); + return (true, mapper.Map(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); + } + } + 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(answer), $"AnswerId {Id} deleted Successfuly"); + } + catch (Exception ex) + { + + logger?.LogError(ex.ToString()); + return (false,null, ex.Message); + } + } + private bool AnswerExists(int id) + { + return answerDbContext.Answers.AsNoTracking().Count(e => e.Id == id) > 0; + } + + private void SeedData() + { + if (!answerDbContext.Answers.Any()) + { + answerDbContext.Answers.Add(new Db.Answer() { Id = 1, AnswerText = "Yes", Comment = "", QuestionId = 1, SurveyResponseId = 1 }); + answerDbContext.Answers.Add(new Db.Answer() { Id = 2, AnswerText = "Yes", Comment = "myComment", QuestionId = 2, SurveyResponseId = 1 }); + 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(); + } + + } + + + + } +} diff --git a/DamageAssesmentApi/DamageAssesment.Api.Answers/appsettings.Development.json b/DamageAssesmentApi/DamageAssesment.Api.Answers/appsettings.Development.json new file mode 100644 index 0000000..0c208ae --- /dev/null +++ b/DamageAssesmentApi/DamageAssesment.Api.Answers/appsettings.Development.json @@ -0,0 +1,8 @@ +{ + "Logging": { + "LogLevel": { + "Default": "Information", + "Microsoft.AspNetCore": "Warning" + } + } +} diff --git a/DamageAssesmentApi/DamageAssesment.Api.Answers/appsettings.json b/DamageAssesmentApi/DamageAssesment.Api.Answers/appsettings.json new file mode 100644 index 0000000..10f68b8 --- /dev/null +++ b/DamageAssesmentApi/DamageAssesment.Api.Answers/appsettings.json @@ -0,0 +1,9 @@ +{ + "Logging": { + "LogLevel": { + "Default": "Information", + "Microsoft.AspNetCore": "Warning" + } + }, + "AllowedHosts": "*" +} diff --git a/DamageAssesmentApi/DamageAssesment.Api.Attachments.Test/AttachmentsServiceTest.cs b/DamageAssesmentApi/DamageAssesment.Api.Attachments.Test/AttachmentsServiceTest.cs new file mode 100644 index 0000000..5bf695c --- /dev/null +++ b/DamageAssesmentApi/DamageAssesment.Api.Attachments.Test/AttachmentsServiceTest.cs @@ -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(); + var mockUploadService = new Mock(); + 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(); + var mockUploadService = new Mock(); + 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(); + var mockUploadService = new Mock(); + 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(); + var mockUploadService = new Mock(); + 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(); + var mockUploadService = new Mock(); + 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(); + var mockUploadService = new Mock(); + 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(); + var mockUploadService = new Mock(); + 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(); + var mockUploadService = new Mock(); + 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(); + var mockUploadService = new Mock(); + 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(); + var mockUploadService = new Mock(); + 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); + } + } +} \ No newline at end of file diff --git a/DamageAssesmentApi/DamageAssesment.Api.Attachments.Test/DamageAssesment.Api.Attachments.Test.csproj b/DamageAssesmentApi/DamageAssesment.Api.Attachments.Test/DamageAssesment.Api.Attachments.Test.csproj new file mode 100644 index 0000000..e67746b --- /dev/null +++ b/DamageAssesmentApi/DamageAssesment.Api.Attachments.Test/DamageAssesment.Api.Attachments.Test.csproj @@ -0,0 +1,30 @@ + + + + net6.0 + enable + enable + + false + true + + + + + + + + runtime; build; native; contentfiles; analyzers; buildtransitive + all + + + runtime; build; native; contentfiles; analyzers; buildtransitive + all + + + + + + + + diff --git a/DamageAssesmentApi/DamageAssesment.Api.Attachments.Test/MockData.cs b/DamageAssesmentApi/DamageAssesment.Api.Attachments.Test/MockData.cs new file mode 100644 index 0000000..284830d --- /dev/null +++ b/DamageAssesmentApi/DamageAssesment.Api.Attachments.Test/MockData.cs @@ -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, string)> getOkResponse() + { + List list = new List(); + + for (int i = 0; i < 10; i++) + { + list.Add(new Attachments.Models.Attachment(i, Guid.NewGuid().ToString() + "@gmail.com") + { + 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 GetAttachmentInfo(int id) + { + List files = new List(); + List answerInfos = new List(); + 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, 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, string)> getNoContentResponse() + { + IEnumerable list = new List(); + return (false, list, null); + } + + public static async Task> getInputAttachmentData() + { + List Attachments=new List(); + Attachments.Add(new Db.Attachment{ Id = 0, AnswerId = 10, ResponseId = 10, URI = "sample", IsDeleted = false,FileName="sample1" }) ; + return Attachments; + } + + } +} diff --git a/DamageAssesmentApi/DamageAssesment.Api.Attachments/Controllers/AttachmentsController.cs b/DamageAssesmentApi/DamageAssesment.Api.Attachments/Controllers/AttachmentsController.cs new file mode 100644 index 0000000..a86a151 --- /dev/null +++ b/DamageAssesmentApi/DamageAssesment.Api.Attachments/Controllers/AttachmentsController.cs @@ -0,0 +1,145 @@ +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 +{ + [Route("api")] + [ApiController] + public class AttachmentsController : ControllerBase + { + private IAttachmentsProvider AttachmentProvider; + private IUploadService UploadService; + + public AttachmentsController(IAttachmentsProvider AttachmentsProvider, IUploadService uploadService) + { + this.AttachmentProvider = AttachmentsProvider; + this.UploadService = uploadService; + } + //get all Attachments + [HttpGet("Attachments")] + public async Task GetAttachmentsAsync() + { + + var result = await AttachmentProvider.GetAttachmentsAsync(); + if (result.IsSuccess) + { + return Ok(result.Attachments); + } + return NoContent(); + + } + //get all Attachment by Id + [HttpGet("Attachments/{id}")] + public async Task 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 UploadAsync(int responseId, int answerId, List postedFile) + //{ + // try + // { + + // if (postedFile.Count > 0) + // { + // //Upload logic for all files + // var Attachments= await this.AttachmentProvider.DeleteAttachmentsAsync(responseId,answerId); + // List 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}"); + // } + //} + + //Save new Attachment + [HttpPost("Attachments"), DisableRequestSizeLimit] + public async Task UploadAttachmentAsync(AttachmentInfo attachmentInfo) + { + try + { + if (attachmentInfo.Answers.Count > 0) + { + var Attachments = await this.AttachmentProvider.GetAttachmentCounter(); + List 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}"); + } + } + + //Save new Attachment + [HttpPut("Attachments"), DisableRequestSizeLimit] + public async Task UpdateAttachmentAsync(AttachmentInfo attachmentInfo) + { + try + { + if (attachmentInfo.Answers.Count > 0) + { + var res = await this.AttachmentProvider.GetAttachmentInfo(attachmentInfo.Answers); + if (res.IsSuccess) + { + List 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}"); + } + } + //delete existing Attachment + [HttpDelete("Delete")] + public async Task 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(); + } + + } +} diff --git a/DamageAssesmentApi/DamageAssesment.Api.Attachments/DMS_Attachments/Active/Response-1/Answer-1/Attachment_1.txt b/DamageAssesmentApi/DamageAssesment.Api.Attachments/DMS_Attachments/Active/Response-1/Answer-1/Attachment_1.txt new file mode 100644 index 0000000..eed7e79 --- /dev/null +++ b/DamageAssesmentApi/DamageAssesment.Api.Attachments/DMS_Attachments/Active/Response-1/Answer-1/Attachment_1.txt @@ -0,0 +1 @@ +sample \ No newline at end of file diff --git a/DamageAssesmentApi/DamageAssesment.Api.Attachments/DamageAssesment.Api.Attachments.csproj b/DamageAssesmentApi/DamageAssesment.Api.Attachments/DamageAssesment.Api.Attachments.csproj new file mode 100644 index 0000000..3454bff --- /dev/null +++ b/DamageAssesmentApi/DamageAssesment.Api.Attachments/DamageAssesment.Api.Attachments.csproj @@ -0,0 +1,18 @@ + + + + net6.0 + enable + enable + + + + + + + + + + + + diff --git a/DamageAssesmentApi/DamageAssesment.Api.Attachments/Db/Attachment.cs b/DamageAssesmentApi/DamageAssesment.Api.Attachments/Db/Attachment.cs new file mode 100644 index 0000000..d27adc1 --- /dev/null +++ b/DamageAssesmentApi/DamageAssesment.Api.Attachments/Db/Attachment.cs @@ -0,0 +1,20 @@ +using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations.Schema; + +namespace DamageAssesment.Api.Attachments.Db +{ + 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; } + } +} diff --git a/DamageAssesmentApi/DamageAssesment.Api.Attachments/Db/AttachmentsDbContext.cs b/DamageAssesmentApi/DamageAssesment.Api.Attachments/Db/AttachmentsDbContext.cs new file mode 100644 index 0000000..561377d --- /dev/null +++ b/DamageAssesmentApi/DamageAssesment.Api.Attachments/Db/AttachmentsDbContext.cs @@ -0,0 +1,12 @@ +using Microsoft.EntityFrameworkCore; + +namespace DamageAssesment.Api.Attachments.Db +{ + public class AttachmentsDbContext:DbContext + { + public AttachmentsDbContext(DbContextOptions options) : base(options) + { + } + public DbSet Attachments { get; set; } + } +} diff --git a/DamageAssesmentApi/DamageAssesment.Api.Attachments/Interfaces/IAttachmentsProvider.cs b/DamageAssesmentApi/DamageAssesment.Api.Attachments/Interfaces/IAttachmentsProvider.cs new file mode 100644 index 0000000..f193e11 --- /dev/null +++ b/DamageAssesmentApi/DamageAssesment.Api.Attachments/Interfaces/IAttachmentsProvider.cs @@ -0,0 +1,17 @@ +using DamageAssesment.Api.Attachments.Models; + +namespace DamageAssesment.Api.Attachments.Interfaces +{ + public interface IAttachmentsProvider + { + Task<(bool IsSuccess, IEnumerable Attachments, string ErrorMessage)> GetAttachmentsAsync(); + Task<(bool IsSuccess, Models.Attachment Attachment, string ErrorMessage)> GetAttachmentByIdAsync(int Id); + Task<(bool IsSuccess, IEnumerable Attachments, string ErrorMessage)> PostAttachmentAsync(List Attachments); + Task<(bool IsSuccess, IEnumerable Attachments, string ErrorMessage)> PutAttachmentAsync(List Attachments); + Task<(bool IsSuccess, Models.Attachment Attachment, string Path)> DeleteAttachmentAsync(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 answerIds); + Task<(bool IsSuccess, int counter, string message)> GetAttachmentCounter(); + Task<(bool IsSuccess, IEnumerable Attachments, string ErrorMessage)> GetAttachmentInfo(List answers); + } +} diff --git a/DamageAssesmentApi/DamageAssesment.Api.Attachments/Interfaces/IAzureBlobService.cs b/DamageAssesmentApi/DamageAssesment.Api.Attachments/Interfaces/IAzureBlobService.cs new file mode 100644 index 0000000..f15ed9e --- /dev/null +++ b/DamageAssesmentApi/DamageAssesment.Api.Attachments/Interfaces/IAzureBlobService.cs @@ -0,0 +1,10 @@ +using Azure.Storage.Blobs.Models; + +namespace DamageAssesment.Api.Attachments.Interfaces +{ + public interface IAzureBlobService + { + Task>> UploadFiles(List files); + void DeleteFile(string path); + } +} diff --git a/DamageAssesmentApi/DamageAssesment.Api.Attachments/Interfaces/IUploadService.cs b/DamageAssesmentApi/DamageAssesment.Api.Attachments/Interfaces/IUploadService.cs new file mode 100644 index 0000000..121d411 --- /dev/null +++ b/DamageAssesmentApi/DamageAssesment.Api.Attachments/Interfaces/IUploadService.cs @@ -0,0 +1,13 @@ +using DamageAssesment.Api.Attachments.Models; + +namespace DamageAssesment.Api.Attachments.Interfaces +{ + public interface IUploadService + { + List UploadAttachment(int responseId,int answerId, int counter, List postedFile); + List UploadAttachment(int responseId, int counter, List answers); + public List UpdateAttachments(int responseId, List answers, IEnumerable attachments); + void Deletefile(string path); + void Movefile(string path); + } +} diff --git a/DamageAssesmentApi/DamageAssesment.Api.Attachments/Models/Attachment.cs b/DamageAssesmentApi/DamageAssesment.Api.Attachments/Models/Attachment.cs new file mode 100644 index 0000000..8f2ba66 --- /dev/null +++ b/DamageAssesmentApi/DamageAssesment.Api.Attachments/Models/Attachment.cs @@ -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; + } + } +} diff --git a/DamageAssesmentApi/DamageAssesment.Api.Attachments/Models/AttachmentInfo.cs b/DamageAssesmentApi/DamageAssesment.Api.Attachments/Models/AttachmentInfo.cs new file mode 100644 index 0000000..5efd1e8 --- /dev/null +++ b/DamageAssesmentApi/DamageAssesment.Api.Attachments/Models/AttachmentInfo.cs @@ -0,0 +1,20 @@ +namespace DamageAssesment.Api.Attachments.Models +{ + public class AttachmentInfo + { + public int ResponseId { get; set; } + public List Answers { get; set; } + } + public class AnswerInfo + { + public int AnswerId { get; set; } + public List 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; } + } +} diff --git a/DamageAssesmentApi/DamageAssesment.Api.Attachments/Profiles/AttachmentsProfiles.cs b/DamageAssesmentApi/DamageAssesment.Api.Attachments/Profiles/AttachmentsProfiles.cs new file mode 100644 index 0000000..44ee69f --- /dev/null +++ b/DamageAssesmentApi/DamageAssesment.Api.Attachments/Profiles/AttachmentsProfiles.cs @@ -0,0 +1,10 @@ +namespace DamageAssesment.Api.Attachments.Profiles +{ + public class AttachmentsProfiles:AutoMapper.Profile + { + public AttachmentsProfiles() + { + CreateMap(); + } + } +} diff --git a/DamageAssesmentApi/DamageAssesment.Api.Attachments/Program.cs b/DamageAssesmentApi/DamageAssesment.Api.Attachments/Program.cs new file mode 100644 index 0000000..d661ef6 --- /dev/null +++ b/DamageAssesmentApi/DamageAssesment.Api.Attachments/Program.cs @@ -0,0 +1,45 @@ +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; + +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.AddScoped(); +builder.Services.AddScoped(); +builder.Services.AddScoped(); +builder.Services.AddAutoMapper(AppDomain.CurrentDomain.GetAssemblies()); //4/30 +builder.Services.AddDbContext(option => +{ + option.UseInMemoryDatabase("Attachments"); +}); +builder.Services.Configure(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(); diff --git a/DamageAssesmentApi/DamageAssesment.Api.Attachments/Properties/launchSettings.json b/DamageAssesmentApi/DamageAssesment.Api.Attachments/Properties/launchSettings.json new file mode 100644 index 0000000..8d37224 --- /dev/null +++ b/DamageAssesmentApi/DamageAssesment.Api.Attachments/Properties/launchSettings.json @@ -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" + } + } + } +} diff --git a/DamageAssesmentApi/DamageAssesment.Api.Attachments/Providers/AttachmentsProvider.cs b/DamageAssesmentApi/DamageAssesment.Api.Attachments/Providers/AttachmentsProvider.cs new file mode 100644 index 0000000..6a3cc63 --- /dev/null +++ b/DamageAssesmentApi/DamageAssesment.Api.Attachments/Providers/AttachmentsProvider.cs @@ -0,0 +1,217 @@ +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 logger; + private IUploadService uploadservice; + private IMapper mapper; + + public AttachmentsProvider(AttachmentsDbContext AttachmentDbContext, ILogger logger, IMapper mapper,IUploadService uploadservice) + { + this.AttachmentDbContext = AttachmentDbContext; + this.logger = logger; + this.mapper = mapper; + this.uploadservice = uploadservice; + SeedData(); + } + public async Task<(bool IsSuccess, IEnumerable Attachments, string ErrorMessage)> GetAttachmentsAsync() + { + + try + { + logger?.LogInformation("Query Question"); + var Attachment = await AttachmentDbContext.Attachments.AsNoTracking().Where(a => !a.IsDeleted).ToListAsync(); + if (Attachment != null) + { + logger?.LogInformation($"{Attachment.Count} Attachments(s) found"); + var result = mapper.Map, IEnumerable>(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"); + var result = mapper.Map(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 Attachments, string ErrorMessage)> PostAttachmentAsync(List Attachments) + { + try + { + logger?.LogInformation("Query Attachment"); + AttachmentDbContext.Attachments.AddRange(Attachments); + AttachmentDbContext.SaveChanges(); + var result = mapper.Map, IEnumerable>(Attachments); + return (true, result, null); + } + catch (Exception ex) + { + logger?.LogError(ex.ToString()); + return (false, null, ex.Message); + } + } + + public async Task<(bool IsSuccess, IEnumerable Attachments, string ErrorMessage)> PutAttachmentAsync(List Attachments) + { + try + { + logger?.LogInformation("Query Attachment"); + AttachmentDbContext.Attachments.UpdateRange(Attachments); + AttachmentDbContext.SaveChanges(); + var result = mapper.Map, IEnumerable>(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 answerIds) + { + int AttachmentId = 0; + try + { + AttachmentId = AttachmentDbContext.Attachments.Max(a => a.Id); + List Attachments = AttachmentDbContext.Attachments.Where(a => a.ResponseId == responseId && answerIds.Contains(a.AnswerId ?? 0)).AsNoTracking().ToList(); + if (Attachments.Count > 0) + { + AttachmentDbContext.Attachments.RemoveRange(Attachments); + AttachmentDbContext.SaveChanges(); + } + 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 Attachments = AttachmentDbContext.Attachments.Where(a => a.ResponseId == responseId && a.AnswerId == answerId).AsNoTracking().ToList(); + if (Attachments.Count > 0) + { + AttachmentDbContext.Attachments.RemoveRange(Attachments); + AttachmentDbContext.SaveChanges(); + } + return (true, AttachmentId, ""); + } + catch (Exception ex) + { + + logger?.LogError(ex.ToString()); + return (false, AttachmentId, ""); + } + } + public async Task<(bool IsSuccess, IEnumerable Attachments, string ErrorMessage)>GetAttachmentInfo(List answers) + { + try + { + List attchmentIds = new List(); + 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>(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); + AttachmentDbContext.SaveChanges(); + return (true, mapper.Map(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; + } + + 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 answerInfos=new List(); + answerInfos.Add(new AnswerInfo(){ AnswerId = 1,postedFiles=new List { fileModel }}); + List attachments = uploadservice.UploadAttachment(1, 0, answerInfos); + if (attachments.Count > 0) + { + AttachmentDbContext.Attachments.AddRange(attachments); + AttachmentDbContext.SaveChanges(); + } + } + + } + } +} diff --git a/DamageAssesmentApi/DamageAssesment.Api.Attachments/Providers/AzureBlobService.cs b/DamageAssesmentApi/DamageAssesment.Api.Attachments/Providers/AzureBlobService.cs new file mode 100644 index 0000000..4e30b42 --- /dev/null +++ b/DamageAssesmentApi/DamageAssesment.Api.Attachments/Providers/AzureBlobService.cs @@ -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 = ""; + public AzureBlobService() + { + _blobClient = new BlobServiceClient(azureConnectionString); + _containerClient = _blobClient.GetBlobContainerClient("apiimages"); + } + + public async Task>> UploadFiles(List files) + { + + var azureResponse = new List>(); + 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(); + } + } +} \ No newline at end of file diff --git a/DamageAssesmentApi/DamageAssesment.Api.Attachments/Providers/UploadService.cs b/DamageAssesmentApi/DamageAssesment.Api.Attachments/Providers/UploadService.cs new file mode 100644 index 0000000..3c0f21f --- /dev/null +++ b/DamageAssesmentApi/DamageAssesment.Api.Attachments/Providers/UploadService.cs @@ -0,0 +1,166 @@ +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 logger; + private IMapper mapper; + private string uploadpath = ""; + private string Deletepath = ""; + public UploadService(IConfiguration configuration, ILogger logger, IMapper mapper) + { + this.logger = logger; + this.mapper = mapper; + uploadpath = configuration.GetValue("Fileupload:folderpath"); + Deletepath = configuration.GetValue("Fileupload:Deletepath"); + } + public List UploadAttachment(int responseId,int answerId,int counter, List 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 attachments = new List(); + 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 Db.Attachment { AnswerId = answerId, ResponseId = responseId, IsDeleted = false, FileName = UserfileName, URI = dbPath }); + } + + return attachments; + } + + public List UploadAttachment(int responseId, int counter,List answers) + { + List attachments = new List(); + 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); + 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 Db.Attachment { AnswerId = answerId, ResponseId = responseId, IsDeleted = false, FileName = UserfileName, URI = dbPath }); + } + } + return attachments; + } + catch (Exception ex) { + return new List(); + } + + + } + public List UpdateAttachments(int responseId,List answers,IEnumerable attachments) + { + List Dbattachments = new List(); + 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); + 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 Db.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); + } + } + } + } +} diff --git a/DamageAssesmentApi/DamageAssesment.Api.Attachments/Resources/Attachments/gitignore b/DamageAssesmentApi/DamageAssesment.Api.Attachments/Resources/Attachments/gitignore new file mode 100644 index 0000000..ab92c23 --- /dev/null +++ b/DamageAssesmentApi/DamageAssesment.Api.Attachments/Resources/Attachments/gitignore @@ -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 diff --git a/DamageAssesmentApi/DamageAssesment.Api.Attachments/appsettings.Development.json b/DamageAssesmentApi/DamageAssesment.Api.Attachments/appsettings.Development.json new file mode 100644 index 0000000..0c208ae --- /dev/null +++ b/DamageAssesmentApi/DamageAssesment.Api.Attachments/appsettings.Development.json @@ -0,0 +1,8 @@ +{ + "Logging": { + "LogLevel": { + "Default": "Information", + "Microsoft.AspNetCore": "Warning" + } + } +} diff --git a/DamageAssesmentApi/DamageAssesment.Api.Attachments/appsettings.json b/DamageAssesmentApi/DamageAssesment.Api.Attachments/appsettings.json new file mode 100644 index 0000000..ceb0a25 --- /dev/null +++ b/DamageAssesmentApi/DamageAssesment.Api.Attachments/appsettings.json @@ -0,0 +1,13 @@ +{ + "Logging": { + "LogLevel": { + "Default": "Information", + "Microsoft.AspNetCore": "Warning" + } + }, + "AllowedHosts": "*", + "Fileupload": { + "folderpath": "DMS_Attachments/Active", + "Deletepath": "DMS_Attachments/Deleted" + } +} diff --git a/DamageAssesmentApi/DamageAssesment.Api.Employees.Test/DamageAssesment.Api.Employees.Test.csproj b/DamageAssesmentApi/DamageAssesment.Api.Employees.Test/DamageAssesment.Api.Employees.Test.csproj new file mode 100644 index 0000000..dfd8d0b --- /dev/null +++ b/DamageAssesmentApi/DamageAssesment.Api.Employees.Test/DamageAssesment.Api.Employees.Test.csproj @@ -0,0 +1,30 @@ + + + + net6.0 + enable + enable + + false + true + + + + + + + + runtime; build; native; contentfiles; analyzers; buildtransitive + all + + + runtime; build; native; contentfiles; analyzers; buildtransitive + all + + + + + + + + diff --git a/DamageAssesmentApi/DamageAssesment.Api.Employees.Test/EmployeeServiceTest.cs b/DamageAssesmentApi/DamageAssesment.Api.Employees.Test/EmployeeServiceTest.cs new file mode 100644 index 0000000..7c45f0d --- /dev/null +++ b/DamageAssesmentApi/DamageAssesment.Api.Employees.Test/EmployeeServiceTest.cs @@ -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(); + 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(); + 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(); + var mockResponse = await MockData.getOkResponse("Emp1"); + mockEmployeeService.Setup(service => service.GetEmployeeByIdAsync("Emp1")).ReturnsAsync(mockResponse); + + var EmployeeProvider = new EmployeesController(mockEmployeeService.Object); + var result = (OkObjectResult)await EmployeeProvider.GetEmployeeByIdAsync("Emp1"); + + Assert.Equal(200, result.StatusCode); + } + + [Fact(DisplayName = "Get Employee by Id - NotFound case")] + public async Task GetEmployeeAsync_ShouldReturnStatusCode404() + { + var mockEmployeeService = new Mock(); + var mockResponse = await MockData.getNotFoundResponse(); + mockEmployeeService.Setup(service => service.GetEmployeeByIdAsync("Emp99")).ReturnsAsync(mockResponse); + + var EmployeeProvider = new EmployeesController(mockEmployeeService.Object); + var result = (NotFoundResult)await EmployeeProvider.GetEmployeeByIdAsync("Emp99"); + Assert.Equal(404, result.StatusCode); + } + + [Fact(DisplayName = "Post Employee - Ok case")] + public async Task PostEmployeeAsync_ShouldReturnStatusCode200() + { + var mockEmployeeService = new Mock(); + var mockResponse = await MockData.getOkResponse("Emp1"); + 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(); + 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(); + var mockResponse = await MockData.getOkResponse("Emp1"); + var mockInputEmployee = await MockData.getInputEmployeeData(); + mockEmployeeService.Setup(service => service.UpdateEmployeeAsync(mockInputEmployee)).ReturnsAsync(mockResponse); + + var EmployeeProvider = new EmployeesController(mockEmployeeService.Object); + var result = (OkObjectResult)await EmployeeProvider.UpdateEmployee(mockInputEmployee); + + Assert.Equal(200, result.StatusCode); + } + + [Fact(DisplayName = "Put Employee - NotFound case")] + public async Task PutEmployeeAsync_ShouldReturnStatusCode404() + { + var mockEmployeeService = new Mock(); + var mockResponse = await MockData.getNotFoundResponse(); + var mockInputEmployee = await MockData.getInputEmployeeData(); + mockEmployeeService.Setup(service => service.UpdateEmployeeAsync(mockInputEmployee)).ReturnsAsync(mockResponse); + + var EmployeeProvider = new EmployeesController(mockEmployeeService.Object); + var result = (NotFoundObjectResult)await EmployeeProvider.UpdateEmployee(mockInputEmployee); + + Assert.Equal(404, result.StatusCode); + } + + [Fact(DisplayName = "Put Employee - BadRequest case")] + public async Task PutEmployeeAsync_ShouldReturnStatusCode400() + { + var mockEmployeeService = new Mock(); + var mockResponse = await MockData.getBadRequestResponse(); + var mockInputEmployee = await MockData.getInputEmployeeData(); + mockEmployeeService.Setup(service => service.UpdateEmployeeAsync(mockInputEmployee)).ReturnsAsync(mockResponse); + + var EmployeeProvider = new EmployeesController(mockEmployeeService.Object); + var result = (BadRequestObjectResult)await EmployeeProvider.UpdateEmployee(mockInputEmployee); + + Assert.Equal(400, result.StatusCode); + } + + [Fact(DisplayName = "Delete Employee - Ok case")] + public async Task DeleteEmployeeAsync_ShouldReturnStatusCode200() + { + var mockEmployeeService = new Mock(); + var mockResponse = await MockData.getOkResponse("Emp1"); + + mockEmployeeService.Setup(service => service.DeleteEmployeeAsync("Emp1")).ReturnsAsync(mockResponse); + + var EmployeeProvider = new EmployeesController(mockEmployeeService.Object); + var result = (OkObjectResult)await EmployeeProvider.DeleteEmployee("Emp1"); + + Assert.Equal(200, result.StatusCode); + } + + [Fact(DisplayName = "Delete Employee - NotFound case")] + public async Task DeleteEmployeeAsync_ShouldReturnStatusCode404() + { + var mockEmployeeService = new Mock(); + var mockResponse = await MockData.getNotFoundResponse(); + mockEmployeeService.Setup(service => service.DeleteEmployeeAsync("Emp1")).ReturnsAsync(mockResponse); + + var EmployeeProvider = new EmployeesController(mockEmployeeService.Object); + var result = (NotFoundResult)await EmployeeProvider.DeleteEmployee("Emp1"); + + Assert.Equal(404, result.StatusCode); + } + } +} \ No newline at end of file diff --git a/DamageAssesmentApi/DamageAssesment.Api.Employees.Test/MockData.cs b/DamageAssesmentApi/DamageAssesment.Api.Employees.Test/MockData.cs new file mode 100644 index 0000000..cd5206e --- /dev/null +++ b/DamageAssesmentApi/DamageAssesment.Api.Employees.Test/MockData.cs @@ -0,0 +1,53 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace DamageAssesment.Api.Employees.Test +{ + public class MockData + { + + public static async Task<(bool, IEnumerable, string)> getOkResponse() + { + IEnumerable list = new List(); + + for (int i = 0; i < 10; i++) + { + list.Append(new Employees.Models.Employee { Id = "Emp"+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(string 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, Employees.Models.Employee, string)> getNotFoundResponse() + { + return (false, null, "Not Found"); + } + public static async Task<(bool, IEnumerable, string)> getNoContentResponse() + { + IEnumerable list = new List(); + return (false, list, null); + } + + public static async Task getInputEmployeeData() + { + return new Employees.Db.Employee { Id = "Emp1", Name = "ABC1", Email = "abc1@gmail.com", OfficePhoneNumber = "12345678", BirthDate = DateTime.Now.AddYears(-18), IsActive = true, PreferredLanguage = "en" }; + + } + + } +} diff --git a/DamageAssesmentApi/DamageAssesment.Api.Employees/Controllers/EmployeesController.cs b/DamageAssesmentApi/DamageAssesment.Api.Employees/Controllers/EmployeesController.cs new file mode 100644 index 0000000..192a9d0 --- /dev/null +++ b/DamageAssesmentApi/DamageAssesment.Api.Employees/Controllers/EmployeesController.cs @@ -0,0 +1,90 @@ +using DamageAssesment.Api.Employees.Interfaces; +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Mvc; + +namespace DamageAssesment.Api.Employees.Controllers +{ + [Route("api")] + [ApiController] + public class EmployeesController : ControllerBase + { + + private IEmployeesProvider EmployeeProvider; + + public EmployeesController(IEmployeesProvider EmployeesProvider) + { + this.EmployeeProvider = EmployeesProvider; + } + //get all Employees + [HttpGet("Employees")] + public async Task GetEmployeesAsync() + { + + var result = await EmployeeProvider.GetEmployeesAsync(); + if (result.IsSuccess) + { + return Ok(result.Employees); + } + return NoContent(); + + } + //get Employee based on Employeeid + [HttpGet("Employees/{Id}")] + public async Task GetEmployeeByIdAsync(string Id) + { + + var result = await EmployeeProvider.GetEmployeeByIdAsync(Id); + if (result.IsSuccess) + { + return Ok(result.Employee); + } + return NotFound(); + + } + //update existing Employee + + [HttpPut("Employees")] + public async Task UpdateEmployee(Db.Employee Employee) + { + if (Employee != null) + { + var result = await this.EmployeeProvider.UpdateEmployeeAsync(Employee); + if (result.IsSuccess) + { + return Ok(result.Employee); + } + if (result.ErrorMessage == "Not Found") + return NotFound(result.ErrorMessage); + + return BadRequest(result.ErrorMessage); + } + return NotFound(); + } + //save new Employee + [HttpPost("Employees")] + public async Task CreateEmployee(Db.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); + } + //delete existing Employee + [HttpDelete("Employees/{id}")] + public async Task DeleteEmployee(string id) + { + var result = await this.EmployeeProvider.DeleteEmployeeAsync(id); + if (result.IsSuccess) + { + return Ok(result.Employee); + } + return NotFound(); + } + } +} diff --git a/DamageAssesmentApi/DamageAssesment.Api.Employees/DamageAssesment.Api.Employees.csproj b/DamageAssesmentApi/DamageAssesment.Api.Employees/DamageAssesment.Api.Employees.csproj new file mode 100644 index 0000000..53e8700 --- /dev/null +++ b/DamageAssesmentApi/DamageAssesment.Api.Employees/DamageAssesment.Api.Employees.csproj @@ -0,0 +1,16 @@ + + + + net6.0 + enable + enable + + + + + + + + + + diff --git a/DamageAssesmentApi/DamageAssesment.Api.Employees/Db/Employee.cs b/DamageAssesmentApi/DamageAssesment.Api.Employees/Db/Employee.cs new file mode 100644 index 0000000..2b3202a --- /dev/null +++ b/DamageAssesmentApi/DamageAssesment.Api.Employees/Db/Employee.cs @@ -0,0 +1,23 @@ +using System.ComponentModel.DataAnnotations; + +namespace DamageAssesment.Api.Employees.Db +{ + public class Employee + { + [Key] + public string Id { 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"; + } +} diff --git a/DamageAssesmentApi/DamageAssesment.Api.Employees/Db/EmployeeDbContext.cs b/DamageAssesmentApi/DamageAssesment.Api.Employees/Db/EmployeeDbContext.cs new file mode 100644 index 0000000..64234cd --- /dev/null +++ b/DamageAssesmentApi/DamageAssesment.Api.Employees/Db/EmployeeDbContext.cs @@ -0,0 +1,14 @@ +using Microsoft.EntityFrameworkCore; + +namespace DamageAssesment.Api.Employees.Db +{ + public class EmployeeDbContext: DbContext + { + public DbSet Employees { get; set; } + public EmployeeDbContext(DbContextOptions options) : base(options) + { + + + } + } +} diff --git a/DamageAssesmentApi/DamageAssesment.Api.Employees/Interfaces/IEmployeesProvider.cs b/DamageAssesmentApi/DamageAssesment.Api.Employees/Interfaces/IEmployeesProvider.cs new file mode 100644 index 0000000..059483d --- /dev/null +++ b/DamageAssesmentApi/DamageAssesment.Api.Employees/Interfaces/IEmployeesProvider.cs @@ -0,0 +1,11 @@ +namespace DamageAssesment.Api.Employees.Interfaces +{ + public interface IEmployeesProvider + { + Task<(bool IsSuccess, IEnumerable Employees, string ErrorMessage)> GetEmployeesAsync(); + Task<(bool IsSuccess, Models.Employee Employee, string ErrorMessage)> GetEmployeeByIdAsync(string Id); + Task<(bool IsSuccess, Models.Employee Employee, string ErrorMessage)> PostEmployeeAsync(Db.Employee Employee); + Task<(bool IsSuccess, Models.Employee Employee, string ErrorMessage)> UpdateEmployeeAsync(Db.Employee Employee); + Task<(bool IsSuccess, Models.Employee Employee, string ErrorMessage)> DeleteEmployeeAsync(string Id); + } +} diff --git a/DamageAssesmentApi/DamageAssesment.Api.Employees/Models/Employee.cs b/DamageAssesmentApi/DamageAssesment.Api.Employees/Models/Employee.cs new file mode 100644 index 0000000..37afe32 --- /dev/null +++ b/DamageAssesmentApi/DamageAssesment.Api.Employees/Models/Employee.cs @@ -0,0 +1,23 @@ +using System.ComponentModel.DataAnnotations; + +namespace DamageAssesment.Api.Employees.Models +{ + public class Employee + { + [Key] + public string Id { 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"; + } +} diff --git a/DamageAssesmentApi/DamageAssesment.Api.Employees/Profiles/EmployeesProfile.cs b/DamageAssesmentApi/DamageAssesment.Api.Employees/Profiles/EmployeesProfile.cs new file mode 100644 index 0000000..444752b --- /dev/null +++ b/DamageAssesmentApi/DamageAssesment.Api.Employees/Profiles/EmployeesProfile.cs @@ -0,0 +1,12 @@ +using AutoMapper; + +namespace DamageAssesment.Api.Employees.Profiles +{ + public class EmployeesProfile:AutoMapper.Profile + { + public EmployeesProfile() + { + CreateMap(); + } + } +} diff --git a/DamageAssesmentApi/DamageAssesment.Api.Employees/Program.cs b/DamageAssesmentApi/DamageAssesment.Api.Employees/Program.cs new file mode 100644 index 0000000..29b91fa --- /dev/null +++ b/DamageAssesmentApi/DamageAssesment.Api.Employees/Program.cs @@ -0,0 +1,34 @@ +using DamageAssesment.Api.Employees.Db; +using DamageAssesment.Api.Employees.Interfaces; +using DamageAssesment.Api.Employees.Providers; +using Microsoft.EntityFrameworkCore; + +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.AddScoped(); +builder.Services.AddAutoMapper(AppDomain.CurrentDomain.GetAssemblies()); //4/30 +builder.Services.AddDbContext(option => +{ + option.UseInMemoryDatabase("Employees"); +}); + +var app = builder.Build(); + +// Configure the HTTP request pipeline. +if (app.Environment.IsDevelopment()) +{ + app.UseSwagger(); + app.UseSwaggerUI(); +} + +app.UseAuthorization(); + +app.MapControllers(); + +app.Run(); diff --git a/DamageAssesmentApi/DamageAssesment.Api.Employees/Properties/launchSettings.json b/DamageAssesmentApi/DamageAssesment.Api.Employees/Properties/launchSettings.json new file mode 100644 index 0000000..2c81744 --- /dev/null +++ b/DamageAssesmentApi/DamageAssesment.Api.Employees/Properties/launchSettings.json @@ -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" + } + } + } +} diff --git a/DamageAssesmentApi/DamageAssesment.Api.Employees/Providers/EmployeesProvider.cs b/DamageAssesmentApi/DamageAssesment.Api.Employees/Providers/EmployeesProvider.cs new file mode 100644 index 0000000..b2ec99b --- /dev/null +++ b/DamageAssesmentApi/DamageAssesment.Api.Employees/Providers/EmployeesProvider.cs @@ -0,0 +1,164 @@ +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 logger; + private IMapper mapper; + + public EmployeesProvider(EmployeeDbContext EmployeeDbContext, ILogger logger, IMapper mapper) + { + this.EmployeeDbContext = EmployeeDbContext; + this.logger = logger; + this.mapper = mapper; + SeedData(); + } + + public async Task<(bool IsSuccess, IEnumerable 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>(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(string Id) + { + try + { + logger?.LogInformation("Query Employee"); + var Employee = await EmployeeDbContext.Employees.AsNoTracking().FirstOrDefaultAsync(q => q.Id.ToLower() == Id.ToLower()); + if (Employee != null) + { + logger?.LogInformation($"{Employee} customer(s) found"); + var result = mapper.Map(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(Db.Employee Employee) + { + try + { + logger?.LogInformation("Query Employee"); + if (!EmployeeExists(Employee.Id)) + { + EmployeeDbContext.Employees.Add(Employee); + EmployeeDbContext.SaveChanges(); + var result = mapper.Map(Employee); + return (true, result, null); + } + return (false, null, "Employee 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(Db.Employee Employee) + { + try + { + if (Employee != null) + { + var _employee = await EmployeeDbContext.Employees.AsNoTracking().Where(s => s.Id.ToLower() == Employee.Id.ToLower()).FirstOrDefaultAsync(); + + if (_employee != null) + { + EmployeeDbContext.Employees.Update(Employee); + EmployeeDbContext.SaveChanges(); + return (true, mapper.Map(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(string Id) + { + try + { + Db.Employee Employee = EmployeeDbContext.Employees.AsNoTracking().Where(a => a.Id.ToLower() == Id.ToLower()).FirstOrDefault(); + if (Employee == null) + { + return (false, null, "Not Found"); + } + EmployeeDbContext.Employees.Remove(Employee); + EmployeeDbContext.SaveChanges(); + return (true, mapper.Map(Employee), $"EmployeeId {Id} deleted Successfuly"); + } + catch (Exception ex) + { + + logger?.LogError(ex.ToString()); + return (false,null, ex.Message); + } + } + private bool EmployeeExists(string id) + { + return EmployeeDbContext.Employees.AsNoTracking().Count(e => e.Id.ToLower() == id.ToLower()) > 0; + } + + private void SeedData() + { + if (!EmployeeDbContext.Employees.Any()) + { + EmployeeDbContext.Employees.Add(new Db.Employee() { Id = "Emp1", Name = "ABC1", Email = "abc1@gmail.com", OfficePhoneNumber = "12345678",BirthDate=DateTime.Now.AddYears(-18), IsActive = true,PreferredLanguage="en" }); + EmployeeDbContext.Employees.Add(new Db.Employee() { Id = "Emp2", Name = "ABC2", Email = "abc2@gmail.com", OfficePhoneNumber = "12345678", BirthDate = DateTime.Now.AddYears(-22), IsActive = true, PreferredLanguage = "fr" }); + EmployeeDbContext.Employees.Add(new Db.Employee() { Id = "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 = "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 = "Emp5", Name = "ABC5", Email = "abc5@gmail.com", OfficePhoneNumber = "12345678", BirthDate = DateTime.Now.AddYears(-23) ,IsActive = true, PreferredLanguage = "sp" }); + EmployeeDbContext.Employees.Add(new Db.Employee() { Id = "Emp6", Name = "ABC6", Email = "abc6@gmail.com", OfficePhoneNumber = "12345678", BirthDate = DateTime.Now.AddYears(-32) ,IsActive = true, PreferredLanguage = "sp" }); + EmployeeDbContext.SaveChanges(); + } + + } + + + + } +} diff --git a/DamageAssesmentApi/DamageAssesment.Api.Employees/appsettings.Development.json b/DamageAssesmentApi/DamageAssesment.Api.Employees/appsettings.Development.json new file mode 100644 index 0000000..0c208ae --- /dev/null +++ b/DamageAssesmentApi/DamageAssesment.Api.Employees/appsettings.Development.json @@ -0,0 +1,8 @@ +{ + "Logging": { + "LogLevel": { + "Default": "Information", + "Microsoft.AspNetCore": "Warning" + } + } +} diff --git a/DamageAssesmentApi/DamageAssesment.Api.Employees/appsettings.json b/DamageAssesmentApi/DamageAssesment.Api.Employees/appsettings.json new file mode 100644 index 0000000..1cf89f5 --- /dev/null +++ b/DamageAssesmentApi/DamageAssesment.Api.Employees/appsettings.json @@ -0,0 +1,14 @@ +{ + "Logging": { + "LogLevel": { + "Default": "Information", + "Microsoft.AspNetCore": "Warning" + } + }, + "AllowedHosts": "*", + "settings": { + "endpoint1": "xxx", + "endpoint2": "xxx", + "endpoint3": "xxx" + } +} diff --git a/DamageAssesmentApi/DamageAssesment.Api.Locations.Test/DamageAssesment.Api.Locations.Test.csproj b/DamageAssesmentApi/DamageAssesment.Api.Locations.Test/DamageAssesment.Api.Locations.Test.csproj new file mode 100644 index 0000000..ee2a779 --- /dev/null +++ b/DamageAssesmentApi/DamageAssesment.Api.Locations.Test/DamageAssesment.Api.Locations.Test.csproj @@ -0,0 +1,30 @@ + + + + net6.0 + enable + enable + + false + true + + + + + + + + runtime; build; native; contentfiles; analyzers; buildtransitive + all + + + runtime; build; native; contentfiles; analyzers; buildtransitive + all + + + + + + + + diff --git a/DamageAssesmentApi/DamageAssesment.Api.Locations.Test/LocationsServiceTest.cs b/DamageAssesmentApi/DamageAssesment.Api.Locations.Test/LocationsServiceTest.cs new file mode 100644 index 0000000..270c638 --- /dev/null +++ b/DamageAssesmentApi/DamageAssesment.Api.Locations.Test/LocationsServiceTest.cs @@ -0,0 +1,294 @@ +using AutoMapper; +using DamageAssesment.Api.Locations.Controllers; +using DamageAssesment.Api.Locations.Db; +using DamageAssesment.Api.Locations.Interfaces; +using DamageAssesment.Api.Locations.Profiles; +using DamageAssesment.Api.Locations.Providers; +using Microsoft.AspNetCore.Mvc; +using Microsoft.EntityFrameworkCore; +using Moq; +using Xunit; + +namespace DamageAssesment.Api.Locations.Test +{ + public class LocationsServiceTest + { + + [Fact(DisplayName = "Get Location using Location ID")] + public async Task GetLocationsUsingLocationID() + { + var options = new DbContextOptionsBuilder() + .UseInMemoryDatabase(nameof(GetLocationsUsingLocationID)) + .Options; + + var dbContext = new LocationDbContext(options); + CreateLocations(dbContext); + //Mapping + var LocationsProfile = new LocationProfile(); + var configuration = new MapperConfiguration(cfg => cfg.AddProfile(LocationsProfile)); + var mapper = new Mapper(configuration); + + var LocationsProvider = new LocationsProvider(dbContext, null, mapper); + //Testmethode + var Location = await LocationsProvider.GetLocationByIdAsync("Loc3"); + + Assert.True(Location.IsSuccess); + Assert.Null(Location.ErrorMessage); + } + [Fact(DisplayName = "Get Locations")] + public async Task GetAllLocationsTest() + { + var options = new DbContextOptionsBuilder() + .UseInMemoryDatabase(nameof(GetLocationsUsingLocationID)) + .Options; + + var dbContext = new LocationDbContext(options); + CreateLocations(dbContext); + //Mapping + var LocationsProfile = new LocationProfile(); + var configuration = new MapperConfiguration(cfg => cfg.AddProfile(LocationsProfile)); + var mapper = new Mapper(configuration); + + var LocationsProvider = new LocationsProvider(dbContext, null, mapper); + //Testmethode + var Location = await LocationsProvider.GetLocationsAsync(); + + Assert.True(Location.IsSuccess); + Assert.Null(Location.ErrorMessage); + } + + [Fact(DisplayName = "Delete Location by Id")] + public async Task DeleteLocationTest() + { + var options = new DbContextOptionsBuilder() + .UseInMemoryDatabase(nameof(GetLocationsUsingLocationID)) + .Options; + + var dbContext = new LocationDbContext(options); + CreateLocations(dbContext); + //Mapping + var LocationsProfile = new LocationProfile(); + var configuration = new MapperConfiguration(cfg => cfg.AddProfile(LocationsProfile)); + var mapper = new Mapper(configuration); + + var LocationsProvider = new LocationsProvider(dbContext, null, mapper); + //Testmethode + var Location = await LocationsProvider.DeleteLocationAsync("Loc2"); + + Assert.True(Location.IsSuccess); + Assert.NotNull(Location.ErrorMessage); + } + [Fact(DisplayName = "Add Location")] + public async Task AddLocationTest() + { + var options = new DbContextOptionsBuilder() + .UseInMemoryDatabase(nameof(GetLocationsUsingLocationID)) + .Options; + + var dbContext = new LocationDbContext(options); + CreateLocations(dbContext); + //Mapping + var LocationsProfile = new LocationProfile(); + var configuration = new MapperConfiguration(cfg => cfg.AddProfile(LocationsProfile)); + var mapper = new Mapper(configuration); + var LocationsProvider = new LocationsProvider(dbContext, null, mapper); + //Testmethode + Db.Location newLocation = new Db.Location() { Id = "Loc9", RegionId = "1", Name = "Test 1", MaintenanceCenter = "1", SchoolType = "US" }; + var Location = await LocationsProvider.PostLocationAsync(newLocation); + + Assert.True(Location.IsSuccess); + Assert.Null(Location.ErrorMessage); + } + [Fact(DisplayName = "Update Location")] + public async Task UpdateLocationTest() + { + var options = new DbContextOptionsBuilder() + .UseInMemoryDatabase(nameof(GetLocationsUsingLocationID)) + .Options; + var dbContext = new LocationDbContext(options); + CreateLocations(dbContext); + //Mapping + var LocationsProfile = new LocationProfile(); + var configuration = new MapperConfiguration(cfg => cfg.AddProfile(LocationsProfile)); + var mapper = new Mapper(configuration); + var LocationsProvider = new LocationsProvider(dbContext, null, mapper); + //Testmethode + Db.Location updateLocation = new Db.Location() { Id = "Loc1", RegionId = "1", Name = "Tampa", MaintenanceCenter = "1", SchoolType = "NA" }; + var Location = await LocationsProvider.UpdateLocationAsync(updateLocation); + var modified = dbContext.Locations.FirstOrDefault(a => a.Id == updateLocation.Id); + Assert.True(Location.IsSuccess); + Assert.NotNull(Location.ErrorMessage); + } + private static void CreateLocations(LocationDbContext dbContext) + { + //Create sample data for testing + if (dbContext.Locations.Count() == 0) + { + for (int i = 1; i < 6; i++) + { + dbContext.Locations.Add(new Db.Location() + { + Id = "Loc"+i.ToString(), + RegionId = i.ToString(), + Name = "Test Location" + Guid.NewGuid().ToString(), + MaintenanceCenter = i.ToString(), + SchoolType = "US" + + }); + } + dbContext.SaveChanges(); + } + } + + //Tests for regions + + [Fact(DisplayName = "Get Regions - Ok case")] + public async Task GetRegionsAsync_ShouldReturnStatusCode200() + { + var mockRegionService = new Mock(); + 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(); + 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(); + 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(); + var mockResponse = await MockData.getNotFoundResponse(); + mockRegionService.Setup(service => service.GetRegionByIdAsync("99")).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 PostSurveyAsync_ShouldReturnStatusCode200() + { + var mockRegionService = new Mock(); + 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 PostSurveyAsync_ShouldReturnStatusCode400() + { + var mockRegionService = new Mock(); + 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(); + var mockResponse = await MockData.getOkResponse("1"); + var mockInputRegion = await MockData.getInputRegionData(); + mockRegionService.Setup(service => service.PutRegionAsync(mockInputRegion)).ReturnsAsync(mockResponse); + + var regionProvider = new RegionsController(mockRegionService.Object); + var result = (OkObjectResult)await regionProvider.PutRegionAsync(mockInputRegion); + + Assert.Equal(200, result.StatusCode); + } + + [Fact(DisplayName = "Put Region - NotFound case")] + public async Task PutSurveyAsync_ShouldReturnStatusCode404() + { + var mockRegionService = new Mock(); + var mockResponse = await MockData.getNotFoundResponse(); + var mockInputRegion = await MockData.getInputRegionData(); + mockRegionService.Setup(service => service.PutRegionAsync(mockInputRegion)).ReturnsAsync(mockResponse); + + var regionProvider = new RegionsController(mockRegionService.Object); + var result = (NotFoundObjectResult)await regionProvider.PutRegionAsync(mockInputRegion); + + Assert.Equal(404, result.StatusCode); + } + + [Fact(DisplayName = "Put Region - BadRequest case")] + public async Task PutSurveyAsync_ShouldReturnStatusCode400() + { + var mockRegionService = new Mock(); + var mockResponse = await MockData.getBadRequestResponse(); + var mockInputRegion = await MockData.getInputRegionData(); + mockRegionService.Setup(service => service.PutRegionAsync(mockInputRegion)).ReturnsAsync(mockResponse); + + var regionProvider = new RegionsController(mockRegionService.Object); + var result = (BadRequestObjectResult)await regionProvider.PutRegionAsync(mockInputRegion); + + Assert.Equal(400, result.StatusCode); + } + + [Fact(DisplayName = "Delete Region - Ok case")] + public async Task DeleteSurveyAsync_ShouldReturnStatusCode200() + { + var mockRegionService = new Mock(); + 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 DeleteSurveyAsync_ShouldReturnStatusCode404() + { + var mockRegionService = new Mock(); + 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); + } + } +} \ No newline at end of file diff --git a/DamageAssesmentApi/DamageAssesment.Api.Locations.Test/MockData.cs b/DamageAssesmentApi/DamageAssesment.Api.Locations.Test/MockData.cs new file mode 100644 index 0000000..cd6b85e --- /dev/null +++ b/DamageAssesmentApi/DamageAssesment.Api.Locations.Test/MockData.cs @@ -0,0 +1,46 @@ +using System.Text; +namespace DamageAssesment.Api.Locations.Test +{ + public class MockData + { + public static async Task<(bool, IEnumerable, string)> getOkResponse() + { + IEnumerable list = new List(); + + for (int i = 0; i < 10; i++) + { + list.Append(new Locations.Models.Region { Id = "R" + i, Abbreviation = "AB" + i, Name = "Region " + i }); + } + return (true, list, null); + } + + + public static async Task<(bool, Locations.Models.Region, string)> getOkResponse(string Id) + { + var surveys = await getOkResponse(); + var survey = surveys.Item2.FirstOrDefault(s => s.Id == Id); + return (true, survey, null); + } + + 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, string)> getNoContentResponse() + { + IEnumerable list = new List(); + return (false, list, null); + } + + public static async Task getInputRegionData() + { + return new Locations.Models.Region { Id = "R99", Name = "Region 99", Abbreviation = "A99" }; + } + + } +} diff --git a/DamageAssesmentApi/DamageAssesment.Api.Locations/Controllers/LocationsController.cs b/DamageAssesmentApi/DamageAssesment.Api.Locations/Controllers/LocationsController.cs new file mode 100644 index 0000000..c1df10f --- /dev/null +++ b/DamageAssesmentApi/DamageAssesment.Api.Locations/Controllers/LocationsController.cs @@ -0,0 +1,85 @@ +using DamageAssesment.Api.Locations.Interfaces; +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Mvc; + +namespace DamageAssesment.Api.Locations.Controllers +{ + [Route("api")] + [ApiController] + public class LocationsController : ControllerBase + { + private ILocationsProvider LocationProvider; + + public LocationsController(ILocationsProvider LocationsProvider) + { + this.LocationProvider = LocationsProvider; + } + // Get all Locations + [HttpGet("Locations")] + public async Task GetLocationsAsync() + { + + var result = await LocationProvider.GetLocationsAsync(); + if (result.IsSuccess) + { + return Ok(result.locations); + } + return NotFound(); + + } + // Get all Location based on Id + [HttpGet("Locations/{id}")] + public async Task GetLocationByIdAsync(string id) + { + + var result = await LocationProvider.GetLocationByIdAsync(id); + if (result.IsSuccess) + { + return Ok(result.Location); + } + return NotFound(); + + } + // Update Location entity + [HttpPut("Locations")] + public async Task UpdateLocation(Db.Location Location) + { + if (Location != null) + { + var result = await this.LocationProvider.UpdateLocationAsync(Location); + if (result.IsSuccess) + { + return Ok(result.ErrorMessage); + } + return NotFound(); + } + return NotFound(); + } + //save new location + [HttpPost("Locations")] + public async Task CreateLocation(Db.Location Location) + { + if (Location != null) + { + var result = await this.LocationProvider.PostLocationAsync(Location); + if (result.IsSuccess) + { + return Ok(result.Question); + } + return NotFound(); + } + return CreatedAtRoute("DefaultApi", new { id = Location.Id }, Location); + } + //delete existing location + [HttpDelete("Locations/{id}")] + public async Task DeleteLocation(string id) + { + var result = await this.LocationProvider.DeleteLocationAsync(id); + if (result.IsSuccess) + { + return Ok(result.ErrorMessage); + } + return NotFound(); + } + } +} diff --git a/DamageAssesmentApi/DamageAssesment.Api.Locations/Controllers/RegionsController.cs b/DamageAssesmentApi/DamageAssesment.Api.Locations/Controllers/RegionsController.cs new file mode 100644 index 0000000..64a9bc7 --- /dev/null +++ b/DamageAssesmentApi/DamageAssesment.Api.Locations/Controllers/RegionsController.cs @@ -0,0 +1,76 @@ +using DamageAssesment.Api.Locations.Interfaces; +using Microsoft.AspNetCore.Mvc; + +namespace DamageAssesment.Api.Locations.Controllers +{ + [Route("api/[controller]")] + [ApiController] + public class RegionsController : ControllerBase + { + private readonly IRegionsProvider regionProvider; + + public RegionsController(IRegionsProvider regionProvider) + { + this.regionProvider = regionProvider; + } + + // Get all Regions + [HttpGet] + public async Task GetRegionsAsync() + { + var result = await regionProvider.GetRegionsAsync(); + if (result.IsSuccess) + { + return Ok(result.regions); + } + return NoContent(); + } + + [HttpGet("{Id}")] + public async Task GetRegionAsync(string Id) + { + var result = await this.regionProvider.GetRegionByIdAsync(Id); + if (result.IsSuccess) + { + return Ok(result.Region); + } + return NotFound(); + } + + [HttpPost] + public async Task PostRegionAsync(Models.Region region) + { + var result = await this.regionProvider.PostRegionAsync(region); + if (result.IsSuccess) + { + return Ok(result.Region); + } + return BadRequest(result.ErrorMessage); + } + + [HttpPut] + public async Task PutRegionAsync(Models.Region region) + { + var result = await this.regionProvider.PutRegionAsync(region); + if (result.IsSuccess) + { + return Ok(result.Region); + } + if (result.ErrorMessage.Equals("Not Found")) + return NotFound(result.ErrorMessage); + + return BadRequest(result.ErrorMessage); + } + + [HttpDelete("{Id}")] + public async Task DeleteRegionAsync(string Id) + { + var result = await this.regionProvider.DeleteRegionAsync(Id); + if (result.IsSuccess) + { + return Ok(result.Region); + } + return NotFound(); + } + } +} diff --git a/DamageAssesmentApi/DamageAssesment.Api.Locations/DamageAssesment.Api.Locations.csproj b/DamageAssesmentApi/DamageAssesment.Api.Locations/DamageAssesment.Api.Locations.csproj new file mode 100644 index 0000000..47751c7 --- /dev/null +++ b/DamageAssesmentApi/DamageAssesment.Api.Locations/DamageAssesment.Api.Locations.csproj @@ -0,0 +1,16 @@ + + + + net6.0 + enable + enable + + + + + + + + + + diff --git a/DamageAssesmentApi/DamageAssesment.Api.Locations/Db/Location.cs b/DamageAssesmentApi/DamageAssesment.Api.Locations/Db/Location.cs new file mode 100644 index 0000000..98afcf2 --- /dev/null +++ b/DamageAssesmentApi/DamageAssesment.Api.Locations/Db/Location.cs @@ -0,0 +1,23 @@ +using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations.Schema; + +namespace DamageAssesment.Api.Locations.Db +{ + public class Location + { + [Key] + [StringLength(4)] + public string Id { get; set; } + + [StringLength(50)] + public string Name { get; set; } + + [StringLength(1)] + public string MaintenanceCenter { get; set; } + + [StringLength(2)] + public string SchoolType { get; set; } + [ForeignKey("Region")] + public string RegionId { get; set; } + } +} diff --git a/DamageAssesmentApi/DamageAssesment.Api.Locations/Db/LocationDbContext.cs b/DamageAssesmentApi/DamageAssesment.Api.Locations/Db/LocationDbContext.cs new file mode 100644 index 0000000..407faca --- /dev/null +++ b/DamageAssesmentApi/DamageAssesment.Api.Locations/Db/LocationDbContext.cs @@ -0,0 +1,14 @@ +using Microsoft.EntityFrameworkCore; + +namespace DamageAssesment.Api.Locations.Db +{ + public class LocationDbContext:DbContext + { + public DbSet Locations { get; set; } + public DbSet Regions { get; set; } + public LocationDbContext(DbContextOptions options) : base(options) + { + + } + } +} diff --git a/DamageAssesmentApi/DamageAssesment.Api.Locations/Db/Region.cs b/DamageAssesmentApi/DamageAssesment.Api.Locations/Db/Region.cs new file mode 100644 index 0000000..7c03858 --- /dev/null +++ b/DamageAssesmentApi/DamageAssesment.Api.Locations/Db/Region.cs @@ -0,0 +1,19 @@ +using System.ComponentModel.DataAnnotations; + +namespace DamageAssesment.Api.Locations.Db +{ + public class Region + { + [Key] + [StringLength(2)] + public string Id { get; set; } + + [StringLength(50)] + public string Name { get; set; } + + [StringLength(5)] + public string Abbreviation { get; set; } + + // public ICollection Locations { get; set; } + } +} diff --git a/DamageAssesmentApi/DamageAssesment.Api.Locations/Interfaces/ILocationsProvider.cs b/DamageAssesmentApi/DamageAssesment.Api.Locations/Interfaces/ILocationsProvider.cs new file mode 100644 index 0000000..8e85496 --- /dev/null +++ b/DamageAssesmentApi/DamageAssesment.Api.Locations/Interfaces/ILocationsProvider.cs @@ -0,0 +1,13 @@ +using DamageAssesment.Api.Locations.Db; + +namespace DamageAssesment.Api.Locations.Interfaces +{ + public interface ILocationsProvider + { + Task<(bool IsSuccess, IEnumerable locations, string ErrorMessage)> GetLocationsAsync(); + Task<(bool IsSuccess, Models.Location Location, string ErrorMessage)> GetLocationByIdAsync(string Id); + Task<(bool IsSuccess, Models.Location Question, string ErrorMessage)> PostLocationAsync(Db.Location Location); + Task<(bool IsSuccess, string ErrorMessage)> UpdateLocationAsync(Db.Location Location); + Task<(bool IsSuccess, string ErrorMessage)> DeleteLocationAsync(string Id); + } +} diff --git a/DamageAssesmentApi/DamageAssesment.Api.Locations/Interfaces/IRegionsProvider.cs b/DamageAssesmentApi/DamageAssesment.Api.Locations/Interfaces/IRegionsProvider.cs new file mode 100644 index 0000000..1df0776 --- /dev/null +++ b/DamageAssesmentApi/DamageAssesment.Api.Locations/Interfaces/IRegionsProvider.cs @@ -0,0 +1,11 @@ +namespace DamageAssesment.Api.Locations.Interfaces +{ + public interface IRegionsProvider + { + Task<(bool IsSuccess, IEnumerable regions, string ErrorMessage)> GetRegionsAsync(); + Task<(bool IsSuccess, Models.Region Region, string ErrorMessage)> GetRegionByIdAsync(string Id); + Task<(bool IsSuccess, Models.Region Region, string ErrorMessage)> PostRegionAsync(Models.Region region); + Task<(bool IsSuccess, Models.Region Region, string ErrorMessage)> PutRegionAsync(Models.Region region); + Task<(bool IsSuccess, Models.Region Region, string ErrorMessage)> DeleteRegionAsync(string Id); + } +} diff --git a/DamageAssesmentApi/DamageAssesment.Api.Locations/Models/Location.cs b/DamageAssesmentApi/DamageAssesment.Api.Locations/Models/Location.cs new file mode 100644 index 0000000..1fdad6a --- /dev/null +++ b/DamageAssesmentApi/DamageAssesment.Api.Locations/Models/Location.cs @@ -0,0 +1,22 @@ +using System.ComponentModel.DataAnnotations; + +namespace DamageAssesment.Api.Locations.Models +{ + public class Location + { + [StringLength(4)] + public string Id { get; set; } + + [StringLength(1)] + public string RegionId { get; set; } + + [StringLength(50)] + public string Name { get; set; } + + [StringLength(1)] + public string MaintenanceCenter { get; set; } + + [StringLength(2)] + public string SchoolType { get; set; } + } +} diff --git a/DamageAssesmentApi/DamageAssesment.Api.Locations/Models/Region.cs b/DamageAssesmentApi/DamageAssesment.Api.Locations/Models/Region.cs new file mode 100644 index 0000000..ebcabeb --- /dev/null +++ b/DamageAssesmentApi/DamageAssesment.Api.Locations/Models/Region.cs @@ -0,0 +1,17 @@ +using System.ComponentModel.DataAnnotations; + +namespace DamageAssesment.Api.Locations.Models +{ + public class Region + { + + [StringLength(1)] + public string Id { get; set; } + + [StringLength(50)] + public string Name { get; set; } + + [StringLength(5)] + public string Abbreviation { get; set; } + } +} diff --git a/DamageAssesmentApi/DamageAssesment.Api.Locations/Profiles/LocationProfile.cs b/DamageAssesmentApi/DamageAssesment.Api.Locations/Profiles/LocationProfile.cs new file mode 100644 index 0000000..ca91e6a --- /dev/null +++ b/DamageAssesmentApi/DamageAssesment.Api.Locations/Profiles/LocationProfile.cs @@ -0,0 +1,10 @@ +namespace DamageAssesment.Api.Locations.Profiles +{ + public class LocationProfile : AutoMapper.Profile + { + public LocationProfile() + { + CreateMap(); + } + } +} diff --git a/DamageAssesmentApi/DamageAssesment.Api.Locations/Profiles/RegionProfile.cs b/DamageAssesmentApi/DamageAssesment.Api.Locations/Profiles/RegionProfile.cs new file mode 100644 index 0000000..9ca15a1 --- /dev/null +++ b/DamageAssesmentApi/DamageAssesment.Api.Locations/Profiles/RegionProfile.cs @@ -0,0 +1,11 @@ +namespace DamageAssesment.Api.Locations.Profiles +{ + public class RegionProfile : AutoMapper.Profile + { + public RegionProfile() + { + CreateMap(); + CreateMap(); + } + } +} diff --git a/DamageAssesmentApi/DamageAssesment.Api.Locations/Program.cs b/DamageAssesmentApi/DamageAssesment.Api.Locations/Program.cs new file mode 100644 index 0000000..a2e3149 --- /dev/null +++ b/DamageAssesmentApi/DamageAssesment.Api.Locations/Program.cs @@ -0,0 +1,35 @@ +using DamageAssesment.Api.Locations.Db; +using DamageAssesment.Api.Locations.Interfaces; +using DamageAssesment.Api.Locations.Providers; +using Microsoft.EntityFrameworkCore; + +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.AddScoped(); +builder.Services.AddScoped(); +builder.Services.AddAutoMapper(AppDomain.CurrentDomain.GetAssemblies()); //4/30 +builder.Services.AddDbContext(option => +{ + option.UseInMemoryDatabase("Locations"); +}); +var app = builder.Build(); + +// Configure the HTTP request pipeline. +if (app.Environment.IsDevelopment()) +{ + app.UseSwagger(); + app.UseSwaggerUI(); +} + +app.UseAuthorization(); + +app.MapControllers(); + +app.Run(); diff --git a/DamageAssesmentApi/DamageAssesment.Api.Locations/Properties/launchSettings.json b/DamageAssesmentApi/DamageAssesment.Api.Locations/Properties/launchSettings.json new file mode 100644 index 0000000..940c35e --- /dev/null +++ b/DamageAssesmentApi/DamageAssesment.Api.Locations/Properties/launchSettings.json @@ -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" + } + } + } +} diff --git a/DamageAssesmentApi/DamageAssesment.Api.Locations/Providers/LocationsProvider.cs b/DamageAssesmentApi/DamageAssesment.Api.Locations/Providers/LocationsProvider.cs new file mode 100644 index 0000000..fcba375 --- /dev/null +++ b/DamageAssesmentApi/DamageAssesment.Api.Locations/Providers/LocationsProvider.cs @@ -0,0 +1,147 @@ +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 logger; + private IMapper mapper; + + public LocationsProvider(LocationDbContext locationDbContext, ILogger logger, IMapper mapper) + { + this.locationDbContext = locationDbContext; + this.logger = logger; + this.mapper = mapper; + SeedData(); + } + + public async Task<(bool IsSuccess, IEnumerable locations, string ErrorMessage)> GetLocationsAsync() + { + + try + { + logger?.LogInformation("Query Question"); + var Location = await locationDbContext.Locations.AsNoTracking().ToListAsync(); + if (Location != null) + { + logger?.LogInformation($"{Location.Count} Locations(s) found"); + var result = mapper.Map, IEnumerable>(Location); + 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(string Id) + { + try + { + logger?.LogInformation("Query Location"); + var Location = await locationDbContext.Locations.AsNoTracking().FirstOrDefaultAsync(q => q.Id == Id); + if (Location != null) + { + logger?.LogInformation($"{Location} customer(s) found"); + var result = mapper.Map(Location); + 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 Question, string ErrorMessage)> PostLocationAsync(Db.Location Location) + { + try + { + logger?.LogInformation("Query Location"); + if (!LocationExists(Location.Id)) + { + locationDbContext.Locations.Add(Location); + locationDbContext.SaveChanges(); + var result = mapper.Map(Location); + return (true, result, null); + } + else + { + return (false, null, "Location is Already exists"); + } + } + catch (Exception ex) + { + logger?.LogError(ex.ToString()); + return (false, null, ex.Message); + } + } + public async Task<(bool IsSuccess, string ErrorMessage)> UpdateLocationAsync(Db.Location Location) + { + try + { + locationDbContext.Entry(Location).State = EntityState.Modified; + locationDbContext.SaveChanges(); + return (true, "Record updated successfully"); + } + catch (Exception ex) + { + + logger?.LogError(ex.ToString()); + return (false, ex.Message); + } + } + public async Task<(bool IsSuccess, string ErrorMessage)> DeleteLocationAsync(string Id) + { + try + { + Db.Location Location = locationDbContext.Locations.AsNoTracking().Where(a => a.Id == Id).FirstOrDefault(); + if (Location == null) + { + return (false, "record not found"); + } + locationDbContext.Locations.Remove(Location); + locationDbContext.SaveChanges(); + return (true, "Record deleted successfully"); + } + catch (Exception ex) + { + + logger?.LogError(ex.ToString()); + return (false, ex.Message); + } + } + + private bool LocationExists(string id) + { + return locationDbContext.Locations.AsNoTracking().Count(e => e.Id == id) > 0; + } + private void SeedData() + { + if (!locationDbContext.Locations.Any()) + { + locationDbContext.Locations.Add(new Db.Location() { Id = "Loc1", RegionId = "1", Name = "BOB GRAHAM EDUCATION CENTER 1", MaintenanceCenter = "1", SchoolType = "US" }); + locationDbContext.Locations.Add(new Db.Location() { Id = "Loc2", RegionId = "2", Name = "BOB GRAHAM EDUCATION CENTER 2", MaintenanceCenter = "1", SchoolType = "US" }); + locationDbContext.Locations.Add(new Db.Location() { Id = "Loc3", RegionId = "3", Name = "BOB GRAHAM EDUCATION CENTER 3", MaintenanceCenter = "1", SchoolType = "US" }); + locationDbContext.Locations.Add(new Db.Location() { Id = "Loc4", RegionId = "1", Name = "BOB GRAHAM EDUCATION CENTER 4", MaintenanceCenter = "1", SchoolType = "US" }); + locationDbContext.Locations.Add(new Db.Location() { Id = "Loc5", RegionId = "2", Name = "BOB GRAHAM EDUCATION CENTER 5", MaintenanceCenter = "1", SchoolType = "US" }); + locationDbContext.Locations.Add(new Db.Location() { Id = "Loc6", RegionId = "3", Name = "BOB GRAHAM EDUCATION CENTER 6", MaintenanceCenter = "1", SchoolType = "US" }); + locationDbContext.SaveChanges(); + } + + } + + + + } +} diff --git a/DamageAssesmentApi/DamageAssesment.Api.Locations/Providers/RegionsProvider.cs b/DamageAssesmentApi/DamageAssesment.Api.Locations/Providers/RegionsProvider.cs new file mode 100644 index 0000000..9d78ce7 --- /dev/null +++ b/DamageAssesmentApi/DamageAssesment.Api.Locations/Providers/RegionsProvider.cs @@ -0,0 +1,164 @@ +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 RegionsProvider : IRegionsProvider + { + private LocationDbContext locationDbContext; + private ILogger logger; + private IMapper mapper; + + public RegionsProvider(LocationDbContext regionDbContext, ILogger logger, IMapper mapper) + { + this.locationDbContext = regionDbContext; + this.logger = logger; + this.mapper = mapper; + SeedData(); + } + + public async Task<(bool IsSuccess, Models.Region Region, string ErrorMessage)> GetRegionByIdAsync(string 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(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 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>(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 regions = await locationDbContext.Regions.AsNoTracking().ToListAsync(); + + region.Id = Convert.ToString(regions.Count + 1); + locationDbContext.Regions.Add(mapper.Map(region)); + locationDbContext.SaveChanges(); + 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(Models.Region region) + { + try + { + if (region != null) + { + var _region = await locationDbContext.Regions.AsNoTracking().Where(s => s.Id == region.Id).FirstOrDefaultAsync(); + + if (_region != null) + { + locationDbContext.Regions.Update(mapper.Map(region)); + locationDbContext.SaveChanges(); + return (true, region, "Region updated Successfuly"); + } + else + { + logger?.LogInformation($"RegionID: {region.Id} Not found"); + return (false, null, "Not Found"); + } + + } + else + { + logger?.LogInformation($"RegionID: {region.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(string 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(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 void SeedData() + { + if (!locationDbContext.Regions.Any()) + { + locationDbContext.Regions.Add(new Db.Region() { Id = "1", Name = "North", Abbreviation = "N" }); + locationDbContext.Regions.Add(new Db.Region() { Id = "2", Name = "South", Abbreviation = "S" }); + locationDbContext.Regions.Add(new Db.Region() { Id = "3", Name = "Central", Abbreviation = "C" }); + locationDbContext.SaveChanges(); + } + } + } +} diff --git a/DamageAssesmentApi/DamageAssesment.Api.Locations/appsettings.Development.json b/DamageAssesmentApi/DamageAssesment.Api.Locations/appsettings.Development.json new file mode 100644 index 0000000..0c208ae --- /dev/null +++ b/DamageAssesmentApi/DamageAssesment.Api.Locations/appsettings.Development.json @@ -0,0 +1,8 @@ +{ + "Logging": { + "LogLevel": { + "Default": "Information", + "Microsoft.AspNetCore": "Warning" + } + } +} diff --git a/DamageAssesmentApi/DamageAssesment.Api.Locations/appsettings.json b/DamageAssesmentApi/DamageAssesment.Api.Locations/appsettings.json new file mode 100644 index 0000000..10f68b8 --- /dev/null +++ b/DamageAssesmentApi/DamageAssesment.Api.Locations/appsettings.json @@ -0,0 +1,9 @@ +{ + "Logging": { + "LogLevel": { + "Default": "Information", + "Microsoft.AspNetCore": "Warning" + } + }, + "AllowedHosts": "*" +} diff --git a/DamageAssesmentApi/DamageAssesment.Api.Questions/Controllers/QuestionsController.cs b/DamageAssesmentApi/DamageAssesment.Api.Questions/Controllers/QuestionsController.cs new file mode 100644 index 0000000..0184d72 --- /dev/null +++ b/DamageAssesmentApi/DamageAssesment.Api.Questions/Controllers/QuestionsController.cs @@ -0,0 +1,171 @@ +using DamageAssesment.Api.Questions.Db; +using DamageAssesment.Api.Questions.Interfaces; +using DamageAssesment.Api.Questions.Models; +using DamageAssesment.Api.Questions.Providers; +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Mvc; + +namespace DamageAssesment.Api.Questions.Controllers +{ + [Route("api")] + [ApiController] + public class QuestionsController : ControllerBase + { + private readonly IQuestionsProvider questionsProvider; + + public QuestionsController(IQuestionsProvider questionsProvider) + { + + this.questionsProvider = questionsProvider; + + } + // get all questions + [HttpGet("Questions")] + public async Task GetQuestionsAsync() + { + var result = await this.questionsProvider.GetQuestionsAsync(); + if (result.IsSuccess) + { + return Ok(result.Questions); + } + return NoContent(); + } + //Get questions based on question id + [HttpGet("Questions/{id}")] + public async Task GetQuestionAsync(int id) + { + var result = await this.questionsProvider.GetQuestionAsync(id); + if (result.IsSuccess) + { + return Ok(result.Question); + } + return NotFound(); + } + //get all questions based on survey id + [HttpGet("GetSurveyQuestions/{surveyId}")] + public async Task GetSurveyQuestions(int surveyId,string? Language) + { + if (string.IsNullOrEmpty(Language)) Language = "en"; + var result = await this.questionsProvider.GetSurveyQuestionAsync(surveyId, Language); + if (result.IsSuccess) + { + return Ok(result.SurveyQuestions); + } + return NotFound(); + } + //update existing question + [HttpPut("Questions")] + public async Task 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); + } + //save new question + [HttpPost("Questions")] + public async Task 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); + } + // delete existing question + [HttpDelete("Questions/{id}")] + public async Task DeleteQuestion(int id) + { + var result = await this.questionsProvider.DeleteQuestionAsync(id); + if (result.IsSuccess) + { + return Ok(result.Question); + } + return NotFound(); + } + + + // get all questions + [HttpGet("QuestionCategories")] + public async Task GetQuestionCategoriesAsync() + { + var result = await this.questionsProvider.GetQuestionCategoriesAsync(); + if (result.IsSuccess) + { + return Ok(result.QuestionCategories); + } + return NoContent(); + } + //Get questions based on question id + [HttpGet("QuestionCategories/{id}")] + public async Task GetQuestionCategoryAsync(int id) + { + var result = await this.questionsProvider.GetQuestionCategoryAsync(id); + if (result.IsSuccess) + { + return Ok(result.QuestionCategory); + } + return NotFound(); + } + + + //update existing question + [HttpPut("QuestionCategories")] + public async Task 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); + } + //save new question + [HttpPost("QuestionCategories")] + public async Task 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); + } + // delete existing question + [HttpDelete("QuestionCategories/{id}")] + public async Task DeleteQuestionCategory(int id) + { + var result = await this.questionsProvider.DeleteQuestionCategoryAsync(id); + if (result.IsSuccess) + { + return Ok(result.QuestionCategory); + } + return NotFound(); + } + } +} diff --git a/DamageAssesmentApi/DamageAssesment.Api.Questions/DamageAssesment.Api.Questions.csproj b/DamageAssesmentApi/DamageAssesment.Api.Questions/DamageAssesment.Api.Questions.csproj new file mode 100644 index 0000000..53e8700 --- /dev/null +++ b/DamageAssesmentApi/DamageAssesment.Api.Questions/DamageAssesment.Api.Questions.csproj @@ -0,0 +1,16 @@ + + + + net6.0 + enable + enable + + + + + + + + + + diff --git a/DamageAssesmentApi/DamageAssesment.Api.Questions/Db/Question.cs b/DamageAssesmentApi/DamageAssesment.Api.Questions/Db/Question.cs new file mode 100644 index 0000000..846df86 --- /dev/null +++ b/DamageAssesmentApi/DamageAssesment.Api.Questions/Db/Question.cs @@ -0,0 +1,29 @@ +using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations.Schema; + +namespace DamageAssesment.Api.Questions.Db +{ + public class Question + { + [Key] + public int Id { get; set; } + + [ForeignKey("QuestionType")] + public int QuestionTypeId { get; set; } + public QuestionType? QuestionType { get; set; } + + //uncomment below propertiers + public int QuestionNumber { get; set; } + public bool IsRequired { get; set; } + public bool Comment { get; set; } //if Comment is true answer has user comment (survey response) + + public bool Key { get; set; } + [ForeignKey("Survey")] + public int? SurveyId { get; set; } + public string QuestionGroup { get; set; } + [ForeignKey("QuestionCategory")] + public int CategoryId { get; set; } + + + } +} diff --git a/DamageAssesmentApi/DamageAssesment.Api.Questions/Db/QuestionCategory.cs b/DamageAssesmentApi/DamageAssesment.Api.Questions/Db/QuestionCategory.cs new file mode 100644 index 0000000..06fc296 --- /dev/null +++ b/DamageAssesmentApi/DamageAssesment.Api.Questions/Db/QuestionCategory.cs @@ -0,0 +1,14 @@ +using System.Buffers.Text; +using System.ComponentModel.DataAnnotations; + +namespace DamageAssesment.Api.Questions.Db +{ + public class QuestionCategory + { + [Key] + public int Id { get; set; } + public string CategoryName { get; set; } + public string CategoryImage { get; set; } + + } +} diff --git a/DamageAssesmentApi/DamageAssesment.Api.Questions/Db/QuestionDbContext.cs b/DamageAssesmentApi/DamageAssesment.Api.Questions/Db/QuestionDbContext.cs new file mode 100644 index 0000000..a784abf --- /dev/null +++ b/DamageAssesmentApi/DamageAssesment.Api.Questions/Db/QuestionDbContext.cs @@ -0,0 +1,25 @@ +using Microsoft.AspNetCore.Identity; +using Microsoft.EntityFrameworkCore; +using System.ComponentModel.DataAnnotations; + +namespace DamageAssesment.Api.Questions.Db +{ + public class QuestionDbContext : DbContext + { + public DbSet Questions { get; set; } + public DbSet QuestionTypes { get; set; } + public DbSet QuestionsTranslations { get; set; } + public DbSet QuestionCategories { get; set; } + public QuestionDbContext(DbContextOptions options) : base(options) + { + + } + //protected override void OnModelCreating(ModelBuilder modelBuilder) + //{ + // modelBuilder.Entity() + // .HasOne(a => a.QuestionType) + // .WithOne(b => b.Question) + // .HasForeignKey(b => b.QuestionTypeID); + //} + } +} diff --git a/DamageAssesmentApi/DamageAssesment.Api.Questions/Db/QuestionType.cs b/DamageAssesmentApi/DamageAssesment.Api.Questions/Db/QuestionType.cs new file mode 100644 index 0000000..3d7e2b6 --- /dev/null +++ b/DamageAssesmentApi/DamageAssesment.Api.Questions/Db/QuestionType.cs @@ -0,0 +1,11 @@ +using System.ComponentModel.DataAnnotations; + +namespace DamageAssesment.Api.Questions.Db +{ + public class QuestionType + { + [Key] + public int Id { get; set; } + public string TypeText { get; set; } + } +} diff --git a/DamageAssesmentApi/DamageAssesment.Api.Questions/Db/QuestionsTranslation.cs b/DamageAssesmentApi/DamageAssesment.Api.Questions/Db/QuestionsTranslation.cs new file mode 100644 index 0000000..bfe75e8 --- /dev/null +++ b/DamageAssesmentApi/DamageAssesment.Api.Questions/Db/QuestionsTranslation.cs @@ -0,0 +1,15 @@ +using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations.Schema; + +namespace DamageAssesment.Api.Questions.Db +{ + public class QuestionsTranslation + { + [Key] + public int Id { get; set; } + [ForeignKey("Question")] + public int QuestionId { get; set; } + public string QuestionText { get; set; } + public string Language { get; set; } + } +} diff --git a/DamageAssesmentApi/DamageAssesment.Api.Questions/Interfaces/IQuestionTypeProvider.cs b/DamageAssesmentApi/DamageAssesment.Api.Questions/Interfaces/IQuestionTypeProvider.cs new file mode 100644 index 0000000..74df172 --- /dev/null +++ b/DamageAssesmentApi/DamageAssesment.Api.Questions/Interfaces/IQuestionTypeProvider.cs @@ -0,0 +1,8 @@ +namespace DamageAssesment.Api.Questions.Interfaces +{ + public interface IQuestionTypesProvider + { + Task<(bool IsSuccess, Db.QuestionType QuestionType, string ErrorMessage)> GetQuestionTypeAsync(int Id); + Task<(bool IsSuccess, IEnumerable QuestionTypes, string ErrorMessage)> GetQuestionTypesAsync(); + } +} diff --git a/DamageAssesmentApi/DamageAssesment.Api.Questions/Interfaces/IQuestionsProvider.cs b/DamageAssesmentApi/DamageAssesment.Api.Questions/Interfaces/IQuestionsProvider.cs new file mode 100644 index 0000000..0f62339 --- /dev/null +++ b/DamageAssesmentApi/DamageAssesment.Api.Questions/Interfaces/IQuestionsProvider.cs @@ -0,0 +1,21 @@ +using DamageAssesment.Api.Questions.Models; + +namespace DamageAssesment.Api.Questions.Interfaces +{ + public interface IQuestionsProvider : IQuestionTypesProvider + { + Task<(bool IsSuccess, Models.Question Question, string ErrorMessage)> GetQuestionAsync(int Id); + Task<(bool IsSuccess, IEnumerable Questions, string ErrorMessage)> GetQuestionsAsync(); + Task<(bool IsSuccess, List SurveyQuestions, string ErrorMessage)> GetSurveyQuestionAsync(int surveyId,string Language); + Task<(bool IsSuccess, Models.Question Question, string ErrorMessage)> PostQuestionAsync(Models.Question Question); + Task<(bool IsSuccess, Models.Question Question, string ErrorMessage)> UpdateQuestionAsync(Models.Question Question); + Task<(bool IsSuccess, Models.Question Question, string ErrorMessage)> DeleteQuestionAsync(int Id); + + + Task<(bool IsSuccess, IEnumerable QuestionCategories, string ErrorMessage)> GetQuestionCategoriesAsync(); + Task<(bool IsSuccess, Models.QuestionCategory QuestionCategory, string ErrorMessage)> GetQuestionCategoryAsync(int Id); + Task<(bool IsSuccess, Models.QuestionCategory QuestionCategory, string ErrorMessage)> PostQuestionCategoryAsync(Models.QuestionCategory QuestionCategory); + Task<(bool IsSuccess, Models.QuestionCategory QuestionCategory, string ErrorMessage)> UpdateQuestionCategoryAsync(Models.QuestionCategory QuestionCategory); + Task<(bool IsSuccess, Models.QuestionCategory QuestionCategory, string ErrorMessage)> DeleteQuestionCategoryAsync(int Id); + } +} diff --git a/DamageAssesmentApi/DamageAssesment.Api.Questions/Models/Question.cs b/DamageAssesmentApi/DamageAssesment.Api.Questions/Models/Question.cs new file mode 100644 index 0000000..e181f1f --- /dev/null +++ b/DamageAssesmentApi/DamageAssesment.Api.Questions/Models/Question.cs @@ -0,0 +1,24 @@ +using System.ComponentModel.DataAnnotations; + +namespace DamageAssesment.Api.Questions.Models +{ + public class Question + { + public int Id { get; set; } + public List Questions { get; set; } + + //public int QuestionTypeID { get; set; } + + public string TypeText { get; set; } = string.Empty; + + public int QuestionNumber { get; set; } + public bool IsRequired { get; set; } + public bool Comment { get; set; } + + public bool Key { get; set; } + public int? SurveyId { get; set; } + public string QuestionGroup { get; set; } + public int CategoryId { get; set; } + // public int? Survey_SurveyID { get; set; } + } +} diff --git a/DamageAssesmentApi/DamageAssesment.Api.Questions/Models/QuestionCategory.cs b/DamageAssesmentApi/DamageAssesment.Api.Questions/Models/QuestionCategory.cs new file mode 100644 index 0000000..78a6b52 --- /dev/null +++ b/DamageAssesmentApi/DamageAssesment.Api.Questions/Models/QuestionCategory.cs @@ -0,0 +1,9 @@ +namespace DamageAssesment.Api.Questions.Models +{ + public class QuestionCategory + { + public int Id { get; set; } + public string CategoryName { get; set; } + public string CategoryImage { get; set; } + } +} diff --git a/DamageAssesmentApi/DamageAssesment.Api.Questions/Models/QuestionsTranslation.cs b/DamageAssesmentApi/DamageAssesment.Api.Questions/Models/QuestionsTranslation.cs new file mode 100644 index 0000000..6df8219 --- /dev/null +++ b/DamageAssesmentApi/DamageAssesment.Api.Questions/Models/QuestionsTranslation.cs @@ -0,0 +1,8 @@ +namespace DamageAssesment.Api.Questions.Models +{ + public class QuestionsTranslation + { + public string QuestionText { get; set; } + public string Language { get; set; } = "En"; + } +} diff --git a/DamageAssesmentApi/DamageAssesment.Api.Questions/Models/SurveyQuestion.cs b/DamageAssesmentApi/DamageAssesment.Api.Questions/Models/SurveyQuestion.cs new file mode 100644 index 0000000..9736510 --- /dev/null +++ b/DamageAssesmentApi/DamageAssesment.Api.Questions/Models/SurveyQuestion.cs @@ -0,0 +1,10 @@ +namespace DamageAssesment.Api.Questions.Models +{ + public class SurveyQuestions + { + public int CategoryId { get; set; } + public string CategoryName { get; set; } + public string CategoryImage { get; set; } + public List Questions { get; set; } + } +} diff --git a/DamageAssesmentApi/DamageAssesment.Api.Questions/Profiles/QuestionProfile.cs b/DamageAssesmentApi/DamageAssesment.Api.Questions/Profiles/QuestionProfile.cs new file mode 100644 index 0000000..015fe0c --- /dev/null +++ b/DamageAssesmentApi/DamageAssesment.Api.Questions/Profiles/QuestionProfile.cs @@ -0,0 +1,18 @@ +using AutoMapper; + +namespace DamageAssesment.Api.Questions.Profiles +{ + public class QuestionProfile : AutoMapper.Profile + { + public QuestionProfile() + { + CreateMap().ForMember(dest => dest.TypeText, + opt => opt.MapFrom(src => src.QuestionType.TypeText)); + CreateMap(); + CreateMap(); + CreateMap(); + CreateMap(); + CreateMap(); + } + } +} diff --git a/DamageAssesmentApi/DamageAssesment.Api.Questions/Program.cs b/DamageAssesmentApi/DamageAssesment.Api.Questions/Program.cs new file mode 100644 index 0000000..3774b0b --- /dev/null +++ b/DamageAssesmentApi/DamageAssesment.Api.Questions/Program.cs @@ -0,0 +1,38 @@ +using DamageAssesment.Api.Questions.Db; +using DamageAssesment.Api.Questions.Interfaces; +using DamageAssesment.Api.Questions.Providers; +using Microsoft.EntityFrameworkCore; +using Microsoft.Extensions.Options; + +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.AddScoped(); +builder.Services.AddAutoMapper(AppDomain.CurrentDomain.GetAssemblies()); + + +builder.Services.AddEndpointsApiExplorer(); +builder.Services.AddSwaggerGen(); +builder.Services.AddDbContext(option => +{ + option.UseInMemoryDatabase("Questions"); +}); +var app = builder.Build(); + +// Configure the HTTP request pipeline. +if (app.Environment.IsDevelopment()) +{ + app.UseSwagger(); + app.UseSwaggerUI(); +} + +app.UseAuthorization(); + +app.MapControllers(); + +app.Run(); diff --git a/DamageAssesmentApi/DamageAssesment.Api.Questions/Properties/launchSettings.json b/DamageAssesmentApi/DamageAssesment.Api.Questions/Properties/launchSettings.json new file mode 100644 index 0000000..e4e08ae --- /dev/null +++ b/DamageAssesmentApi/DamageAssesment.Api.Questions/Properties/launchSettings.json @@ -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" + } + } + } +} diff --git a/DamageAssesmentApi/DamageAssesment.Api.Questions/Providers/QuestionsProvider.cs b/DamageAssesmentApi/DamageAssesment.Api.Questions/Providers/QuestionsProvider.cs new file mode 100644 index 0000000..647f640 --- /dev/null +++ b/DamageAssesmentApi/DamageAssesment.Api.Questions/Providers/QuestionsProvider.cs @@ -0,0 +1,387 @@ +using AutoMapper; +using DamageAssesment.Api.Questions.Db; +using DamageAssesment.Api.Questions.Interfaces; +using DamageAssesment.Api.Questions.Models; +using Microsoft.AspNetCore.Mvc; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Metadata.Internal; + +namespace DamageAssesment.Api.Questions.Providers +{ + + + public class QuestionsProvider : IQuestionsProvider, IQuestionTypesProvider + { + private QuestionDbContext questionDbContext; + private ILogger logger; + private IMapper mapper; + + public QuestionsProvider(QuestionDbContext questionDbContext, ILogger logger, IMapper mapper) + { + this.questionDbContext = questionDbContext; + this.logger = logger; + this.mapper = mapper; + SeedData(); + } + + + + private void SeedData() + { + + if (!questionDbContext.QuestionsTranslations.Any()) + { + questionDbContext.QuestionsTranslations.Add(new Db.QuestionsTranslation() {Id=1, QuestionId = 1, QuestionText = "Can You Open ?",Language="en" }); + questionDbContext.QuestionsTranslations.Add(new Db.QuestionsTranslation() { Id = 2, QuestionId = 1, QuestionText = "Peux-tu ouvrir ?", Language = "fr" }); + questionDbContext.QuestionsTranslations.Add(new Db.QuestionsTranslation() { Id = 3, QuestionId = 2, QuestionText = "Are the grounds flodded ?", Language = "en" }); + questionDbContext.QuestionsTranslations.Add(new Db.QuestionsTranslation() { Id = 4, QuestionId = 2, QuestionText = "Les terrains sont-ils inondés ?", Language = "fr" }); + questionDbContext.QuestionsTranslations.Add(new Db.QuestionsTranslation() { Id = 5, QuestionId = 3, QuestionText = "Is the access blocked by flooding ?", Language = "en" }); + questionDbContext.QuestionsTranslations.Add(new Db.QuestionsTranslation() { Id = 6, QuestionId = 3, QuestionText = "L'accès est-il bloqué par les inondations ?", Language = "fr" }); + questionDbContext.QuestionsTranslations.Add(new Db.QuestionsTranslation() { Id = 7, QuestionId = 1, QuestionText = "Puedes abrir ?", Language = "sp" }); + questionDbContext.QuestionsTranslations.Add(new Db.QuestionsTranslation() { Id = 8, QuestionId = 2, QuestionText = "¿Están inundados los terrenos?", Language = "sp" }); + questionDbContext.QuestionsTranslations.Add(new Db.QuestionsTranslation() { Id = 9, QuestionId = 3, QuestionText = "¿El acceso está bloqueado por inundaciones?", Language = "sp" }); + questionDbContext.SaveChanges(); + } + if (!questionDbContext.Questions.Any()) + { + questionDbContext.Questions.Add(new Db.Question() { Id = 1, QuestionTypeId = 2, SurveyId = 1, QuestionNumber = 1, IsRequired = true, Comment = false, Key = true, QuestionGroup = "group1",CategoryId=1 }); + questionDbContext.Questions.Add(new Db.Question() { Id = 2, QuestionTypeId = 1, SurveyId = 1, QuestionNumber = 2, IsRequired = false, Comment = true, Key = false, QuestionGroup = "group1", CategoryId = 1 }); + questionDbContext.Questions.Add(new Db.Question() { Id = 3, QuestionTypeId = 1, SurveyId = 1, QuestionNumber = 3, IsRequired = true, Comment = false, Key = true, QuestionGroup = "group1", CategoryId = 2 }); + questionDbContext.SaveChanges(); + } + if (!questionDbContext.QuestionTypes.Any()) + { + questionDbContext.QuestionTypes.Add(new Db.QuestionType() { Id = 1, TypeText = "Text 1" }); + questionDbContext.QuestionTypes.Add(new Db.QuestionType() { Id = 2, TypeText = "Text 2" }); + questionDbContext.QuestionTypes.Add(new Db.QuestionType() { Id = 3, TypeText = "Text 3" }); + questionDbContext.QuestionTypes.Add(new Db.QuestionType() { Id = 4, TypeText = "Text 4" }); + questionDbContext.QuestionTypes.Add(new Db.QuestionType() { Id = 5, TypeText = "Text 5" }); + questionDbContext.SaveChanges(); + } + + if (!questionDbContext.QuestionCategories.Any()) + { + questionDbContext.QuestionCategories.Add(new Db.QuestionCategory() { Id = 1, CategoryName = "Category 1", CategoryImage="img1" }); + questionDbContext.QuestionCategories.Add(new Db.QuestionCategory() { Id = 2, CategoryName = "Category 2", CategoryImage = "img1" }); + questionDbContext.QuestionCategories.Add(new Db.QuestionCategory() { Id = 3, CategoryName = "Category 3", CategoryImage = "img1" }); + questionDbContext.QuestionCategories.Add(new Db.QuestionCategory() { Id = 4, CategoryName = "Category 4", CategoryImage = "img1" }); + questionDbContext.QuestionCategories.Add(new Db.QuestionCategory() { Id = 5, CategoryName = "Category 5", CategoryImage = "img1" }); + questionDbContext.SaveChanges(); + } + + } + + public async Task<(bool IsSuccess, IEnumerable Questions, string ErrorMessage)> GetQuestionsAsync() + { + try + { + logger?.LogInformation("Query Question"); + var questions = await questionDbContext.Questions.Include("QuestionType").AsNoTracking().ToListAsync(); + if (questions != null) + { + + //logger?.LogInformation($"{question} customer(s) found"); + var result = mapper.Map, IEnumerable>(questions); + foreach (var question in result) + { + question.Questions=mapper.Map,List>( + questionDbContext.QuestionsTranslations.Where(a=>a.QuestionId==question.Id).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, Models.Question Question, string ErrorMessage)> GetQuestionAsync(int Id) + { + try + { + logger?.LogInformation("Query Question"); + var question = await questionDbContext.Questions.Include("QuestionType").AsNoTracking().FirstOrDefaultAsync(q => q.Id == Id); + if (question != null) + { + logger?.LogInformation($"{question} customer(s) found"); + var result = mapper.Map(question); + result.Questions = mapper.Map, List>( + questionDbContext.QuestionsTranslations.Where(a => a.QuestionId == result.Id).ToList()); + return (true, result, null); + } + return (false, null, "Not found"); + } + catch (Exception ex) + { + logger?.LogError(ex.ToString()); + return (false, null, ex.Message); + } + } + public List GetSurveyQuestion(List questions,string Language) + { + foreach (var item in questions) + { + item.Questions= mapper.Map, List>( + questionDbContext.QuestionsTranslations.Where(a => a.QuestionId == item.Id && a.Language== Language).ToList()); + } + return questions; + } + public async Task<(bool IsSuccess, List SurveyQuestions, string ErrorMessage)> GetSurveyQuestionAsync(int SurveyId, string Language) + { + try + { + logger?.LogInformation("Query Question"); + var questions = await questionDbContext.Questions.Include("QuestionType").Where(a=>a.SurveyId==SurveyId).AsNoTracking().ToListAsync(); + if (questions != null) + { + List surveyQuestionsList = new List(); + List CategoryIds=questions.Select(a=>a.CategoryId).Distinct().ToList(); + var questioncategories = await questionDbContext.QuestionCategories.Where(a =>CategoryIds.Contains(a.Id)).ToListAsync(); + //logger?.LogInformation($"{question} customer(s) found"); + foreach (var item in questioncategories) + { + surveyQuestionsList.Add(new SurveyQuestions() + { + CategoryId = item.Id, + CategoryImage = item.CategoryImage, + CategoryName = item.CategoryName, + Questions = GetSurveyQuestion(mapper.Map, List>(questions.Where(a => a.CategoryId == item.Id).ToList()), Language) + }); + } + + //var result = mapper.Map, IEnumerable>(questions); + return (true, surveyQuestionsList, null); + } + return (false, null, "Not found"); + } + catch (Exception ex) + { + logger?.LogError(ex.ToString()); + return (false, null, ex.Message); + } + } + public async Task<(bool IsSuccess, Models.Question Question, string ErrorMessage)> PostQuestionAsync(Models.Question Question) + { + try + { + logger?.LogInformation("Query Question"); + var dbquestion = mapper.Map(Question); + var dbquestiontranslation = mapper.Map, List>(Question.Questions); + dbquestion.QuestionTypeId=questionDbContext.QuestionTypes.Where(a=>a.TypeText==Question.TypeText).Select(a=>a.Id).FirstOrDefault(); + questionDbContext.Questions.Add(dbquestion); + dbquestiontranslation.ForEach(i => i.QuestionId = dbquestion.Id); + questionDbContext.QuestionsTranslations.AddRange(dbquestiontranslation); + questionDbContext.SaveChanges(); + Question.Id = dbquestion.Id; + return (true, Question, null); + } + catch (Exception ex) + { + logger?.LogError(ex.ToString()); + return (false, null, ex.Message); + } + } + public async Task<(bool IsSuccess, Models.Question Question, string ErrorMessage)> UpdateQuestionAsync(Models.Question Question) + { + try + { + var dbquestion = mapper.Map(Question); + var dbquestiontranslation = mapper.Map, List>(Question.Questions); + dbquestion.QuestionTypeId = questionDbContext.QuestionTypes.Where(a => a.TypeText == Question.TypeText).Select(a => a.Id).FirstOrDefault(); + questionDbContext.Entry(dbquestion).State = EntityState.Modified; + var oldquestions = questionDbContext.QuestionsTranslations.Where(a => a.QuestionId == dbquestion.Id).ToList(); + if(oldquestions!=null) + questionDbContext.QuestionsTranslations.RemoveRange(oldquestions); + dbquestiontranslation.ForEach(i => i.QuestionId = dbquestion.Id); + questionDbContext.QuestionsTranslations.AddRange(dbquestiontranslation); + questionDbContext.SaveChanges(); + return (true, Question, null); + } + catch (Exception ex) + { + + logger?.LogError(ex.ToString()); + return (false, null, ex.Message); + } + } + public async Task<(bool IsSuccess, Models.Question Question, string ErrorMessage)> DeleteQuestionAsync(int Id) + { + try + { + var question = await questionDbContext.Questions.Where(x => x.Id == Id).FirstOrDefaultAsync(); + + if (question != null) + { + questionDbContext.Questions.Remove(question); + questionDbContext.SaveChanges(); + return (true, mapper.Map(question), $"QuestionID {Id} deleted Successfuly"); + } + else + { + logger?.LogInformation($"QuestionID: {Id} Not found"); + return (false, null, "Not Found"); + } + } + catch (Exception ex) + { + logger?.LogError(ex.ToString()); + return (false, null, ex.Message); + } + } + + + + //Question Category Logic + + public async Task<(bool IsSuccess, IEnumerable QuestionCategories, string ErrorMessage)> GetQuestionCategoriesAsync() + { + try + { + logger?.LogInformation("Query Question"); + var questionCategories = await questionDbContext.QuestionCategories.AsNoTracking().ToListAsync(); + if (questionCategories != null) + { + //logger?.LogInformation($"{question} customer(s) found"); + var result = mapper.Map, IEnumerable>(questionCategories); + 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.QuestionCategory QuestionCategory, string ErrorMessage)> GetQuestionCategoryAsync(int Id) + { + try + { + logger?.LogInformation("Query Question"); + var questioncategory = await questionDbContext.QuestionCategories.AsNoTracking().FirstOrDefaultAsync(q => q.Id == Id); + if (questioncategory != null) + { + logger?.LogInformation($"{questioncategory} customer(s) found"); + var result = mapper.Map(questioncategory); + 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.QuestionCategory QuestionCategory, string ErrorMessage)> PostQuestionCategoryAsync(Models.QuestionCategory QuestionCategory) + { + try + { + logger?.LogInformation("Query Question"); + var dbQuestionCategory = mapper.Map(QuestionCategory); + // Question.QuestionType = GetQuestionType(Question.QuestionTypeId); + questionDbContext.QuestionCategories.Add(dbQuestionCategory); + questionDbContext.SaveChanges(); + QuestionCategory.Id=dbQuestionCategory.Id; + return (true, QuestionCategory, null); + } + catch (Exception ex) + { + logger?.LogError(ex.ToString()); + return (false, null, ex.Message); + } + } + public async Task<(bool IsSuccess, Models.QuestionCategory QuestionCategory, string ErrorMessage)> UpdateQuestionCategoryAsync(Models.QuestionCategory QuestionCategory) + { + try + { + var dbQuestionCategory = mapper.Map(QuestionCategory); + questionDbContext.Entry(dbQuestionCategory).State = EntityState.Modified; + + questionDbContext.SaveChanges(); + return (true, QuestionCategory, null); + } + catch (Exception ex) + { + + logger?.LogError(ex.ToString()); + return (false, null, ex.Message); + } + } + public async Task<(bool IsSuccess, Models.QuestionCategory QuestionCategory, string ErrorMessage)> DeleteQuestionCategoryAsync(int Id) + { + try + { + var questioncategory = await questionDbContext.QuestionCategories.Where(x => x.Id == Id).FirstOrDefaultAsync(); + if (questioncategory != null) + { + var question = await questionDbContext.Questions.Where(x => x.Id == Id).ToListAsync(); + questionDbContext.Questions.RemoveRange(question); + questionDbContext.QuestionCategories.Remove(questioncategory); + questionDbContext.SaveChanges(); + return (true, mapper.Map(questioncategory), $"QuestionID {Id} deleted Successfuly"); + } + else + { + logger?.LogInformation($"QuestionID: {Id} Not found"); + return (false, null, "Not Found"); + } + } + catch (Exception ex) + { + logger?.LogError(ex.ToString()); + return (false, null, ex.Message); + } + } + private bool QuestionExists(int id) + { + return questionDbContext.Questions.AsNoTracking().Count(e => e.Id == id) > 0; + } + private QuestionType GetQuestionType(int Id) + { + return questionDbContext.QuestionTypes.Where(a => a.Id == Id).FirstOrDefault(); + } + + public async Task<(bool IsSuccess, QuestionType QuestionType, string ErrorMessage)> GetQuestionTypeAsync(int Id) + { + try + { + logger?.LogInformation("Query Question"); + var questiontype = await questionDbContext.QuestionTypes.FirstOrDefaultAsync(q => q.Id == Id); + if (questiontype != null) + { + logger?.LogInformation($"{questiontype} customer(s) found"); + return (true, questiontype, null); + } + return (false, null, "Not found"); + } + catch (Exception ex) + { + logger?.LogError(ex.ToString()); + return (false, null, ex.Message); + } + } + + public async Task<(bool IsSuccess, IEnumerable QuestionTypes, string ErrorMessage)> GetQuestionTypesAsync() + { + try + { + logger?.LogInformation("Query Question"); + var questionTypes = await questionDbContext.QuestionTypes.ToListAsync(); + if (questionTypes != null) + { + //logger?.LogInformation($"{question} customer(s) found"); + return (true, questionTypes, null); + } + return (false, null, "Not found"); + } + catch (Exception ex) + { + logger?.LogError(ex.ToString()); + return (false, null, ex.Message); + } + } + } +} diff --git a/DamageAssesmentApi/DamageAssesment.Api.Questions/appsettings.Development.json b/DamageAssesmentApi/DamageAssesment.Api.Questions/appsettings.Development.json new file mode 100644 index 0000000..0c208ae --- /dev/null +++ b/DamageAssesmentApi/DamageAssesment.Api.Questions/appsettings.Development.json @@ -0,0 +1,8 @@ +{ + "Logging": { + "LogLevel": { + "Default": "Information", + "Microsoft.AspNetCore": "Warning" + } + } +} diff --git a/DamageAssesmentApi/DamageAssesment.Api.Questions/appsettings.json b/DamageAssesmentApi/DamageAssesment.Api.Questions/appsettings.json new file mode 100644 index 0000000..10f68b8 --- /dev/null +++ b/DamageAssesmentApi/DamageAssesment.Api.Questions/appsettings.json @@ -0,0 +1,9 @@ +{ + "Logging": { + "LogLevel": { + "Default": "Information", + "Microsoft.AspNetCore": "Warning" + } + }, + "AllowedHosts": "*" +} diff --git a/DamageAssesmentApi/DamageAssesment.Api.QuestionsTest/CategoryMockData.cs b/DamageAssesmentApi/DamageAssesment.Api.QuestionsTest/CategoryMockData.cs new file mode 100644 index 0000000..cf0bb04 --- /dev/null +++ b/DamageAssesmentApi/DamageAssesment.Api.QuestionsTest/CategoryMockData.cs @@ -0,0 +1,50 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace DamageAssesment.Api.Questions.Test +{ + public class CategoryMockData + { + public static async Task<(bool, IEnumerable, string)> getOkResponse() + { + IEnumerable list = new List(); + + for (int i = 0; i < 10; i++) + { + list.Append(new Questions.Models.QuestionCategory { Id = i, CategoryImage = "img"+i,CategoryName="Category "+i }); + } + return (true, list, null); + } + + public static async Task<(bool, Questions.Models.QuestionCategory, string)> getOkResponse(int Id) + { + var Questions = await getOkResponse(); + var Question = Questions.Item2.FirstOrDefault(s => s.Id == Id); + return (true, Question, null); + } + + public static async Task<(bool, Questions.Models.QuestionCategory, string)> getBadRequestResponse() + { + return (false, null, "Bad Request"); + } + + public static async Task<(bool, Questions.Models.QuestionCategory, string)> getNotFoundResponse() + { + return (false, null, "Not Found"); + } + public static async Task<(bool, IEnumerable, string)> getNoContentResponse() + { + IEnumerable list = new List(); + return (false, list, null); + } + + public static async Task getInputQuestionCategoryData() + { + return new Questions.Models.QuestionCategory { Id = 1, CategoryName = "Category 1",CategoryImage="img 1" }; + + } + } +} diff --git a/DamageAssesmentApi/DamageAssesment.Api.QuestionsTest/DamageAssesment.Api.Questions.Test.csproj b/DamageAssesmentApi/DamageAssesment.Api.QuestionsTest/DamageAssesment.Api.Questions.Test.csproj new file mode 100644 index 0000000..fea3dd0 --- /dev/null +++ b/DamageAssesmentApi/DamageAssesment.Api.QuestionsTest/DamageAssesment.Api.Questions.Test.csproj @@ -0,0 +1,31 @@ + + + + net6.0 + enable + enable + + false + true + + + + + + + + + runtime; build; native; contentfiles; analyzers; buildtransitive + all + + + runtime; build; native; contentfiles; analyzers; buildtransitive + all + + + + + + + + diff --git a/DamageAssesmentApi/DamageAssesment.Api.QuestionsTest/MockData.cs b/DamageAssesmentApi/DamageAssesment.Api.QuestionsTest/MockData.cs new file mode 100644 index 0000000..f9c0c87 --- /dev/null +++ b/DamageAssesmentApi/DamageAssesment.Api.QuestionsTest/MockData.cs @@ -0,0 +1,89 @@ +using DamageAssesment.Api.Questions.Db; +using Microsoft.EntityFrameworkCore.Metadata.Internal; +using Newtonsoft.Json; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace DamageAssesment.Api.Questions.Test +{ + public class MockData + { + + public static async Task<(bool, IEnumerable, string)> getOkResponse() + { + IEnumerable list = new List(); + + for (int i = 0; i < 10; i++) + { + list.Append(new Questions.Models.Question { Id = i, TypeText = "Text" + i, SurveyId = 1, QuestionNumber = 1, IsRequired = true, Comment = false, Key = true, QuestionGroup = "group1",CategoryId=i }); + } + return (true, list, null); + } + + + public static async Task<(bool, List, string)> getOkSurveyResponse() + { + List list = new List(); + + for (int i = 0; i < 10; i++) + { + List question = new List(); + question.Add(new Models.Question { Id = i, TypeText = "Text" + i, SurveyId = 1, QuestionNumber = 1, IsRequired = true, Comment = false, Key = true, QuestionGroup = "group1", CategoryId = i }); + list.Append(new Questions.Models.SurveyQuestions + { + CategoryId = i, + CategoryImage = "img" + i, + CategoryName = "Category " + i, + Questions = question + }); + } + return (true, list, null); + } + + public static async Task<(bool, Questions.Models.Question, string)> getOkResponse(int Id) + { + var Questions = await getOkResponse(); + var Question = Questions.Item2.FirstOrDefault(s => s.Id == Id); + return (true, Question, null); + } + + public static async Task<(bool, Questions.Models.Question, string)> getBadRequestResponse() + { + return (false, null, "Bad Request"); + } + + public static async Task<(bool, Questions.Models.Question, string)> getNotFoundResponse() + { + return (false, null, "Not Found"); + } + public static async Task<(bool, IEnumerable, string)> getNoContentResponse() + { + IEnumerable list = new List(); + return (false, list, null); + } + public static async Task<(bool, List, string)> getNoSurveyContentResponse() + { + List list = new List(); + return (false, list, null); + } + + public static async Task getInputQuestionData() + { + Models.QuestionsTranslation QuestionsTranslation = new Models.QuestionsTranslation() + { + Language = "en", + QuestionText = "Sample question" + }; + List QuestionsTranslations = new List(); + QuestionsTranslations.Add(QuestionsTranslation); + return new Questions.Models.Question { Id = 1, Questions=QuestionsTranslations, TypeText = "Text 1", SurveyId = 1, QuestionNumber = 1, IsRequired = true, Comment = false, Key = true, QuestionGroup = "group1" ,CategoryId=1}; + + } + + + + } +} diff --git a/DamageAssesmentApi/DamageAssesment.Api.QuestionsTest/QuestionsServiceTest.cs b/DamageAssesmentApi/DamageAssesment.Api.QuestionsTest/QuestionsServiceTest.cs new file mode 100644 index 0000000..b21fa9c --- /dev/null +++ b/DamageAssesmentApi/DamageAssesment.Api.QuestionsTest/QuestionsServiceTest.cs @@ -0,0 +1,343 @@ + +using AutoMapper; +using DamageAssesment.Api.Questions.Controllers; +using DamageAssesment.Api.Questions.Db; +using DamageAssesment.Api.Questions.Interfaces; +using DamageAssesment.Api.Questions.Models; +using DamageAssesment.Api.Questions.Profiles; +using DamageAssesment.Api.Questions.Providers; +using Microsoft.AspNetCore.Mvc; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Metadata.Internal; +using Moq; +using Newtonsoft.Json; +using Xunit; + +namespace DamageAssesment.Api.Questions.Test +{ + public class QuestionServiceTest + { + [Fact(DisplayName = "Get Questions - Ok case")] + public async Task GetQuestionsAsync_ShouldReturnStatusCode200() + { + var mockQuestionService = new Mock(); + var mockResponse = await MockData.getOkResponse(); + mockQuestionService.Setup(service => service.GetQuestionsAsync()).ReturnsAsync(mockResponse); + + var QuestionProvider = new QuestionsController(mockQuestionService.Object); + var result = (OkObjectResult)await QuestionProvider.GetQuestionsAsync(); + + Assert.Equal(200, result.StatusCode); + } + + [Fact(DisplayName = "Get Questions - NoContent Case")] + public async Task GetQuestionsAsync_ShouldReturnStatusCode204() + { + var mockQuestionService = new Mock(); + var mockResponse = await MockData.getNoContentResponse(); + mockQuestionService.Setup(service => service.GetQuestionsAsync()).ReturnsAsync(mockResponse); + + var QuestionProvider = new QuestionsController(mockQuestionService.Object); + var result = (NoContentResult)await QuestionProvider.GetQuestionsAsync(); + + Assert.Equal(204, result.StatusCode); + } + + [Fact(DisplayName = "Get Question by Id - Ok case")] + public async Task GetQuestionAsync_ShouldReturnStatusCode200() + { + var mockQuestionService = new Mock(); + var mockResponse = await MockData.getOkResponse(1); + mockQuestionService.Setup(service => service.GetQuestionAsync(1)).ReturnsAsync(mockResponse); + + var QuestionProvider = new QuestionsController(mockQuestionService.Object); + var result = (OkObjectResult)await QuestionProvider.GetQuestionAsync(1); + + Assert.Equal(200, result.StatusCode); + } + + [Fact(DisplayName = "Get Question by Id - NotFound case")] + public async Task GetQuestionAsync_ShouldReturnStatusCode404() + { + var mockQuestionService = new Mock(); + var mockResponse = await MockData.getNotFoundResponse(); + mockQuestionService.Setup(service => service.GetQuestionAsync(99)).ReturnsAsync(mockResponse); + + var QuestionProvider = new QuestionsController(mockQuestionService.Object); + var result = (NotFoundResult)await QuestionProvider.GetQuestionAsync(99); + Assert.Equal(404, result.StatusCode); + } + + [Fact(DisplayName = "Get Question by SurveyID - Ok case")] + public async Task GetQuestionBySurveyAsync_ShouldReturnStatusCode200() + { + var mockQuestionService = new Mock(); + var mockResponse = await MockData.getOkSurveyResponse(); + mockQuestionService.Setup(service => service.GetSurveyQuestionAsync(1,"en")).ReturnsAsync(mockResponse); + + var QuestionProvider = new QuestionsController(mockQuestionService.Object); + var result = (OkObjectResult)await QuestionProvider.GetSurveyQuestions(1,"en"); + + Assert.Equal(200, result.StatusCode); + } + + [Fact(DisplayName = "Get Question by SurveyID - NotFound case")] + public async Task GetQuestionBySurveyAsync_ShouldReturnStatusCode404() + { + var mockQuestionService = new Mock(); + var mockResponse = await MockData.getNoSurveyContentResponse(); + mockQuestionService.Setup(service => service.GetSurveyQuestionAsync(99,"en")).ReturnsAsync(mockResponse); + + var QuestionProvider = new QuestionsController(mockQuestionService.Object); + var result = (NotFoundResult)await QuestionProvider.GetSurveyQuestions(99,"en"); + Assert.Equal(404, result.StatusCode); + } + [Fact(DisplayName = "Post Question - Ok case")] + public async Task PostQuestionAsync_ShouldReturnStatusCode200() + { + var mockQuestionService = new Mock(); + var mockResponse = await MockData.getOkResponse(1); + var mockInputQuestion = await MockData.getInputQuestionData(); + mockQuestionService.Setup(service => service.PostQuestionAsync(mockInputQuestion)).ReturnsAsync(mockResponse); + + var QuestionProvider = new QuestionsController(mockQuestionService.Object); + var result = (OkObjectResult)await QuestionProvider.CreateQuestion(mockInputQuestion); + + Assert.Equal(200, result.StatusCode); + } + + [Fact(DisplayName = "Post Question - BadRequest case")] + public async Task PostQuestionAsync_ShouldReturnStatusCode400() + { + var mockQuestionService = new Mock(); + var mockInputQuestion = await MockData.getInputQuestionData(); + var mockResponse = await MockData.getBadRequestResponse(); + mockQuestionService.Setup(service => service.UpdateQuestionAsync(mockInputQuestion)).ReturnsAsync(mockResponse); + + var QuestionProvider = new QuestionsController(mockQuestionService.Object); + var result = (BadRequestObjectResult)await QuestionProvider.UpdateQuestion(mockInputQuestion); + + Assert.Equal(400, result.StatusCode); + } + + [Fact(DisplayName = "Put Question - Ok case")] + public async Task PutQuestionAsync_ShouldReturnStatusCode200() + { + var mockQuestionService = new Mock(); + var mockResponse = await MockData.getOkResponse(1); + var mockInputQuestion = await MockData.getInputQuestionData(); + mockQuestionService.Setup(service => service.UpdateQuestionAsync(mockInputQuestion)).ReturnsAsync(mockResponse); + + var QuestionProvider = new QuestionsController(mockQuestionService.Object); + var result = (OkObjectResult)await QuestionProvider.UpdateQuestion(mockInputQuestion); + + Assert.Equal(200, result.StatusCode); + } + + [Fact(DisplayName = "Put Question - NotFound case")] + public async Task PutQuestionAsync_ShouldReturnStatusCode404() + { + var mockQuestionService = new Mock(); + var mockResponse = await MockData.getNotFoundResponse(); + var mockInputQuestion = await MockData.getInputQuestionData(); + mockQuestionService.Setup(service => service.UpdateQuestionAsync(mockInputQuestion)).ReturnsAsync(mockResponse); + + var QuestionProvider = new QuestionsController(mockQuestionService.Object); + var result = (NotFoundObjectResult)await QuestionProvider.UpdateQuestion(mockInputQuestion); + + Assert.Equal(404, result.StatusCode); + } + + [Fact(DisplayName = "Put Question - BadRequest case")] + public async Task PutQuestionAsync_ShouldReturnStatusCode400() + { + var mockQuestionService = new Mock(); + var mockResponse = await MockData.getBadRequestResponse(); + var mockInputQuestion = await MockData.getInputQuestionData(); + mockQuestionService.Setup(service => service.UpdateQuestionAsync(mockInputQuestion)).ReturnsAsync(mockResponse); + + var QuestionProvider = new QuestionsController(mockQuestionService.Object); + var result = (BadRequestObjectResult)await QuestionProvider.UpdateQuestion(mockInputQuestion); + + Assert.Equal(400, result.StatusCode); + } + + [Fact(DisplayName = "Delete Question - Ok case")] + public async Task DeleteQuestionAsync_ShouldReturnStatusCode200() + { + var mockQuestionService = new Mock(); + var mockResponse = await MockData.getOkResponse(1); + + mockQuestionService.Setup(service => service.DeleteQuestionAsync(1)).ReturnsAsync(mockResponse); + + var QuestionProvider = new QuestionsController(mockQuestionService.Object); + var result = (OkObjectResult)await QuestionProvider.DeleteQuestion(1); + + Assert.Equal(200, result.StatusCode); + } + [Fact(DisplayName = "Delete Question - NotFound case")] + public async Task DeleteQuestionAsync_ShouldReturnStatusCode404() + { + var mockQuestionService = new Mock(); + var mockResponse = await MockData.getNotFoundResponse(); + mockQuestionService.Setup(service => service.DeleteQuestionAsync(1)).ReturnsAsync(mockResponse); + + var QuestionProvider = new QuestionsController(mockQuestionService.Object); + var result = (NotFoundResult)await QuestionProvider.DeleteQuestion(1); + + Assert.Equal(404, result.StatusCode); + } + + + // Question Category Test cases + + + [Fact(DisplayName = "Get Question Categories - Ok case")] + public async Task GetQuestionCategoriesAsync_ShouldReturnStatusCode200() + { + var mockQuestionService = new Mock(); + var mockResponse = await CategoryMockData.getOkResponse(); + mockQuestionService.Setup(service => service.GetQuestionCategoriesAsync()).ReturnsAsync(mockResponse); + + var QuestionProvider = new QuestionsController(mockQuestionService.Object); + var result = (OkObjectResult)await QuestionProvider.GetQuestionCategoriesAsync(); + + Assert.Equal(200, result.StatusCode); + } + + [Fact(DisplayName = "Get Question Categories - NoContent Case")] + public async Task GetQuestionCategoriesAsync_ShouldReturnStatusCode204() + { + var mockQuestionService = new Mock(); + var mockResponse = await CategoryMockData.getNoContentResponse(); + mockQuestionService.Setup(service => service.GetQuestionCategoriesAsync()).ReturnsAsync(mockResponse); + + var QuestionProvider = new QuestionsController(mockQuestionService.Object); + var result = (NoContentResult)await QuestionProvider.GetQuestionCategoriesAsync(); + + Assert.Equal(204, result.StatusCode); + } + + [Fact(DisplayName = "Get Question category by Id - Ok case")] + public async Task GetQuestioncategoryAsync_ShouldReturnStatusCode200() + { + var mockQuestionService = new Mock(); + var mockResponse = await CategoryMockData.getOkResponse(1); + mockQuestionService.Setup(service => service.GetQuestionCategoryAsync(1)).ReturnsAsync(mockResponse); + + var QuestionProvider = new QuestionsController(mockQuestionService.Object); + var result = (OkObjectResult)await QuestionProvider.GetQuestionCategoryAsync(1); + + Assert.Equal(200, result.StatusCode); + } + + [Fact(DisplayName = "Get Question category by Id - NotFound case")] + public async Task GetQuestioncategoryAsync_ShouldReturnStatusCode404() + { + var mockQuestionService = new Mock(); + var mockResponse = await CategoryMockData.getNotFoundResponse(); + mockQuestionService.Setup(service => service.GetQuestionCategoryAsync(99)).ReturnsAsync(mockResponse); + + var QuestionProvider = new QuestionsController(mockQuestionService.Object); + var result = (NotFoundResult)await QuestionProvider.GetQuestionCategoryAsync(99); + Assert.Equal(404, result.StatusCode); + } + + [Fact(DisplayName = "Post Question category - Ok case")] + public async Task PostQuestioncategoryAsync_ShouldReturnStatusCode200() + { + var mockQuestionService = new Mock(); + var mockResponse = await CategoryMockData.getOkResponse(1); + var mockInputQuestion = await CategoryMockData.getInputQuestionCategoryData(); + mockQuestionService.Setup(service => service.PostQuestionCategoryAsync(mockInputQuestion)).ReturnsAsync(mockResponse); + + var QuestionProvider = new QuestionsController(mockQuestionService.Object); + var result = (OkObjectResult)await QuestionProvider.CreateQuestionCategory(mockInputQuestion); + + Assert.Equal(200, result.StatusCode); + } + + [Fact(DisplayName = "Post Question category - BadRequest case")] + public async Task PostQuestioncategoryAsync_ShouldReturnStatusCode400() + { + var mockQuestionService = new Mock(); + var mockInputQuestion = await CategoryMockData.getInputQuestionCategoryData(); + var mockResponse = await CategoryMockData.getBadRequestResponse(); + mockQuestionService.Setup(service => service.PostQuestionCategoryAsync(mockInputQuestion)).ReturnsAsync(mockResponse); + + var QuestionProvider = new QuestionsController(mockQuestionService.Object); + var result = (BadRequestObjectResult)await QuestionProvider.CreateQuestionCategory(mockInputQuestion); + + Assert.Equal(400, result.StatusCode); + } + + [Fact(DisplayName = "Put Question - Ok case")] + public async Task PutQuestioncategoryAsync_ShouldReturnStatusCode200() + { + var mockQuestionService = new Mock(); + var mockResponse = await CategoryMockData.getOkResponse(1); + var mockInputQuestion = await CategoryMockData.getInputQuestionCategoryData(); + mockQuestionService.Setup(service => service.UpdateQuestionCategoryAsync(mockInputQuestion)).ReturnsAsync(mockResponse); + + var QuestionProvider = new QuestionsController(mockQuestionService.Object); + var result = (OkObjectResult)await QuestionProvider.UpdateQuestionCategory(mockInputQuestion); + + Assert.Equal(200, result.StatusCode); + } + + [Fact(DisplayName = "Put Question - NotFound case")] + public async Task PutQuestioncategoryAsync_ShouldReturnStatusCode404() + { + var mockQuestionService = new Mock(); + var mockResponse = await CategoryMockData.getNotFoundResponse(); + var mockInputQuestion = await CategoryMockData.getInputQuestionCategoryData(); + mockQuestionService.Setup(service => service.UpdateQuestionCategoryAsync(mockInputQuestion)).ReturnsAsync(mockResponse); + + var QuestionProvider = new QuestionsController(mockQuestionService.Object); + var result = (NotFoundObjectResult)await QuestionProvider.UpdateQuestionCategory(mockInputQuestion); + + Assert.Equal(404, result.StatusCode); + } + + [Fact(DisplayName = "Put Question - BadRequest case")] + public async Task PutQuestioncategoryAsync_ShouldReturnStatusCode400() + { + var mockQuestionService = new Mock(); + var mockResponse = await CategoryMockData.getBadRequestResponse(); + var mockInputQuestion = await CategoryMockData.getInputQuestionCategoryData(); + mockQuestionService.Setup(service => service.UpdateQuestionCategoryAsync(mockInputQuestion)).ReturnsAsync(mockResponse); + + var QuestionProvider = new QuestionsController(mockQuestionService.Object); + var result = (BadRequestObjectResult)await QuestionProvider.UpdateQuestionCategory(mockInputQuestion); + + Assert.Equal(400, result.StatusCode); + } + + [Fact(DisplayName = "Delete Question - Ok case")] + public async Task DeleteQuestioncategoryAsync_ShouldReturnStatusCode200() + { + var mockQuestionService = new Mock(); + var mockResponse = await CategoryMockData.getOkResponse(1); + + mockQuestionService.Setup(service => service.DeleteQuestionCategoryAsync(1)).ReturnsAsync(mockResponse); + + var QuestionProvider = new QuestionsController(mockQuestionService.Object); + var result = (OkObjectResult)await QuestionProvider.DeleteQuestionCategory(1); + + Assert.Equal(200, result.StatusCode); + } + [Fact(DisplayName = "Delete Question - NotFound case")] + public async Task DeleteQuestioncategoryAsync_ShouldReturnStatusCode404() + { + var mockQuestionService = new Mock(); + var mockResponse = await CategoryMockData.getNotFoundResponse(); + mockQuestionService.Setup(service => service.DeleteQuestionCategoryAsync(1)).ReturnsAsync(mockResponse); + + var QuestionProvider = new QuestionsController(mockQuestionService.Object); + var result = (NotFoundResult)await QuestionProvider.DeleteQuestionCategory(1); + + Assert.Equal(404, result.StatusCode); + } + + } +} \ No newline at end of file diff --git a/DamageAssesmentApi/DamageAssesment.Api.SurveyResponses/Bases/ServiceProviderBase.cs b/DamageAssesmentApi/DamageAssesment.Api.SurveyResponses/Bases/ServiceProviderBase.cs new file mode 100644 index 0000000..71a37b6 --- /dev/null +++ b/DamageAssesmentApi/DamageAssesment.Api.SurveyResponses/Bases/ServiceProviderBase.cs @@ -0,0 +1,21 @@ +namespace DamageAssesment.Api.SurveyResponses.Bases +{ + public class ServiceProviderBase + { + protected readonly IConfiguration configuration; + protected readonly HttpClient httpClient; + protected private readonly ILogger logger; + protected string ressource; + protected string urlBase; + + + public ServiceProviderBase(IConfiguration configuration, HttpClient httpClient, ILogger logger, string ressource, string urlBase) + { + this.configuration = configuration; + this.httpClient = httpClient; + this.logger = logger; + this.ressource = ressource; + this.urlBase = urlBase; + } + } +} diff --git a/DamageAssesmentApi/DamageAssesment.Api.SurveyResponses/Controllers/SurveyResponsesController.cs b/DamageAssesmentApi/DamageAssesment.Api.SurveyResponses/Controllers/SurveyResponsesController.cs new file mode 100644 index 0000000..42b29dc --- /dev/null +++ b/DamageAssesmentApi/DamageAssesment.Api.SurveyResponses/Controllers/SurveyResponsesController.cs @@ -0,0 +1,157 @@ +using DamageAssesment.Api.SurveyResponses.Interfaces; +using DamageAssesment.Api.SurveyResponses.Models; +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Mvc; +using Microsoft.Extensions.Configuration; + +namespace DamageAssesment.Api.SurveyResponses.Controllers +{ + [Route("api")] + [ApiController] + public class SurveyResponsesController : ControllerBase + { + private readonly ISurveysResponse surveyResponseProvider; + + public SurveyResponsesController(ISurveysResponse surveyResponseProvider) + { + this.surveyResponseProvider = surveyResponseProvider; + } + + [HttpGet("SurveyResponses")] + public async Task GetSurveyResponsesAsync() + { + var result = await this.surveyResponseProvider.GetSurveyResponsesAsync(); + if (result.IsSuccess) + { + return Ok(result.surveyResponses); + } + + if (result.ErrorMessage == "No Data Found") + return NoContent(); + + return BadRequest(result.ErrorMessage); + } + + [HttpGet("SurveyResponses/{surveyId}")] + public async Task GetSurveyResponsesAsync(int surveyId) + { + var result = await this.surveyResponseProvider.GetSurveyResponsesBySurveyAsync(surveyId); + if (result.IsSuccess) + { + return Ok(result.SurveyResponses); + } + return NoContent(); + } + + [HttpGet("Responses/{surveyId}/{locationId}")] + public async Task GetSurveyResponsesBySurveyAndLocationAsync(int surveyId, string locationId) + { + var result = await this.surveyResponseProvider.GetSurveyResponsesBySurveyAndLocationAsync(surveyId, locationId); + if (result.IsSuccess) + { + return Ok(result.SurveyResponses); + } + + return NoContent(); + } + + [HttpGet("ResponsesByAnswer/{surveyId}/{questionId}/{answer}")] + public async Task GetSurveyResponsesByAnswerAsyncAsync(int surveyId, int questionId, string answer) + { + var result = await surveyResponseProvider.GetResponsesByAnswerAsync(surveyId, questionId, answer); + if (result.IsSuccess) + { + return Ok(result.SurveyResponses); + } + + return NoContent(); + } + + [HttpGet("AnswersByRegion/{surveyId}")] + public async Task GetAnswersByRegionAsync(int surveyId) + { + var result = await this.surveyResponseProvider.GetAnswersByRegionAsync(surveyId); + if (result.IsSuccess) + { + return Ok(result.Answers); + } + return NoContent(); + } + + [HttpGet("AnswersByMaintenanceCenter/{surveyId}")] + public async Task GetAnswersByMaintenaceCentersync(int surveyId) + { + var result = await this.surveyResponseProvider.GetSurveyResponsesByMaintenanceCenterAsync(surveyId); + if (result.IsSuccess) + { + return Ok(result.SurveyResponses); + } + return NoContent(); + } + + [HttpGet("SurveyResponse/{responseId}")] + public async Task GetSurveyResponseByIdAsync(int responseId) + { + var result = await this.surveyResponseProvider.GetSurveyResponseByIdAsync(responseId); + if (result.IsSuccess) + { + return Ok(result.SurveyResponse); + } + return NoContent(); + } + + + [HttpPost("SurveyResponses")] + public async Task PostSurveysAsync(Models.SurveyResponse surveyResponse) + { + var result = await this.surveyResponseProvider.PostSurveyResponseAsync(surveyResponse); + if (result.IsSuccess) + { + return Ok(result.SurveyResponse); + } + return BadRequest(result.ErrorMessage); + } + + [HttpPut("SurveyResponses/{Id}")] + public async Task PutSurveyResponseAsync(int Id, Models.SurveyResponse surveyResponse) + { + var result = await this.surveyResponseProvider.PutSurveyResponseAsync(Id, surveyResponse); + if (result.IsSuccess) + { + return Ok(result.SurveyResponse); + } + if (result.ErrorMessage == "Not Found") + return NotFound(result.ErrorMessage); + + return BadRequest(result.ErrorMessage); + } + + [HttpDelete("SurveyResponses/{Id}")] + public async Task DeleteSurveyResponseAsync(int Id) + { + var result = await this.surveyResponseProvider.DeleteSurveyResponseAsync(Id); + if (result.IsSuccess) + { + return Ok(result.SurveyResponse); + } + return NotFound(); + } + + [HttpPost("SurveyResponses/Answers")] + public async Task PostSurveyAnswersAsync(AnswerRequest answers) + { + /* var result = await this.surveyResponseProvider.PostSurveyAnswersAsync(surveyAnswers); + if (result.IsSuccess) + { + return Ok(result.SurveyResponse); + } + return BadRequest(result.ErrorMessage);*/ + var result = await this.surveyResponseProvider.PostSurveyAnswersAsync(answers); + + if (result.IsSuccess) + return Ok(result.SurveyResponse); + else + return BadRequest(result.ErrorMessage); + } + } +} diff --git a/DamageAssesmentApi/DamageAssesment.Api.SurveyResponses/DamageAssesment.Api.SurveyResponses.csproj b/DamageAssesmentApi/DamageAssesment.Api.SurveyResponses/DamageAssesment.Api.SurveyResponses.csproj new file mode 100644 index 0000000..a2383fa --- /dev/null +++ b/DamageAssesmentApi/DamageAssesment.Api.SurveyResponses/DamageAssesment.Api.SurveyResponses.csproj @@ -0,0 +1,19 @@ + + + + net6.0 + enable + enable + + + + + + + + + + + + + diff --git a/DamageAssesmentApi/DamageAssesment.Api.SurveyResponses/Db/SurveyResponse.cs b/DamageAssesmentApi/DamageAssesment.Api.SurveyResponses/Db/SurveyResponse.cs new file mode 100644 index 0000000..c1e5db1 --- /dev/null +++ b/DamageAssesmentApi/DamageAssesment.Api.SurveyResponses/Db/SurveyResponse.cs @@ -0,0 +1,30 @@ +using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations.Schema; + +namespace DamageAssesment.Api.SurveyResponses.Db +{ + public class SurveyResponse + { + [Key] + public int Id { get; set; } + + [ForeignKey("Survey")] + public int SurveyId { get; set; } + + [StringLength(4)] + [ForeignKey("Location")] + public string LocationId { get; set; } + + [StringLength(6)] + [ForeignKey("Employee")] + public string EmployeeId { get; set; } + + //public DateTime? CreatedDate { get; set; } + + //[StringLength(50)] + // public string ClientDevice { get; set; } + + // [StringLength(250)] + //public string KeyAnswerResult { get; set; } + } +} diff --git a/DamageAssesmentApi/DamageAssesment.Api.SurveyResponses/Db/SurveyResponseDbContext.cs b/DamageAssesmentApi/DamageAssesment.Api.SurveyResponses/Db/SurveyResponseDbContext.cs new file mode 100644 index 0000000..bb8a2a2 --- /dev/null +++ b/DamageAssesmentApi/DamageAssesment.Api.SurveyResponses/Db/SurveyResponseDbContext.cs @@ -0,0 +1,14 @@ +using Microsoft.EntityFrameworkCore; + +namespace DamageAssesment.Api.SurveyResponses.Db +{ + public class SurveyResponseDbContext:DbContext + { + public DbSet SurveyResponses { get; set; } + + public SurveyResponseDbContext(DbContextOptions options) : base(options) + { + + } + } +} diff --git a/DamageAssesmentApi/DamageAssesment.Api.SurveyResponses/Interfaces/IAnswerServiceProvider.cs b/DamageAssesmentApi/DamageAssesment.Api.SurveyResponses/Interfaces/IAnswerServiceProvider.cs new file mode 100644 index 0000000..e947659 --- /dev/null +++ b/DamageAssesmentApi/DamageAssesment.Api.SurveyResponses/Interfaces/IAnswerServiceProvider.cs @@ -0,0 +1,12 @@ +using DamageAssesment.Api.SurveyResponses.Models; + +namespace DamageAssesment.Api.SurveyResponses.Interfaces +{ + public interface IAnswerServiceProvider + { + Task> getAnswersAsync(); + Task> GetAnswersByResponseIdAsync(int responseId); + + Task PostAnswersAsync(Models.Answer answer); + } +} diff --git a/DamageAssesmentApi/DamageAssesment.Api.SurveyResponses/Interfaces/IAttachmentServiceProvider.cs b/DamageAssesmentApi/DamageAssesment.Api.SurveyResponses/Interfaces/IAttachmentServiceProvider.cs new file mode 100644 index 0000000..a20c91c --- /dev/null +++ b/DamageAssesmentApi/DamageAssesment.Api.SurveyResponses/Interfaces/IAttachmentServiceProvider.cs @@ -0,0 +1,10 @@ +using DamageAssesment.Api.SurveyResponses.Models; + +namespace DamageAssesment.Api.SurveyResponses.Interfaces +{ + public interface IAttachmentServiceProvider + { + Task> getAttachmentsAsync(); + Task> PostAttachmentsAsync(Models.AttachmentInfo attachmentInfo); + } +} diff --git a/DamageAssesmentApi/DamageAssesment.Api.SurveyResponses/Interfaces/IEmployeeServiceProvider.cs b/DamageAssesmentApi/DamageAssesment.Api.SurveyResponses/Interfaces/IEmployeeServiceProvider.cs new file mode 100644 index 0000000..a402c30 --- /dev/null +++ b/DamageAssesmentApi/DamageAssesment.Api.SurveyResponses/Interfaces/IEmployeeServiceProvider.cs @@ -0,0 +1,10 @@ +using DamageAssesment.Api.SurveyResponses.Models; + +namespace DamageAssesment.Api.SurveyResponses.Interfaces +{ + public interface IEmployeeServiceProvider + { + Task> getEmployeesAsync(); + Task getEmployeeAsync(string employeeID); + } +} diff --git a/DamageAssesmentApi/DamageAssesment.Api.SurveyResponses/Interfaces/ILocationServiceProvider.cs b/DamageAssesmentApi/DamageAssesment.Api.SurveyResponses/Interfaces/ILocationServiceProvider.cs new file mode 100644 index 0000000..75db3f1 --- /dev/null +++ b/DamageAssesmentApi/DamageAssesment.Api.SurveyResponses/Interfaces/ILocationServiceProvider.cs @@ -0,0 +1,9 @@ +using DamageAssesment.Api.SurveyResponses.Models; + +namespace DamageAssesment.Api.SurveyResponses.Interfaces +{ + public interface ILocationServiceProvider + { + Task> getLocationsAsync(); + } +} diff --git a/DamageAssesmentApi/DamageAssesment.Api.SurveyResponses/Interfaces/IQuestionServiceProvider.cs b/DamageAssesmentApi/DamageAssesment.Api.SurveyResponses/Interfaces/IQuestionServiceProvider.cs new file mode 100644 index 0000000..ab5f5ba --- /dev/null +++ b/DamageAssesmentApi/DamageAssesment.Api.SurveyResponses/Interfaces/IQuestionServiceProvider.cs @@ -0,0 +1,11 @@ +using DamageAssesment.Api.SurveyResponses.Models; + +namespace DamageAssesment.Api.SurveyResponses.Interfaces +{ + public interface IQuestionServiceProvider + { + Task> getQuestionsAsync(); + Task> getSurveyQuestionsAsync(int surveyId); + Task getQuestionsAsync(int questionId); + } +} diff --git a/DamageAssesmentApi/DamageAssesment.Api.SurveyResponses/Interfaces/IRegionServiceProvider.cs b/DamageAssesmentApi/DamageAssesment.Api.SurveyResponses/Interfaces/IRegionServiceProvider.cs new file mode 100644 index 0000000..8aeb1f8 --- /dev/null +++ b/DamageAssesmentApi/DamageAssesment.Api.SurveyResponses/Interfaces/IRegionServiceProvider.cs @@ -0,0 +1,9 @@ +using DamageAssesment.Api.SurveyResponses.Models; + +namespace DamageAssesment.Api.SurveyResponses.Interfaces +{ + public interface IRegionServiceProvider + { + Task> getRegionsAsync(); + } +} diff --git a/DamageAssesmentApi/DamageAssesment.Api.SurveyResponses/Interfaces/ISurveyServiceProvider.cs b/DamageAssesmentApi/DamageAssesment.Api.SurveyResponses/Interfaces/ISurveyServiceProvider.cs new file mode 100644 index 0000000..97d6461 --- /dev/null +++ b/DamageAssesmentApi/DamageAssesment.Api.SurveyResponses/Interfaces/ISurveyServiceProvider.cs @@ -0,0 +1,10 @@ +using DamageAssesment.Api.SurveyResponses.Models; + +namespace DamageAssesment.Api.SurveyResponses.Interfaces +{ + public interface ISurveyServiceProvider + { + Task> getSurveysAsync(); + Task getSurveyAsync(int surveyId); + } +} diff --git a/DamageAssesmentApi/DamageAssesment.Api.SurveyResponses/Interfaces/ISurveysResponse.cs b/DamageAssesmentApi/DamageAssesment.Api.SurveyResponses/Interfaces/ISurveysResponse.cs new file mode 100644 index 0000000..79ca1ad --- /dev/null +++ b/DamageAssesmentApi/DamageAssesment.Api.SurveyResponses/Interfaces/ISurveysResponse.cs @@ -0,0 +1,23 @@ +using DamageAssesment.Api.SurveyResponses.Models; +using Microsoft.AspNetCore.Mvc; + +namespace DamageAssesment.Api.SurveyResponses.Interfaces +{ + public interface ISurveysResponse + { + Task<(bool IsSuccess, dynamic Answers, string ErrorMessage)> GetAnswersByRegionAsync(int surveyId); + Task<(bool IsSuccess, Models.SurveyResponse SurveyResponse, string ErrorMessage)> PostSurveyResponseAsync(Models.SurveyResponse surveyResponse); + // Task<(bool IsSuccess,dynamic surveyResponses, string ErrorMessage)> GetSurveyResponseAsync(int responseId); + Task<(bool IsSuccess, dynamic surveyResponses, string ErrorMessage)> GetSurveyResponsesAsync(); + Task<(bool IsSuccess, Models.SurveyResponse SurveyResponse, string ErrorMessage)> PutSurveyResponseAsync(int Id, Models.SurveyResponse surveyResponse); + Task<(bool IsSuccess, Models.SurveyResponse SurveyResponse, string ErrorMessage)> DeleteSurveyResponseAsync(int Id); + Task<(bool IsSuccess, dynamic SurveyResponse, string ErrorMessage)> GetSurveyResponseByIdAsync(int responseId); + Task<(bool IsSuccess, dynamic SurveyResponses, string ErrorMessage)> GetSurveyResponsesBySurveyAsync(int surveyId); + Task<(bool IsSuccess, dynamic SurveyResponses, string ErrorMessage)> GetSurveyResponsesBySurveyAndLocationAsync(int surveyId, string location); + Task<(bool IsSuccess, dynamic SurveyResponses, string ErrorMessage)> GetSurveyResponsesByMaintenanceCenterAsync(int surveyId); + Task<(bool IsSuccess, dynamic SurveyResponses, string ErrorMessage)> GetResponsesByAnswerAsync(int surveyId, int questionId, string answer); + + Task<(bool IsSuccess, Models.SurveyResponse SurveyResponse, string ErrorMessage)> PostSurveyAnswersAsync(Models.AnswerRequest answers); + + } +} diff --git a/DamageAssesmentApi/DamageAssesment.Api.SurveyResponses/Models/AggregateAnswer.cs b/DamageAssesmentApi/DamageAssesment.Api.SurveyResponses/Models/AggregateAnswer.cs new file mode 100644 index 0000000..d728e1d --- /dev/null +++ b/DamageAssesmentApi/DamageAssesment.Api.SurveyResponses/Models/AggregateAnswer.cs @@ -0,0 +1,11 @@ +using System.ComponentModel.DataAnnotations; + +namespace DamageAssesment.Api.SurveyResponses.Models +{ + public class AggregateAnswer + { + public string? Answer { get; set; } + public int Counter { get; set; } + + } +} diff --git a/DamageAssesmentApi/DamageAssesment.Api.SurveyResponses/Models/AggregateResult.cs b/DamageAssesmentApi/DamageAssesment.Api.SurveyResponses/Models/AggregateResult.cs new file mode 100644 index 0000000..ef8d174 --- /dev/null +++ b/DamageAssesmentApi/DamageAssesment.Api.SurveyResponses/Models/AggregateResult.cs @@ -0,0 +1,11 @@ +using System.ComponentModel.DataAnnotations; + +namespace DamageAssesment.Api.SurveyResponses.Models +{ + public class AggregateResult + { + public string RegionId { get; set; } + public AggregateAnswer Answers { get; set; } + + } +} diff --git a/DamageAssesmentApi/DamageAssesment.Api.SurveyResponses/Models/Answer.cs b/DamageAssesmentApi/DamageAssesment.Api.SurveyResponses/Models/Answer.cs new file mode 100644 index 0000000..cab6f5b --- /dev/null +++ b/DamageAssesmentApi/DamageAssesment.Api.SurveyResponses/Models/Answer.cs @@ -0,0 +1,18 @@ +using System.ComponentModel.DataAnnotations; + +namespace DamageAssesment.Api.SurveyResponses.Models +{ + public class Answer + { + public int Id { get; set; } + public int QuestionId { get; set; } + public string? LocationId { get; set; } + public string AnswerText { get; set; } + public string? Comment { get; set; } + public int SurveyResponseId { get; set; } + public string? RegionId { get; set; } + // public string? Name { get; set; } + // public string? Abbreviation { get; set; } + + } +} diff --git a/DamageAssesmentApi/DamageAssesment.Api.SurveyResponses/Models/AnswerData.cs b/DamageAssesmentApi/DamageAssesment.Api.SurveyResponses/Models/AnswerData.cs new file mode 100644 index 0000000..cee0699 --- /dev/null +++ b/DamageAssesmentApi/DamageAssesment.Api.SurveyResponses/Models/AnswerData.cs @@ -0,0 +1,13 @@ +using System.ComponentModel.DataAnnotations; + +namespace DamageAssesment.Api.SurveyResponses.Models +{ + public class AnswerData + { + public string RegionId { get; set; } + public string Name { get; set; } + public string Abbreviation { get; set; } + public List Answers { get; set; } + + } +} diff --git a/DamageAssesmentApi/DamageAssesment.Api.SurveyResponses/Models/AnswerRequest.cs b/DamageAssesmentApi/DamageAssesment.Api.SurveyResponses/Models/AnswerRequest.cs new file mode 100644 index 0000000..68a217a --- /dev/null +++ b/DamageAssesmentApi/DamageAssesment.Api.SurveyResponses/Models/AnswerRequest.cs @@ -0,0 +1,10 @@ +namespace DamageAssesment.Api.SurveyResponses.Models +{ + public class AnswerRequest + { + public int SurveyId { get; set; } + public string LocationId { get; set; } + public string EmployeeId { get; set; } + public List Answers { get; set; } + } +} diff --git a/DamageAssesmentApi/DamageAssesment.Api.SurveyResponses/Models/Attachment.cs b/DamageAssesmentApi/DamageAssesment.Api.SurveyResponses/Models/Attachment.cs new file mode 100644 index 0000000..92ab874 --- /dev/null +++ b/DamageAssesmentApi/DamageAssesment.Api.SurveyResponses/Models/Attachment.cs @@ -0,0 +1,21 @@ +using System.ComponentModel.DataAnnotations; + +namespace DamageAssesment.Api.SurveyResponses.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 Attachment(int answerId, string uri) + { + this.AnswerId = answerId; + this.URI = uri; + } + } +} diff --git a/DamageAssesmentApi/DamageAssesment.Api.SurveyResponses/Models/AttachmentInfo.cs b/DamageAssesmentApi/DamageAssesment.Api.SurveyResponses/Models/AttachmentInfo.cs new file mode 100644 index 0000000..e3e30b9 --- /dev/null +++ b/DamageAssesmentApi/DamageAssesment.Api.SurveyResponses/Models/AttachmentInfo.cs @@ -0,0 +1,20 @@ +namespace DamageAssesment.Api.SurveyResponses.Models +{ + public class AttachmentInfo + { + public int ResponseId { get; set; } + public List Answers { get; set; } + } + public class AnswerInfo + { + public int AnswerId { get; set; } + public List 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; } + } +} diff --git a/DamageAssesmentApi/DamageAssesment.Api.SurveyResponses/Models/Employee.cs b/DamageAssesmentApi/DamageAssesment.Api.SurveyResponses/Models/Employee.cs new file mode 100644 index 0000000..c1fb576 --- /dev/null +++ b/DamageAssesmentApi/DamageAssesment.Api.SurveyResponses/Models/Employee.cs @@ -0,0 +1,21 @@ +using System.ComponentModel.DataAnnotations; + +namespace DamageAssesment.Api.SurveyResponses.Models +{ + public class Employee + { + public string Id { 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; } + } +} diff --git a/DamageAssesmentApi/DamageAssesment.Api.SurveyResponses/Models/Location.cs b/DamageAssesmentApi/DamageAssesment.Api.SurveyResponses/Models/Location.cs new file mode 100644 index 0000000..4c7f846 --- /dev/null +++ b/DamageAssesmentApi/DamageAssesment.Api.SurveyResponses/Models/Location.cs @@ -0,0 +1,11 @@ +namespace DamageAssesment.Api.SurveyResponses.Models +{ + public class Location + { + public string Id { get; set; } + public string RegionId { get; set; } + public string Name { get; set; } + public string MaintenanceCenter { get; set; } + public string SchoolType { get; set; } + } +} diff --git a/DamageAssesmentApi/DamageAssesment.Api.SurveyResponses/Models/Question.cs b/DamageAssesmentApi/DamageAssesment.Api.SurveyResponses/Models/Question.cs new file mode 100644 index 0000000..5dba504 --- /dev/null +++ b/DamageAssesmentApi/DamageAssesment.Api.SurveyResponses/Models/Question.cs @@ -0,0 +1,24 @@ +using System.ComponentModel.DataAnnotations; + +namespace DamageAssesment.Api.SurveyResponses.Models +{ + public class Question + { + public int Id { get; set; } + public List Questions { get; set; } + + //public int QuestionTypeID { get; set; } + + public string TypeText { get; set; } = string.Empty; + + public int QuestionNumber { get; set; } + public bool IsRequired { get; set; } + public bool Comment { get; set; } + + public bool Key { get; set; } + public int? SurveyId { get; set; } + public string QuestionGroup { get; set; } + public int CategoryId { get; set; } + // public int? Survey_SurveyID { get; set; } + } +} diff --git a/DamageAssesmentApi/DamageAssesment.Api.SurveyResponses/Models/QuestionRequest.cs b/DamageAssesmentApi/DamageAssesment.Api.SurveyResponses/Models/QuestionRequest.cs new file mode 100644 index 0000000..d0930ab --- /dev/null +++ b/DamageAssesmentApi/DamageAssesment.Api.SurveyResponses/Models/QuestionRequest.cs @@ -0,0 +1,10 @@ +namespace DamageAssesment.Api.SurveyResponses.Models +{ + public class QuestionRequest + { + public int QuestionId { get; set; } + public string AnswerText { get; set; } + public string Comment { get; set; } + public List PostedFiles { get; set; } = new List(); + } +} diff --git a/DamageAssesmentApi/DamageAssesment.Api.SurveyResponses/Models/QuestionsTranslation.cs b/DamageAssesmentApi/DamageAssesment.Api.SurveyResponses/Models/QuestionsTranslation.cs new file mode 100644 index 0000000..e347a5c --- /dev/null +++ b/DamageAssesmentApi/DamageAssesment.Api.SurveyResponses/Models/QuestionsTranslation.cs @@ -0,0 +1,8 @@ +namespace DamageAssesment.Api.SurveyResponses.Models +{ + public class QuestionsTranslation + { + public string QuestionText { get; set; } + public string Language { get; set; } = "En"; + } +} diff --git a/DamageAssesmentApi/DamageAssesment.Api.SurveyResponses/Models/Region.cs b/DamageAssesmentApi/DamageAssesment.Api.SurveyResponses/Models/Region.cs new file mode 100644 index 0000000..b1941d2 --- /dev/null +++ b/DamageAssesmentApi/DamageAssesment.Api.SurveyResponses/Models/Region.cs @@ -0,0 +1,11 @@ +using System.ComponentModel.DataAnnotations; + +namespace DamageAssesment.Api.SurveyResponses.Models +{ + public class Region + { + public string Id { get; set; } + public string Name { get; set; } + public string Abbreviation { get; set; } + } +} diff --git a/DamageAssesmentApi/DamageAssesment.Api.SurveyResponses/Models/ResultData.cs b/DamageAssesmentApi/DamageAssesment.Api.SurveyResponses/Models/ResultData.cs new file mode 100644 index 0000000..4df1631 --- /dev/null +++ b/DamageAssesmentApi/DamageAssesment.Api.SurveyResponses/Models/ResultData.cs @@ -0,0 +1,10 @@ +using System.ComponentModel.DataAnnotations; + +namespace DamageAssesment.Api.SurveyResponses.Models +{ + public class ResultData + { + public List Regions { get; set; } + + } +} diff --git a/DamageAssesmentApi/DamageAssesment.Api.SurveyResponses/Models/Survey.cs b/DamageAssesmentApi/DamageAssesment.Api.SurveyResponses/Models/Survey.cs new file mode 100644 index 0000000..04b60e5 --- /dev/null +++ b/DamageAssesmentApi/DamageAssesment.Api.SurveyResponses/Models/Survey.cs @@ -0,0 +1,28 @@ +using System.ComponentModel.DataAnnotations; + +namespace DamageAssesment.Api.SurveyResponses.Models +{ + public class Survey + { + [Key] + public int Id { get; set; } + + [StringLength(100)] + public string Title { get; set; } + + //[StringLength(1000)] + //public string Description { get; set; } + + public bool IsEnabled { get; set; } + + public DateTime? StartDate { get; set; } + + public DateTime? EndDate { get; set; } + + //public DateTime CreatedDate { get; set; } + + //[StringLength(6)] + //public string EmployeeID { get; set; } + + } +} diff --git a/DamageAssesmentApi/DamageAssesment.Api.SurveyResponses/Models/SurveyQuestion.cs b/DamageAssesmentApi/DamageAssesment.Api.SurveyResponses/Models/SurveyQuestion.cs new file mode 100644 index 0000000..d510b4e --- /dev/null +++ b/DamageAssesmentApi/DamageAssesment.Api.SurveyResponses/Models/SurveyQuestion.cs @@ -0,0 +1,10 @@ +namespace DamageAssesment.Api.SurveyResponses.Models +{ + public class SurveyQuestions + { + public int CategoryId { get; set; } + public string CategoryName { get; set; } + public string CategoryImage { get; set; } + public List Questions { get; set; } + } +} diff --git a/DamageAssesmentApi/DamageAssesment.Api.SurveyResponses/Models/SurveyResponse.cs b/DamageAssesmentApi/DamageAssesment.Api.SurveyResponses/Models/SurveyResponse.cs new file mode 100644 index 0000000..12ed615 --- /dev/null +++ b/DamageAssesmentApi/DamageAssesment.Api.SurveyResponses/Models/SurveyResponse.cs @@ -0,0 +1,28 @@ +using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations.Schema; + +namespace DamageAssesment.Api.SurveyResponses.Models +{ + public class SurveyResponse + { + [Key] + public int Id { get; set; } + + [ForeignKey("Survey")] + public int SurveyId { get; set; } + + [ForeignKey("Location")] + public string LocationId { get; set; } + + [ForeignKey("Employee")] + public string EmployeeId { get; set; } + + //public DateTime? CreatedDate { get; set; } + + //[StringLength(50)] + //public string ClientDevice { get; set; } + + //[StringLength(250)] + //public string KeyAnswerResult { get; set; } + } +} diff --git a/DamageAssesmentApi/DamageAssesment.Api.SurveyResponses/Profiles/SurveyResponsesProvider.cs b/DamageAssesmentApi/DamageAssesment.Api.SurveyResponses/Profiles/SurveyResponsesProvider.cs new file mode 100644 index 0000000..d7c65a0 --- /dev/null +++ b/DamageAssesmentApi/DamageAssesment.Api.SurveyResponses/Profiles/SurveyResponsesProvider.cs @@ -0,0 +1,11 @@ +namespace DamageAssesment.Api.SurveyResponses.Profiles +{ + public class SurveyResponsesProvider : AutoMapper.Profile + { + public SurveyResponsesProvider() + { + CreateMap(); + CreateMap(); + } + } +} diff --git a/DamageAssesmentApi/DamageAssesment.Api.SurveyResponses/Program.cs b/DamageAssesmentApi/DamageAssesment.Api.SurveyResponses/Program.cs new file mode 100644 index 0000000..b94d753 --- /dev/null +++ b/DamageAssesmentApi/DamageAssesment.Api.SurveyResponses/Program.cs @@ -0,0 +1,71 @@ +using DamageAssesment.Api.SurveyResponses.Db; +using DamageAssesment.Api.SurveyResponses.Interfaces; +using DamageAssesment.Api.SurveyResponses.Providers; +using Microsoft.AspNetCore.DataProtection.XmlEncryption; +using Microsoft.EntityFrameworkCore; +using Polly; + +var builder = WebApplication.CreateBuilder(args); +const int maxApiCallRetries = 3; +const int intervalToRetry = 2; //2 seconds +const int maxRetryForCircuitBraker = 5; +const int intervalForCircuitBraker = 5; //5 seconds + + +// Add services to the container. + +builder.Services.AddControllers(); +// Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle + +builder.Services.AddScoped(); +//builder.Services.AddScoped(); + +builder.Services.AddHttpClient(). + AddTransientHttpErrorPolicy(policy => policy.WaitAndRetryAsync(maxApiCallRetries, _ => TimeSpan.FromSeconds(intervalToRetry))). + AddTransientHttpErrorPolicy(policy => policy.CircuitBreakerAsync(maxRetryForCircuitBraker, TimeSpan.FromSeconds(intervalForCircuitBraker) )); + +builder.Services.AddHttpClient(). + AddTransientHttpErrorPolicy(policy => policy.WaitAndRetryAsync(maxApiCallRetries, _ => TimeSpan.FromSeconds(intervalToRetry))). + AddTransientHttpErrorPolicy(policy => policy.CircuitBreakerAsync(maxRetryForCircuitBraker, TimeSpan.FromSeconds(intervalForCircuitBraker))); + +builder.Services.AddHttpClient(). + AddTransientHttpErrorPolicy(policy => policy.WaitAndRetryAsync(maxApiCallRetries, _ => TimeSpan.FromSeconds(intervalToRetry))). + AddTransientHttpErrorPolicy(policy => policy.CircuitBreakerAsync(maxRetryForCircuitBraker, TimeSpan.FromSeconds(intervalForCircuitBraker))); + +builder.Services.AddHttpClient(). + AddTransientHttpErrorPolicy(policy => policy.WaitAndRetryAsync(maxApiCallRetries, _ => TimeSpan.FromSeconds(intervalToRetry))). + AddTransientHttpErrorPolicy(policy => policy.CircuitBreakerAsync(maxRetryForCircuitBraker, TimeSpan.FromSeconds(intervalForCircuitBraker))); + +builder.Services.AddHttpClient(). + AddTransientHttpErrorPolicy(policy => policy.WaitAndRetryAsync(maxApiCallRetries, _ => TimeSpan.FromSeconds(intervalToRetry))). + AddTransientHttpErrorPolicy(policy => policy.CircuitBreakerAsync(maxRetryForCircuitBraker, TimeSpan.FromSeconds(intervalForCircuitBraker))); + +builder.Services.AddHttpClient(). + AddTransientHttpErrorPolicy(policy => policy.WaitAndRetryAsync(maxApiCallRetries, _ => TimeSpan.FromSeconds(intervalToRetry))). + AddTransientHttpErrorPolicy(policy => policy.CircuitBreakerAsync(maxRetryForCircuitBraker, TimeSpan.FromSeconds(intervalForCircuitBraker))); + +builder.Services.AddHttpClient(). + AddTransientHttpErrorPolicy(policy => policy.WaitAndRetryAsync(maxApiCallRetries, _ => TimeSpan.FromSeconds(intervalToRetry))). + AddTransientHttpErrorPolicy(policy => policy.CircuitBreakerAsync(maxRetryForCircuitBraker, TimeSpan.FromSeconds(intervalForCircuitBraker))); + +builder.Services.AddAutoMapper(AppDomain.CurrentDomain.GetAssemblies()); +builder.Services.AddEndpointsApiExplorer(); +builder.Services.AddSwaggerGen(); +builder.Services.AddDbContext(option => +{ + option.UseInMemoryDatabase("SurveyResponses"); +}); +var app = builder.Build(); + +// Configure the HTTP request pipeline. +if (app.Environment.IsDevelopment()) +{ + app.UseSwagger(); + app.UseSwaggerUI(); +} + +app.UseAuthorization(); + +app.MapControllers(); + +app.Run(); diff --git a/DamageAssesmentApi/DamageAssesment.Api.SurveyResponses/Properties/launchSettings.json b/DamageAssesmentApi/DamageAssesment.Api.SurveyResponses/Properties/launchSettings.json new file mode 100644 index 0000000..0d51b15 --- /dev/null +++ b/DamageAssesmentApi/DamageAssesment.Api.SurveyResponses/Properties/launchSettings.json @@ -0,0 +1,31 @@ +{ + "$schema": "https://json.schemastore.org/launchsettings.json", + "iisSettings": { + "windowsAuthentication": false, + "anonymousAuthentication": true, + "iisExpress": { + "applicationUrl": "http://localhost:58856", + "sslPort": 0 + } + }, + "profiles": { + "DamageAssesment.Api.SurveyResponses": { + "commandName": "Project", + "dotnetRunMessages": true, + "launchBrowser": true, + "launchUrl": "swagger", + "applicationUrl": "http://localhost:5104", + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development" + } + }, + "IIS Express": { + "commandName": "IISExpress", + "launchBrowser": true, + "launchUrl": "swagger", + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development" + } + } + } +} diff --git a/DamageAssesmentApi/DamageAssesment.Api.SurveyResponses/Providers/AnswerServiceProvider.cs b/DamageAssesmentApi/DamageAssesment.Api.SurveyResponses/Providers/AnswerServiceProvider.cs new file mode 100644 index 0000000..5796eff --- /dev/null +++ b/DamageAssesmentApi/DamageAssesment.Api.SurveyResponses/Providers/AnswerServiceProvider.cs @@ -0,0 +1,87 @@ +using DamageAssesment.Api.SurveyResponses.Bases; +using DamageAssesment.Api.SurveyResponses.Db; +using DamageAssesment.Api.SurveyResponses.Interfaces; +using DamageAssesment.Api.SurveyResponses.Models; +using Newtonsoft.Json; +using System.Data.Common; +using System.Security.Cryptography; +using System.Text.Json.Nodes; +using System.Text; + +namespace DamageAssesment.Api.SurveyResponses.Providers +{ + public class AnswerServiceProvider : ServiceProviderBase, IAnswerServiceProvider + { + + public AnswerServiceProvider(IConfiguration configuration, HttpClient httpClient, ILogger logger, IRegionServiceProvider regionServiceProvider, ILocationServiceProvider locationServiceProvider) : base(configuration, httpClient, logger, "/api/Answers", configuration.GetValue("EndPointSettings:AnswerUrlBase")) + { + } + public async Task> getAnswersAsync() + { + try + { + httpClient.BaseAddress = new Uri(urlBase); + var response = await httpClient.GetAsync(ressource); + response.EnsureSuccessStatusCode(); + var responseString = await response.Content.ReadAsStringAsync(); + var answers = JsonConvert.DeserializeObject>(responseString); + + if (answers == null || !answers.Any()) + return null; + else return answers; + } + catch (Exception ex) + { + logger?.LogError($"Exception Found : {ex.Message} - Ref: AnswerServiceProvider.getAnswersAsync()"); + return null; + } + } + + public async Task> GetAnswersByResponseIdAsync(int responseId) + { + try + { + httpClient.BaseAddress = new Uri(urlBase); + + var response = await httpClient.GetAsync("/api/AnswersByResponse/"+ responseId); + response.EnsureSuccessStatusCode(); + var responseString = await response.Content.ReadAsStringAsync(); + var answers = JsonConvert.DeserializeObject>(responseString); + + if (answers == null || !answers.Any()) + return null; + else return answers; + } + catch (Exception ex) + { + logger?.LogError($"Exception Found : {ex.Message} - Ref: AnswerServiceProvider.GetAnswersByResponseId()"); + return null; + } + } + + public async Task PostAnswersAsync(Answer answer) + { + try + { + httpClient.BaseAddress = new Uri(urlBase); + var jsonObject = JsonConvert.SerializeObject(answer); + var content = new StringContent(jsonObject.ToString(), Encoding.UTF8, "application/json"); + var response = await httpClient.PostAsync(ressource,content); + response.EnsureSuccessStatusCode(); + var responseString = await response.Content.ReadAsStringAsync(); + var answers = JsonConvert.DeserializeObject(responseString); + + if (answers == null) { + logger?.LogError($"Answer cannot be added - Ref: AnswerServiceProvider.PostAnswersAsync()"); + return null; + } + else return answers; + } + catch (Exception ex) + { + logger?.LogError($"Exception Found : {ex.Message} - Ref: AnswerServiceProvider.PostAnswersAsync()"); + return null; + } + } + } +} diff --git a/DamageAssesmentApi/DamageAssesment.Api.SurveyResponses/Providers/AttachmentServiceProvider.cs b/DamageAssesmentApi/DamageAssesment.Api.SurveyResponses/Providers/AttachmentServiceProvider.cs new file mode 100644 index 0000000..3e46c84 --- /dev/null +++ b/DamageAssesmentApi/DamageAssesment.Api.SurveyResponses/Providers/AttachmentServiceProvider.cs @@ -0,0 +1,67 @@ +using DamageAssesment.Api.SurveyResponses.Bases; +using DamageAssesment.Api.SurveyResponses.Interfaces; +using DamageAssesment.Api.SurveyResponses.Models; +using Microsoft.Extensions.Logging; +using Newtonsoft.Json; +using System.Net.Http; +using System.Runtime.Intrinsics.Arm; +using System.Text; + +namespace DamageAssesment.Api.SurveyResponses.Providers +{ + public class AttachmentServiceProvider : ServiceProviderBase, IAttachmentServiceProvider + { + public AttachmentServiceProvider(IConfiguration configuration, HttpClient httpClient, ILogger logger) : base(configuration, httpClient, logger, "/api/Attachments", configuration.GetValue("EndPointSettings:AttachmentUrlBase")) + { + } + + public async Task> getAttachmentsAsync() + { + try + { + httpClient.BaseAddress = new Uri(urlBase); + var response = await httpClient.GetAsync(ressource); + response.EnsureSuccessStatusCode(); + var responseString = await response.Content.ReadAsStringAsync(); + var attachments = JsonConvert.DeserializeObject>(responseString); + + if (attachments == null || !attachments.Any()) + return null; + else return attachments; + } + catch (Exception ex) + { + logger?.LogError($"Exception Found : {ex.Message} - Ref: AttachmentServiceProvider.getAttachmentsAsync()"); + return null; + } + } + + public async Task> PostAttachmentsAsync(AttachmentInfo attachmentInfo) + { + try + { + httpClient.BaseAddress = new Uri(urlBase); + var jsonObject = JsonConvert.SerializeObject(attachmentInfo); + var content = new StringContent(jsonObject.ToString(), Encoding.UTF8, "application/json"); + var response = await httpClient.PostAsync(ressource, content); + response.EnsureSuccessStatusCode(); + var responseString = await response.Content.ReadAsStringAsync(); + var attachments = JsonConvert.DeserializeObject>(responseString); + + if (attachments == null) + { + logger?.LogError($"Attachments cannot be added - Ref: AttachmentServiceProvider.PostAttachmentsAsync()"); + return null; + } + else return attachments; + } + catch (Exception ex) + { + logger?.LogError($"Exception Found : {ex.Message} - Ref: AttachmentServiceProvider.PostAttachmentsAsync()"); + return null; + } + } + + } + +} diff --git a/DamageAssesmentApi/DamageAssesment.Api.SurveyResponses/Providers/EmployeeServiceProvider.cs b/DamageAssesmentApi/DamageAssesment.Api.SurveyResponses/Providers/EmployeeServiceProvider.cs new file mode 100644 index 0000000..faf31ff --- /dev/null +++ b/DamageAssesmentApi/DamageAssesment.Api.SurveyResponses/Providers/EmployeeServiceProvider.cs @@ -0,0 +1,58 @@ +using DamageAssesment.Api.SurveyResponses.Bases; +using DamageAssesment.Api.SurveyResponses.Interfaces; +using DamageAssesment.Api.SurveyResponses.Models; +using Newtonsoft.Json; +using System.Reflection; + +namespace DamageAssesment.Api.SurveyResponses.Providers +{ + public class EmployeeServiceProvider :ServiceProviderBase, IEmployeeServiceProvider + { + public EmployeeServiceProvider(IConfiguration configuration, HttpClient httpClient, ILogger logger) : base(configuration, httpClient, logger, "/api/Employees", configuration.GetValue("EndPointSettings:EmployeeUrlBase")) + { + } + + public async Task> getEmployeesAsync() + { + try + { + httpClient.BaseAddress = new Uri(urlBase); + var response = await httpClient.GetAsync(ressource); + response.EnsureSuccessStatusCode(); + var responseString = await response.Content.ReadAsStringAsync(); + var employees = JsonConvert.DeserializeObject>(responseString); + + if (employees == null || !employees.Any()) + return null; + else return employees; + } + catch (Exception ex) + { + logger?.LogError($"Exception Found : {ex.Message} - Ref: EmployeeServiceProvider.getEmployeesAsync()"); + return null; + } + } + + public async Task getEmployeeAsync(string employeeID) + { + try + { + httpClient.BaseAddress = new Uri(urlBase); + //ressource = ressource + "/" + employeeID; + var response = await httpClient.GetAsync("/api/Employees/"+ employeeID); + response.EnsureSuccessStatusCode(); + var responseString = await response.Content.ReadAsStringAsync(); + var employee = JsonConvert.DeserializeObject(responseString); + + if (employee == null ) + return null; + else return employee; + } + catch (Exception ex) + { + logger?.LogError($"Exception Found : {ex.Message} - Ref: EmployeeServiceProvider.getEmployeeAsync()"); + return null; + } + } + } +} diff --git a/DamageAssesmentApi/DamageAssesment.Api.SurveyResponses/Providers/LocationServiceProvider.cs b/DamageAssesmentApi/DamageAssesment.Api.SurveyResponses/Providers/LocationServiceProvider.cs new file mode 100644 index 0000000..d5c9161 --- /dev/null +++ b/DamageAssesmentApi/DamageAssesment.Api.SurveyResponses/Providers/LocationServiceProvider.cs @@ -0,0 +1,35 @@ +using DamageAssesment.Api.SurveyResponses.Bases; +using DamageAssesment.Api.SurveyResponses.Interfaces; +using DamageAssesment.Api.SurveyResponses.Models; +using Newtonsoft.Json; + +namespace DamageAssesment.Api.SurveyResponses.Providers +{ + public class LocationServiceProvider :ServiceProviderBase, ILocationServiceProvider + { + public LocationServiceProvider(IConfiguration configuration, HttpClient httpClient, ILogger logger) : base(configuration, httpClient, logger, "/api/Locations", configuration.GetValue("EndPointSettings:LocationUrlBase")) + { + } + + public async Task> getLocationsAsync() + { + try + { + httpClient.BaseAddress = new Uri(urlBase); + var response = await httpClient.GetAsync(ressource); + response.EnsureSuccessStatusCode(); + var responseString = await response.Content.ReadAsStringAsync(); + var locations = JsonConvert.DeserializeObject>(responseString); + + if (locations == null || !locations.Any()) + return null; + else return locations; + } + catch (Exception ex) + { + logger?.LogError($"Exception Found : {ex.Message} - Ref: LocationServiceProvider.getLocationsAsync()"); + return null; + } + } + } +} diff --git a/DamageAssesmentApi/DamageAssesment.Api.SurveyResponses/Providers/QuestionServiceProvider.cs b/DamageAssesmentApi/DamageAssesment.Api.SurveyResponses/Providers/QuestionServiceProvider.cs new file mode 100644 index 0000000..2d9e915 --- /dev/null +++ b/DamageAssesmentApi/DamageAssesment.Api.SurveyResponses/Providers/QuestionServiceProvider.cs @@ -0,0 +1,80 @@ +using DamageAssesment.Api.SurveyResponses.Bases; +using DamageAssesment.Api.SurveyResponses.Interfaces; +using DamageAssesment.Api.SurveyResponses.Models; +using Newtonsoft.Json; + + + +namespace DamageAssesment.Api.SurveyResponses.Providers +{ + public class QuestionServiceProvider : ServiceProviderBase, IQuestionServiceProvider + { + public QuestionServiceProvider(IConfiguration configuration, HttpClient httpClient, ILogger logger) : base(configuration, httpClient, logger, "/api/Questions", configuration.GetValue("EndPointSettings:QuestionUrlBase")) + { + } + + public async Task> getQuestionsAsync() + { + try + { + httpClient.BaseAddress = new Uri(urlBase); + var response = await httpClient.GetAsync(ressource); + response.EnsureSuccessStatusCode(); + var responseString = await response.Content.ReadAsStringAsync(); + var questions = JsonConvert.DeserializeObject>(responseString); + + if (questions == null || !questions.Any()) + return null; + else return questions; + } + catch (Exception ex) + { + logger?.LogError($"Exception Found : {ex.Message} - Ref: QuestionServiceProvider.getQuestionsAsync()"); + return null; + } + } + + public async Task> getSurveyQuestionsAsync(int surveyId) + { + try + { + httpClient.BaseAddress = new Uri(urlBase); + var response = await httpClient.GetAsync("/api/GetSurveyQuestions/" + surveyId); + response.EnsureSuccessStatusCode(); + var responseString = await response.Content.ReadAsStringAsync(); + var questions = JsonConvert.DeserializeObject>(responseString); + + if (questions == null || !questions.Any()) + return null; + else return questions; + } + catch (Exception ex) + { + logger?.LogError($"Exception Found : {ex.Message} - Ref: QuestionServiceProvider.getSurveyQuestionsAsync()"); + return null; + } + } + + + public async Task getQuestionsAsync(int questionId) + { + try + { + httpClient.BaseAddress = new Uri(urlBase); + var response = await httpClient.GetAsync("/api/Questions/" + questionId); + response.EnsureSuccessStatusCode(); + var responseString = await response.Content.ReadAsStringAsync(); + var question = JsonConvert.DeserializeObject(responseString); + + if (question == null) + return null; + else return question; + } + catch (Exception ex) + { + logger?.LogError($"Exception Found : {ex.Message} - Ref: QuestionServiceProvider.getQuestionsAsync(questionId)"); + return null; + } + } + } +} diff --git a/DamageAssesmentApi/DamageAssesment.Api.SurveyResponses/Providers/RegionServiceProvider.cs b/DamageAssesmentApi/DamageAssesment.Api.SurveyResponses/Providers/RegionServiceProvider.cs new file mode 100644 index 0000000..a435081 --- /dev/null +++ b/DamageAssesmentApi/DamageAssesment.Api.SurveyResponses/Providers/RegionServiceProvider.cs @@ -0,0 +1,34 @@ +using DamageAssesment.Api.SurveyResponses.Bases; +using DamageAssesment.Api.SurveyResponses.Interfaces; +using DamageAssesment.Api.SurveyResponses.Models; +using Newtonsoft.Json; + +namespace DamageAssesment.Api.SurveyResponses.Providers +{ + public class RegionServiceProvider : ServiceProviderBase, IRegionServiceProvider + { + public RegionServiceProvider(IConfiguration configuration, HttpClient httpClient, ILogger logger) : base(configuration, httpClient, logger, "/api/Regions", configuration.GetValue("EndPointSettings:LocationUrlBase")) + { + } + public async Task> getRegionsAsync() + { + try + { + httpClient.BaseAddress = new Uri(urlBase); + var response = await httpClient.GetAsync(ressource); + response.EnsureSuccessStatusCode(); + var responseString = await response.Content.ReadAsStringAsync(); + var regions = JsonConvert.DeserializeObject>(responseString); + + if (regions == null || !regions.Any()) + return null; + else return regions; + } + catch (Exception ex) + { + logger?.LogError($"Exception Found : {ex.Message} - Ref: RegionServiceProvider.getRegionsAsync()"); + return null; + } + } + } +} diff --git a/DamageAssesmentApi/DamageAssesment.Api.SurveyResponses/Providers/SurveyResponsesProvider.cs b/DamageAssesmentApi/DamageAssesment.Api.SurveyResponses/Providers/SurveyResponsesProvider.cs new file mode 100644 index 0000000..48a6a1a --- /dev/null +++ b/DamageAssesmentApi/DamageAssesment.Api.SurveyResponses/Providers/SurveyResponsesProvider.cs @@ -0,0 +1,795 @@ +using AutoMapper; +using DamageAssesment.Api.SurveyResponses.Db; +using DamageAssesment.Api.SurveyResponses.Interfaces; +using DamageAssesment.Api.SurveyResponses.Models; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Internal; +using System.Diagnostics; +using static Microsoft.EntityFrameworkCore.DbLoggerCategory; + +namespace DamageAssesment.Api.SurveyResponses.Providers +{ + public class SurveyResponsesProvider : ISurveysResponse + { + private readonly SurveyResponseDbContext surveyResponseDbContext; + private readonly ILogger logger; + private readonly IAnswerServiceProvider answerServiceProvider; + private readonly IRegionServiceProvider regionServiceProvider; + private readonly ILocationServiceProvider locationServiceProvider; + private readonly IEmployeeServiceProvider employeeServiceProvider; + private readonly IAttachmentServiceProvider attachmentServiceProvider; + private readonly IQuestionServiceProvider questionServiceProvider; + private readonly ISurveyServiceProvider surveyServiceProvider; + private readonly IMapper mapper; + + public SurveyResponsesProvider(SurveyResponseDbContext surveyResponseDbContext, ILogger logger, IAnswerServiceProvider answerServiceProvider, IRegionServiceProvider regionServiceProvider, ILocationServiceProvider locationServiceProvider, IEmployeeServiceProvider employeeServiceProvider, IAttachmentServiceProvider attachmentServiceProvider, IQuestionServiceProvider questionServiceProvider, ISurveyServiceProvider surveyServiceProvider, IMapper mapper) + { + this.surveyResponseDbContext = surveyResponseDbContext; + this.logger = logger; + this.answerServiceProvider = answerServiceProvider; + this.regionServiceProvider = regionServiceProvider; + this.locationServiceProvider = locationServiceProvider; + this.employeeServiceProvider = employeeServiceProvider; + this.attachmentServiceProvider = attachmentServiceProvider; + this.questionServiceProvider = questionServiceProvider; + this.surveyServiceProvider = surveyServiceProvider; + this.mapper = mapper; + + seedData(); + } + + private void seedData() + { + if (!surveyResponseDbContext.SurveyResponses.Any()) + { + surveyResponseDbContext.SurveyResponses.Add(new Db.SurveyResponse { Id = 1, SurveyId = 1, EmployeeId = "Emp1", LocationId = "Loc1" }); + surveyResponseDbContext.SurveyResponses.Add(new Db.SurveyResponse { Id = 2, SurveyId = 1, EmployeeId = "Emp2", LocationId = "Loc2" }); + surveyResponseDbContext.SurveyResponses.Add(new Db.SurveyResponse { Id = 3, SurveyId = 3, EmployeeId = "Emp4", LocationId = "Loc1" }); + surveyResponseDbContext.SurveyResponses.Add(new Db.SurveyResponse { Id = 4, SurveyId = 4, EmployeeId = "Emp1", LocationId = "Loc2" }); + surveyResponseDbContext.SurveyResponses.Add(new Db.SurveyResponse { Id = 5, SurveyId = 1, EmployeeId = "Emp3", LocationId = "Loc3" }); + surveyResponseDbContext.SurveyResponses.Add(new Db.SurveyResponse { Id = 6, SurveyId = 1, EmployeeId = "Emp4", LocationId = "Loc2" }); + surveyResponseDbContext.SurveyResponses.Add(new Db.SurveyResponse { Id = 7, SurveyId = 1, EmployeeId = "Emp4", LocationId = "Loc3" }); + surveyResponseDbContext.SaveChanges(); + } + } + + public async Task<(bool IsSuccess, dynamic Answers, string ErrorMessage)> GetAnswersByRegionAsync(int surveyId) + { + try + { + logger?.LogInformation("Querying to get SurveyResponse object from DB"); + var listSurveyResponse = surveyResponseDbContext.SurveyResponses.Where(s => s.SurveyId == surveyId); + + if (listSurveyResponse.Any()) + { + var answers = await getAnswersByRegionAndSurveyIdAsync(listSurveyResponse); + return (true, answers, "Request Successful."); + } + else + { + return (false, null, "Not found"); + } + } + catch (Exception ex) + { + logger?.LogError(ex.ToString()); + return (false, null, ex.Message); + } + } + + public async Task<(bool IsSuccess, dynamic SurveyResponse, string ErrorMessage)> GetSurveyResponseByIdAsync(int responseId) + { + try + { + logger?.LogInformation("Querying to get SurveyResponse object from DB"); + var surveyResponse = surveyResponseDbContext.SurveyResponses.Where(s => s.Id == responseId).SingleOrDefault(); + + if (surveyResponse != null) + { + var answers = await getSurveyResponseByResponseIdAsync(surveyResponse); + + if (answers != null) + return (true, answers, "Request Successful."); + else + { + answers = new { }; + return (true, answers, "Empty object returned"); + } + } + else + { + return (false, null, "Not found"); + } + } + catch (Exception ex) + { + logger?.LogError(ex.ToString()); + return (false, null, ex.Message); + } + } + + + + public async Task<(bool IsSuccess, dynamic SurveyResponses, string ErrorMessage)> GetSurveyResponsesBySurveyAsync(int surveyId) + { + try + { + logger?.LogInformation("Querying to get Survey object from microservice"); + var survey = await surveyServiceProvider.getSurveyAsync(surveyId); + + if (survey != null) + { + var answers = await getSurveyResponsesBySurveyIdAsync(surveyId); + + if (answers != null) + return (true, answers, "Request Successful."); + else + { + answers = new List(); + return (true, answers, "Empty object returned"); + } + } + else + { + return (false, null, "Not found"); + } + } + catch (Exception ex) + { + logger?.LogError(ex.ToString()); + return (false, null, ex.Message); + } + } + + public async Task<(bool IsSuccess, dynamic SurveyResponses, string ErrorMessage)> GetSurveyResponsesBySurveyAndLocationAsync(int surveyId, string locationId) + { + try + { + logger?.LogInformation("Querying to get Survey object from microservice"); + var survey = await surveyServiceProvider.getSurveyAsync(surveyId); + + if (survey != null) + { + var answers = await getSurveyResponsesBySurveyIdLocationIdAsync(surveyId, locationId); + + if (answers != null) + return (true, answers, "Request Successful."); + else + { + answers = new List(); + return (true, answers, "Empty object returned"); + } + } + else + { + return (false, null, "Not found"); + } + } + catch (Exception ex) + { + logger?.LogError(ex.ToString()); + return (false, null, ex.Message); + } + } + + public async Task<(bool IsSuccess, dynamic SurveyResponses, string ErrorMessage)> GetSurveyResponsesByMaintenanceCenterAsync(int surveyId) + { + try + { + logger?.LogInformation("Querying to get Survey object from microservice"); + var survey = await surveyServiceProvider.getSurveyAsync(surveyId); + + if (survey != null) + { + var answers = await getResultsByMaintenanceCenterAsync(surveyId); + + if (answers != null) + return (true, answers, "Request Successful."); + else + { + answers = new List(); + return (true, answers, "Empty object returned"); + } + } + else + { + return (false, null, "Not found"); + } + } + catch (Exception ex) + { + logger?.LogError(ex.ToString()); + return (false, null, ex.Message); + } + } + + public async Task<(bool IsSuccess, dynamic SurveyResponses, string ErrorMessage)> GetResponsesByAnswerAsync(int surveyId, int questionId, string answer) + { + try + { + logger?.LogInformation("Querying to get Survey object from microservice"); + var survey = await surveyServiceProvider.getSurveyAsync(surveyId); + var question = await questionServiceProvider.getQuestionsAsync(questionId); + bool IsCorrectAnswer = answer.ToLower().Equals("yes") || answer.ToLower().Equals("no") ? true : false; + + + if (survey != null && question != null && IsCorrectAnswer) + { + var answers = await getSurveyResponsesByAnswerAsync(survey, question, answer); + + if (answers != null) + return (true, answers, "Request Successful."); + else + { + answers = new List(); + return (true, answers, "Empty object returned"); + } + } + else + { + return (false, null, "Not found"); + } + } + catch (Exception ex) + { + logger?.LogError(ex.ToString()); + return (false, null, ex.Message); + } + } + + + public async Task<(bool IsSuccess, dynamic surveyResponses, string ErrorMessage)> GetSurveyResponsesAsync() + { + try + { + var answers = await getAllSurveyResponsesAsync(); + + if (answers != null) + return (true, answers, "Request Successful."); + else + { + answers = new List(); + return (true, answers, "Empty object returned"); + } + + } + catch (Exception ex) + { + logger?.LogError(ex.ToString()); + return (false, null, ex.Message); + } + } + + public async Task<(bool IsSuccess, Models.SurveyResponse SurveyResponse, string ErrorMessage)> PostSurveyResponseAsync(Models.SurveyResponse surveyResponse) + { + try + { + if (surveyResponse != null) + { + var surveyResponses = await surveyResponseDbContext.SurveyResponses.ToListAsync(); + surveyResponse.Id = surveyResponses.Count + 1; + surveyResponseDbContext.SurveyResponses.Add(mapper.Map(surveyResponse)); + surveyResponseDbContext.SaveChanges(); + return (true, surveyResponse, "Request Successful"); + } + else + { + logger?.LogInformation($"SurveyResponseID={surveyResponse.Id} cannot be added"); + return (false, null, "Survey cannot be added"); + } + } + catch (Exception ex) + { + logger?.LogError(ex.ToString()); + return (false, null, ex.Message); + } + } + + + public async Task<(bool IsSuccess, Models.SurveyResponse SurveyResponse, string ErrorMessage)> PutSurveyResponseAsync(int Id, Models.SurveyResponse SurveyResponse) + { + try + { + if (SurveyResponse != null) + { + var _SurveyResponse = await surveyResponseDbContext.SurveyResponses.Where(s => s.Id == Id).FirstOrDefaultAsync(); + + if (_SurveyResponse != null) + { + _SurveyResponse.SurveyId = SurveyResponse.SurveyId; + _SurveyResponse.EmployeeId = SurveyResponse.EmployeeId; + _SurveyResponse.LocationId = SurveyResponse.LocationId; + surveyResponseDbContext.SaveChanges(); + return (true, mapper.Map(_SurveyResponse), "Successful"); + } + else + { + logger?.LogInformation($"SurveyReponseId = {Id} Not found"); + return (false, null, "Not Found"); + } + + } + else + { + logger?.LogInformation($"SurveyReponseId = {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.SurveyResponse SurveyResponse, string ErrorMessage)> DeleteSurveyResponseAsync(int Id) + { + try + { + var _SurveyResponse = await surveyResponseDbContext.SurveyResponses.Where(s => s.Id == Id).FirstOrDefaultAsync(); + + if (_SurveyResponse != null) + { + surveyResponseDbContext.Remove(_SurveyResponse); + surveyResponseDbContext.SaveChanges(); + return (true, mapper.Map(_SurveyResponse), "Successful"); + } + else + { + logger?.LogInformation($"SurveyReponseId = {Id} Not found"); + return (false, null, "Not Found"); + } + + } + catch (Exception ex) + { + logger?.LogError(ex.ToString()); + return (false, null, ex.Message); + } + } + + //Method to get Answers by region with surveyId as input parameter + private async Task getAnswersByRegionAndSurveyIdAsync(IQueryable surveyResponses) + { + try + { + var answersList = await answerServiceProvider.getAnswersAsync(); + if (answersList == null || !answersList.Any()) + return null; + + //get all the answers for the particular survey + var surveyAnswers = answersList.Join( + surveyResponses, + answer => answer.SurveyResponseId, + surveyResponse => surveyResponse.Id, + (answer, surveyResponse) => new + Answer + { + Id = answer.Id, + QuestionId = answer.QuestionId, + AnswerText = answer.AnswerText, + Comment = answer.Comment, + LocationId = surveyResponse.LocationId, + SurveyResponseId = surveyResponse.Id + }); + + if (surveyAnswers == null || !surveyAnswers.Any()) + return null; + + var regions = await regionServiceProvider.getRegionsAsync(); + var locations = await locationServiceProvider.getLocationsAsync(); + + if (regions == null || !regions.Any() || locations == null || !locations.Any()) + return null; + + + //get all the answers based on the locations + var result = from answer in surveyAnswers + from location in locations + where answer.LocationId == location.Id + select new Answer + { + Id = answer.Id, + QuestionId = answer.QuestionId, + AnswerText = answer.AnswerText, + Comment = answer.Comment, + RegionId = location.RegionId, + LocationId = location.Id, + SurveyResponseId = answer.SurveyResponseId + }; + + //group records by answer and region + var q = from e in result + group e by (e.RegionId, e.AnswerText) into g + select new AggregateResult + { + RegionId = g.Key.RegionId, + Answers = new AggregateAnswer + { + Answer = g.Key.AnswerText, + Counter = g.Count() + } + }; + + //build the result + List resultList = new List(); + foreach (Region region in regions) + { + var answers = q.Where(x => x.RegionId.Equals(region.Id)).Select(x => x.Answers).ToList(); + resultList.Add(new AnswerData { RegionId = region.Id, Name = region.Name, Abbreviation = region.Abbreviation, Answers = answers }); + } + + //return the object result + return new ResultData { Regions = resultList }; + } + catch (Exception ex) + { + logger?.LogError($"Exception Found : {ex.Message} - Ref: SurveyResponsesProvider.getSurveyResultAsync()"); + return null; + } + } + + //Method to get Survey Response by ResponseId + private async Task getSurveyResponseByResponseIdAsync(Db.SurveyResponse surveyResponse) + { + try + { + var surveyResonses = await surveyResponseDbContext.SurveyResponses.Where(x => x.Id == surveyResponse.Id).ToListAsync(); + //var surveyResponse = surveyResonses.SingleOrDefault(); + var employee = await employeeServiceProvider.getEmployeeAsync(surveyResponse.EmployeeId); + var answers = await answerServiceProvider.GetAnswersByResponseIdAsync(surveyResponse.Id); + var allQuestions = await questionServiceProvider.getQuestionsAsync(); + var questions = allQuestions.Where(s=> s.SurveyId == surveyResponse.Id); + var attachments = await attachmentServiceProvider.getAttachmentsAsync(); + + + var result = from r in surveyResonses + select new + { + r.Id, + r.SurveyId, + r.LocationId, + r.EmployeeId, + Employee = employee, + answers = from ans in answers + select new + { + ans.QuestionId, + ans.Id, + ans.AnswerText, + ans.Comment, + Questions = (from q in questions where q.Id == ans.QuestionId select new { q.Id, q.QuestionNumber, q.QuestionGroup, q.Questions }).SingleOrDefault(), + Attachments = from att in attachments where att.AnswerId == ans.Id select new { att.Id, att.URI } + } + }; + return result.SingleOrDefault(); + } + catch (Exception ex) + { + logger?.LogError($"Exception Found : {ex.Message} - Ref: SurveyResponsesProvider.getSurveyResultAsync()"); + return null; + } + } + + + //Method to get Survey Responses by surveyId + private async Task getSurveyResponsesBySurveyIdAsync(int surveyId) + { + try + { + var surveyResonses = await surveyResponseDbContext.SurveyResponses.Where(x => x.SurveyId == surveyId).ToListAsync(); + + var employees = await employeeServiceProvider.getEmployeesAsync(); + var answers = await answerServiceProvider.getAnswersAsync(); + var questions = await questionServiceProvider.getQuestionsAsync(); + var surveyQuestions = from q in questions where q.SurveyId == surveyId select q; + + //var surveyQuestions = await questionServiceProvider.getSurveyQuestionsAsync(surveyId); + + var attachments = await attachmentServiceProvider.getAttachmentsAsync(); + var result = from r in surveyResonses + select new + { + r.Id, + r.SurveyId, + r.LocationId, + r.EmployeeId, + Employee = (from e in employees where e.Id == r.EmployeeId select new { e.Id, e.Name, e.BirthDate, e.Email, e.OfficePhoneNumber }).SingleOrDefault(), + answers = from ans in answers + where ans.SurveyResponseId == r.Id + select new + { + ans.Id, + ans.QuestionId, + ans.AnswerText, + ans.Comment, + Questions = (from q in surveyQuestions where q.Id == ans.QuestionId select new { q.Id, q.QuestionNumber, q.QuestionGroup, q.Questions }).SingleOrDefault(), + Attachments = from att in attachments where att.AnswerId == ans.Id select new { att.Id, att.URI } + + } + }; + return result; + } + catch (Exception ex) + { + logger?.LogError($"Exception Found : {ex.Message} - Ref: SurveyResponsesProvider.getSurveyResponseBySurveyIdAsync()"); + return null; + } + } + + + //Method to get All Survey Responses + private async Task getAllSurveyResponsesAsync() + { + try + { + var surveyResonses = await surveyResponseDbContext.SurveyResponses.ToListAsync(); + + var employees = await employeeServiceProvider.getEmployeesAsync(); + var answers = await answerServiceProvider.getAnswersAsync(); + var questions = await questionServiceProvider.getQuestionsAsync(); + var attachments = await attachmentServiceProvider.getAttachmentsAsync(); + + var result = from r in surveyResonses + select new + { + r.Id, + r.SurveyId, + r.LocationId, + r.EmployeeId, + Employee = (from e in employees where r.EmployeeId == e.Id select new { e.Id, e.Name, e.BirthDate, e.Email, e.OfficePhoneNumber }).SingleOrDefault(), + answers = from ans in answers + where ans.SurveyResponseId == r.Id + select new + { + ans.Id, + ans.QuestionId, + ans.AnswerText, + ans.Comment, + Questions = (from q in questions where q.Id == ans.QuestionId select new { q.Id, q.QuestionNumber, q.QuestionGroup, q.Questions }).SingleOrDefault(), + Attachments = from att in attachments where att.AnswerId == ans.Id select new { att.Id, att.URI } + } + }; + return result; + } + catch (Exception ex) + { + logger?.LogError($"Exception Found : {ex.Message} - Ref: SurveyResponsesProvider.getSurveyResponseBySurveyIdAsync()"); + return null; + } + } + + + //Method to get Answers By Maintenance Center by surveyId + private async Task getResultsByMaintenanceCenterAsync(int surveyId) + { + try + { + var surveyResponses = await surveyResponseDbContext.SurveyResponses.Where(x => x.SurveyId == surveyId).ToListAsync(); + var answers = await answerServiceProvider.getAnswersAsync(); + var locations = await locationServiceProvider.getLocationsAsync(); + var maintenanceCenters = locations.DistinctBy(m => m.MaintenanceCenter); + + //get all the answers for the particular survey + var surveyAnswers = from resp in surveyResponses + from ans in answers + where ans.SurveyResponseId.Equals(resp.Id) + select new + { + AnswerId = ans.Id, + ans.QuestionId, + ans.AnswerText, + ans.Comment, + resp.LocationId, + ResponseId = resp.Id + }; + + //get all the answers with location + var surveyAnswersLocations = from surveyAns in surveyAnswers + from location in locations + where surveyAns.LocationId == location.Id + select new { surveyAns, location.MaintenanceCenter }; + + //aggreting the answers + var aggregatedResult = from e in surveyAnswersLocations + group e by (e.MaintenanceCenter, e.surveyAns.AnswerText) into g + select new + { + g.Key.MaintenanceCenter, + Answers = new AggregateAnswer + { + Answer = g.Key.AnswerText, + Counter = g.Count() + } + }; + + //format the result foreach maintenance center + List results = new List(); + foreach (Location m in maintenanceCenters) + { + var _answers = aggregatedResult.Where(x => x.MaintenanceCenter.Equals(m.MaintenanceCenter)).Select(x => x.Answers).ToList(); + results.Add(new { m.Name, m.Id, m.RegionId, m.MaintenanceCenter, m.SchoolType, Answers = _answers }); + } + + return results; + } + catch (Exception ex) + { + logger?.LogError($"Exception Found : {ex.Message} - Ref: SurveyResponsesProvider.getSurveyResponseBySurveyIdAsync()"); + return null; + } + } + + //Method to get Survey Responses by surveyId and LocationId + private async Task getSurveyResponsesBySurveyIdLocationIdAsync(int surveyId, string locationId) + { + try + { + var surveyResonses = await surveyResponseDbContext.SurveyResponses.Where(x => x.SurveyId == surveyId && x.LocationId.Equals(locationId)).ToListAsync(); + + var employees = await employeeServiceProvider.getEmployeesAsync(); + var answers = await answerServiceProvider.getAnswersAsync(); + var questions = await questionServiceProvider.getQuestionsAsync(); + var surveyQuestions = from q in questions where q.SurveyId == surveyId select q; + var attachments = await attachmentServiceProvider.getAttachmentsAsync(); + + var result = from r in surveyResonses + select new + { + r.Id, + r.SurveyId, + r.LocationId, + r.EmployeeId, + Employee = (from e in employees where r.EmployeeId == e.Id select new { e.Id, e.Name, e.BirthDate, e.Email, e.OfficePhoneNumber }).SingleOrDefault(), + answers = from ans in answers + where ans.SurveyResponseId == r.Id + + select new + { + ans.QuestionId, + ans.Id, + ans.AnswerText, + ans.Comment, + Questions = (from q in surveyQuestions where q.Id == ans.QuestionId select new { q.Id, q.QuestionNumber, q.QuestionGroup, q.Questions }).SingleOrDefault(), + Attachments = from att in attachments where att.AnswerId == ans.Id select new { att.Id, att.URI } + } + }; + return result; + } + catch (Exception ex) + { + logger?.LogError($"Exception Found : {ex.Message} - Ref: SurveyResponsesProvider.getSurveyResponseBySurveyIdAsync()"); + return null; + } + } + + + //Method to get Survey Responses by surveyId questionId and answer + private async Task getSurveyResponsesByAnswerAsync(Survey survey, Question question, string answer) + { + try + { + var surveyResponses = await surveyResponseDbContext.SurveyResponses.Where(x => x.SurveyId == survey.Id).ToListAsync(); + //var questions = await questionServiceProvider.getQuestionsAsync(); + + var answers = await answerServiceProvider.getAnswersAsync(); + var employees = await employeeServiceProvider.getEmployeesAsync(); + var attachments = await attachmentServiceProvider.getAttachmentsAsync(); + + var result = from r in surveyResponses + select new + { + r.Id, + r.SurveyId, + r.LocationId, + r.EmployeeId, + Employee = (from e in employees where r.EmployeeId == e.Id select new { e.Id, e.Name, e.BirthDate, e.Email, e.OfficePhoneNumber }).SingleOrDefault(), + answers = from ans in answers + where ans.SurveyResponseId == r.Id + && ans.QuestionId == question.Id + && ans.AnswerText.ToLower().Equals(answer.ToLower()) + + select new + { + ans.QuestionId, + AnswerId = ans.Id, + ans.AnswerText, + ans.Comment, + Question = question, + Attachments = from att in attachments where att.AnswerId == ans.Id select new { att.Id, att.URI } + } + }; + return result; + } + catch (Exception ex) + { + logger?.LogError($"Exception Found : {ex.Message} - Ref: SurveyResponsesProvider.getSurveyResponseBySurveyIdAsync()"); + return null; + } + } + + + async Task ProcessAnswers(QuestionRequest questionRequest, int surveyResponseId) + { + if (questionRequest != null) + { + var answer = await answerServiceProvider.PostAnswersAsync(new Answer { Id = 0, QuestionId = questionRequest.QuestionId, AnswerText = questionRequest.AnswerText, Comment = questionRequest.Comment, SurveyResponseId = surveyResponseId }); + if (answer != null) + { + List listAnswerInfo = new List(); + listAnswerInfo.Add(new AnswerInfo { AnswerId = answer.Id, postedFiles = questionRequest.PostedFiles }); + var attachments = await attachmentServiceProvider.PostAttachmentsAsync(new AttachmentInfo { ResponseId = surveyResponseId, Answers = listAnswerInfo }); + + string message = $"Answer for question {questionRequest.QuestionId} saved to the database"; + logger?.LogInformation(message); + return (true); + } + else + { + string message = $"Answer for question {questionRequest.QuestionId} cannot be saved to the database"; + logger?.LogInformation(message); + return (false); + } + } + else + { + var message = $"Answer for question {questionRequest.QuestionId} cannot be saved to the database - questionRequest object is null"; + logger?.LogInformation(message); + return (false); + } + } + + + public async Task<(bool IsSuccess, Models.SurveyResponse SurveyResponse, string ErrorMessage)> PostSurveyAnswersAsync(Models.AnswerRequest answers) + { + try + { + if (answers != null) + { + var response = await PostSurveyResponseAsync(new Models.SurveyResponse { Id = 0, SurveyId = answers.SurveyId, EmployeeId = answers.EmployeeId, LocationId = answers.LocationId }); + + if (response.IsSuccess) + { + var surveyResponse = response.SurveyResponse; + + var answerTasks = new List(); //new List(); + + //var tasks = answers.Answers.Select(x => ProcessAnswers(x,surveyResponse.SurveyResponseID)); + foreach (QuestionRequest ans in answers.Answers) + { + //var stopwatch = new Stopwatch(); + //stopwatch.Start(); + var task = Task.Run(() => ProcessAnswers(ans, surveyResponse.Id)); + + //var task = await ProcessAnswers(ans, surveyResponse.Id); + answerTasks.Add(task); + + + //stopwatch.Stop(); + //answerTasks.Add(ProcessAnswers(ans, surveyResponse.Id)); + } + await Task.WhenAll(answerTasks); + return (true, surveyResponse, null); + } + else + { + var message = "Survey answers cannot be saved to the database"; + logger?.LogInformation(message); + return (false, null, message); + } + } + else + { + var message = "Request failed because null object is submitted"; + logger?.LogInformation(message); + return (false, null, message); + } + } + catch (Exception ex) + { + logger?.LogError(ex.ToString()); + return (false, null, ex.Message); + } + } + } +} diff --git a/DamageAssesmentApi/DamageAssesment.Api.SurveyResponses/Providers/SurveyServiceProvider.cs b/DamageAssesmentApi/DamageAssesment.Api.SurveyResponses/Providers/SurveyServiceProvider.cs new file mode 100644 index 0000000..06b1eed --- /dev/null +++ b/DamageAssesmentApi/DamageAssesment.Api.SurveyResponses/Providers/SurveyServiceProvider.cs @@ -0,0 +1,59 @@ +using DamageAssesment.Api.SurveyResponses.Bases; +using DamageAssesment.Api.SurveyResponses.Interfaces; +using DamageAssesment.Api.SurveyResponses.Models; +using Newtonsoft.Json; +using System.Reflection; + +namespace DamageAssesment.Api.SurveyResponses.Providers +{ + public class SurveyServiceProvider :ServiceProviderBase, ISurveyServiceProvider + { + public SurveyServiceProvider(IConfiguration configuration, HttpClient httpClient, ILogger logger) : base(configuration, httpClient, logger, "/api/Surveys", configuration.GetValue("EndPointSettings:SurveyUrlBase")) + { + } + + public async Task> getSurveysAsync() + { + try + { + httpClient.BaseAddress = new Uri(urlBase); + var response = await httpClient.GetAsync(ressource); + response.EnsureSuccessStatusCode(); + var responseString = await response.Content.ReadAsStringAsync(); + var surveys = JsonConvert.DeserializeObject>(responseString); + + if (surveys == null || !surveys.Any()) + return null; + else return surveys; + } + catch (Exception ex) + { + logger?.LogError($"Exception Found : {ex.Message} - Ref: SurveyServiceProvider.getSurveysAsync()"); + return null; + } + } + + public async Task getSurveyAsync(int surveyId) + { + try + { + httpClient.BaseAddress = new Uri(urlBase); + var response = await httpClient.GetAsync(ressource+"/"+ surveyId); + response.EnsureSuccessStatusCode(); + var responseString = await response.Content.ReadAsStringAsync(); + var survey = JsonConvert.DeserializeObject(responseString); + + if (survey == null ) + return null; + else return survey; + } + catch (Exception ex) + { + logger?.LogError($"Exception Found : {ex.Message} - Ref: SurveyServiceProvider.getSurveyAsync()"); + return null; + } + } + + + } +} diff --git a/DamageAssesmentApi/DamageAssesment.Api.SurveyResponses/appsettings.Development.json b/DamageAssesmentApi/DamageAssesment.Api.SurveyResponses/appsettings.Development.json new file mode 100644 index 0000000..0c208ae --- /dev/null +++ b/DamageAssesmentApi/DamageAssesment.Api.SurveyResponses/appsettings.Development.json @@ -0,0 +1,8 @@ +{ + "Logging": { + "LogLevel": { + "Default": "Information", + "Microsoft.AspNetCore": "Warning" + } + } +} diff --git a/DamageAssesmentApi/DamageAssesment.Api.SurveyResponses/appsettings.json b/DamageAssesmentApi/DamageAssesment.Api.SurveyResponses/appsettings.json new file mode 100644 index 0000000..2d6dfe4 --- /dev/null +++ b/DamageAssesmentApi/DamageAssesment.Api.SurveyResponses/appsettings.json @@ -0,0 +1,19 @@ +{ + "Logging": { + "LogLevel": { + "Default": "Information", + "Microsoft.AspNetCore": "Warning" + } + }, + "AllowedHosts": "*", + "EndPointSettings": { + "AnswerUrlBase": "http://localhost:5200", + "LocationUrlBase": "http://localhost:5213", + "RegionUrlBase": "http://localhost:5211", + "QuestionUrlBase": "http://localhost:5133", + "EmployeeUrlBase": "http://localhost:5135", + "AttachmentUrlBase": "http://localhost:5243", + "SurveyUrlBase": "http://localhost:5009" + + } +} diff --git a/DamageAssesmentApi/DamageAssesment.Api.Surveys.Test/DamageAssesment.Api.Survey.Test.csproj b/DamageAssesmentApi/DamageAssesment.Api.Surveys.Test/DamageAssesment.Api.Survey.Test.csproj new file mode 100644 index 0000000..c4ecd6b --- /dev/null +++ b/DamageAssesmentApi/DamageAssesment.Api.Surveys.Test/DamageAssesment.Api.Survey.Test.csproj @@ -0,0 +1,30 @@ + + + + net6.0 + enable + enable + + false + true + + + + + + + + runtime; build; native; contentfiles; analyzers; buildtransitive + all + + + runtime; build; native; contentfiles; analyzers; buildtransitive + all + + + + + + + + diff --git a/DamageAssesmentApi/DamageAssesment.Api.Surveys.Test/MockData.cs b/DamageAssesmentApi/DamageAssesment.Api.Surveys.Test/MockData.cs new file mode 100644 index 0000000..6936c04 --- /dev/null +++ b/DamageAssesmentApi/DamageAssesment.Api.Surveys.Test/MockData.cs @@ -0,0 +1,53 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Xunit.Sdk; + +namespace DamageAssesment.Api.Survey.Test +{ + public class MockData + { + public static async Task<(bool, IEnumerable, string)> getOkResponse() + { + IEnumerable list = new List(); + + for (int i = 0; i < 10; i++) + { + list.Append(new Surveys.Models.Survey { Id = i, Title = "Survey Title - " + i }); + } + return (true, list, null); + } + + + public static async Task<(bool, Surveys.Models.Survey, string)> getOkResponse( int Id) + { + var surveys = await getOkResponse(); + var survey = surveys.Item2.FirstOrDefault(s => s.Id == Id); + return (true, survey, null); + } + + public static async Task<(bool, Surveys.Models.Survey, string)> getBadRequestResponse() + { + return (false, null,"Bad Request"); + } + + public static async Task<(bool, Surveys.Models.Survey, string)> getNotFoundResponse() + { + return (false, null, "Not Found"); + } + public static async Task<(bool, IEnumerable, string)> getNoContentResponse() + { + IEnumerable list = new List(); + return (false, list, null); + } + + public static async Task getInputSurveyData() + { + return new Surveys.Models.Survey { Id = 100, Title = "Mock survey", IsEnabled= true, StartDate = DateTime.Now, EndDate = DateTime.Now.AddDays(90) }; + + } + + } +} diff --git a/DamageAssesmentApi/DamageAssesment.Api.Surveys.Test/SurveyServiceTest.cs b/DamageAssesmentApi/DamageAssesment.Api.Surveys.Test/SurveyServiceTest.cs new file mode 100644 index 0000000..1aaf4a6 --- /dev/null +++ b/DamageAssesmentApi/DamageAssesment.Api.Surveys.Test/SurveyServiceTest.cs @@ -0,0 +1,161 @@ +using DamageAssesment.Api.Survey.Test; +using DamageAssesment.Api.Surveys.Controllers; +using DamageAssesment.Api.Surveys.Interfaces; +using Microsoft.AspNetCore.Mvc; +using Moq; +using Xunit; + +namespace DamageAssesment.Api.Surveys.Test +{ + public class SurveyServiceTest + { + [Fact(DisplayName = "Get Surveys - Ok case")] + public async Task GetSurveysAsync_ShouldReturnStatusCode200() + { + var mockSurveyService = new Mock(); + var mockResponse = await MockData.getOkResponse(); + mockSurveyService.Setup(service => service.GetSurveysAsync()).ReturnsAsync(mockResponse); + + var surveyProvider = new SurveysController(mockSurveyService.Object); + var result = (OkObjectResult) await surveyProvider.GetSurveysAsync(); + + Assert.Equal(200, result.StatusCode); + } + + [Fact(DisplayName = "Get Surveys - NoContent Case")] + public async Task GetSurveysAsync_ShouldReturnStatusCode204() + { + var mockSurveyService = new Mock(); + var mockResponse = await MockData.getNoContentResponse(); + mockSurveyService.Setup(service => service.GetSurveysAsync()).ReturnsAsync(mockResponse); + + var surveyProvider = new SurveysController(mockSurveyService.Object); + var result = (NoContentResult)await surveyProvider.GetSurveysAsync(); + + Assert.Equal(204, result.StatusCode); + } + + [Fact(DisplayName = "Get Survey by Id - Ok case")] + public async Task GetSurveyAsync_ShouldReturnStatusCode200() + { + var mockSurveyService = new Mock(); + var mockResponse = await MockData.getOkResponse(1); + mockSurveyService.Setup(service => service.GetSurveysAsync(1)).ReturnsAsync(mockResponse); + + var surveyProvider = new SurveysController(mockSurveyService.Object); + var result = (OkObjectResult)await surveyProvider.GetSurveysAsync(1); + + Assert.Equal(200, result.StatusCode); + } + + [Fact(DisplayName = "Get Survey by Id - NotFound case")] + public async Task GetSurveyAsync_ShouldReturnStatusCode404() + { + var mockSurveyService = new Mock(); + var mockResponse = await MockData.getNotFoundResponse(); + mockSurveyService.Setup(service => service.GetSurveysAsync(99)).ReturnsAsync(mockResponse); + + var surveyProvider = new SurveysController(mockSurveyService.Object); + var result = (NotFoundResult)await surveyProvider.GetSurveysAsync(99); + Assert.Equal(404, result.StatusCode); + } + + [Fact(DisplayName = "Post Survey - Ok case")] + public async Task PostSurveyAsync_ShouldReturnStatusCode200() + { + var mockSurveyService = new Mock(); + var mockResponse = await MockData.getOkResponse(1); + var mockInputSurvey = await MockData.getInputSurveyData(); + mockSurveyService.Setup(service => service.PostSurveyAsync(mockInputSurvey)).ReturnsAsync(mockResponse); + + var surveyProvider = new SurveysController(mockSurveyService.Object); + var result = (OkObjectResult)await surveyProvider.PostSurveysAsync(mockInputSurvey); + + Assert.Equal(200, result.StatusCode); + } + + [Fact(DisplayName = "Post Survey - BadRequest case")] + public async Task PostSurveyAsync_ShouldReturnStatusCode400() + { + var mockSurveyService = new Mock(); + var mockInputSurvey = await MockData.getInputSurveyData(); + var mockResponse = await MockData.getBadRequestResponse(); + mockSurveyService.Setup(service => service.PostSurveyAsync(mockInputSurvey)).ReturnsAsync(mockResponse); + + var surveyProvider = new SurveysController(mockSurveyService.Object); + var result = (BadRequestObjectResult)await surveyProvider.PostSurveysAsync(mockInputSurvey); + + Assert.Equal(400, result.StatusCode); + } + + [Fact(DisplayName = "Put Survey - Ok case")] + public async Task PutSurveyAsync_ShouldReturnStatusCode200() + { + var mockSurveyService = new Mock(); + var mockResponse = await MockData.getOkResponse(1); + var mockInputSurvey = await MockData.getInputSurveyData(); + mockSurveyService.Setup(service => service.PutSurveyAsync(1,mockInputSurvey)).ReturnsAsync(mockResponse); + + var surveyProvider = new SurveysController(mockSurveyService.Object); + var result = (OkObjectResult)await surveyProvider.PutSurveysAsync(1,mockInputSurvey); + + Assert.Equal(200, result.StatusCode); + } + + [Fact(DisplayName = "Put Survey - NotFound case")] + public async Task PutSurveyAsync_ShouldReturnStatusCode404() + { + var mockSurveyService = new Mock(); + var mockResponse = await MockData.getNotFoundResponse(); + var mockInputSurvey = await MockData.getInputSurveyData(); + mockSurveyService.Setup(service => service.PutSurveyAsync(1,mockInputSurvey)).ReturnsAsync(mockResponse); + + var surveyProvider = new SurveysController(mockSurveyService.Object); + var result = (NotFoundObjectResult)await surveyProvider.PutSurveysAsync(1,mockInputSurvey); + + Assert.Equal(404, result.StatusCode); + } + + [Fact(DisplayName = "Put Survey - BadRequest case")] + public async Task PutSurveyAsync_ShouldReturnStatusCode400() + { + var mockSurveyService = new Mock(); + var mockResponse = await MockData.getBadRequestResponse(); + var mockInputSurvey = await MockData.getInputSurveyData(); + mockSurveyService.Setup(service => service.PutSurveyAsync(1,mockInputSurvey)).ReturnsAsync(mockResponse); + + var surveyProvider = new SurveysController(mockSurveyService.Object); + var result = (BadRequestObjectResult)await surveyProvider.PutSurveysAsync(1,mockInputSurvey); + + Assert.Equal(400, result.StatusCode); + } + + [Fact(DisplayName = "Delete Survey - Ok case")] + public async Task DeleteSurveyAsync_ShouldReturnStatusCode200() + { + var mockSurveyService = new Mock(); + var mockResponse = await MockData.getOkResponse(1); + + mockSurveyService.Setup(service => service.DeleteSurveyAsync(1)).ReturnsAsync(mockResponse); + + var surveyProvider = new SurveysController(mockSurveyService.Object); + var result = (OkObjectResult)await surveyProvider.DeleteSurveysAsync(1); + + Assert.Equal(200, result.StatusCode); + } + + [Fact(DisplayName = "Delete Survey - NotFound case")] + public async Task DeleteSurveyAsync_ShouldReturnStatusCode404() + { + var mockSurveyService = new Mock(); + var mockResponse = await MockData.getNotFoundResponse(); + mockSurveyService.Setup(service => service.DeleteSurveyAsync(1)).ReturnsAsync(mockResponse); + + var surveyProvider = new SurveysController(mockSurveyService.Object); + var result = (NotFoundResult)await surveyProvider.DeleteSurveysAsync(1); + + Assert.Equal(404, result.StatusCode); + } + + } +} \ No newline at end of file diff --git a/DamageAssesmentApi/DamageAssesment.Api.Surveys/Controllers/SurveysController.cs b/DamageAssesmentApi/DamageAssesment.Api.Surveys/Controllers/SurveysController.cs new file mode 100644 index 0000000..56f2e29 --- /dev/null +++ b/DamageAssesmentApi/DamageAssesment.Api.Surveys/Controllers/SurveysController.cs @@ -0,0 +1,75 @@ +using DamageAssesment.Api.Surveys.Interfaces; +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Mvc; + +namespace DamageAssesment.Api.Surveys.Controllers +{ + [Route("api/[controller]")] + [ApiController] + public class SurveysController : ControllerBase + { + private ISurveyProvider surveyProvider; + + public SurveysController(ISurveyProvider surveyProvider) + { + this.surveyProvider = surveyProvider; + } + + [HttpGet] + public async Task GetSurveysAsync() + { + var result = await this.surveyProvider.GetSurveysAsync(); + if (result.IsSuccess) + { + return Ok(result.Surveys); + } + return NoContent(); + } + [HttpGet("{Id}")] + public async Task GetSurveysAsync(int Id) + { + var result = await this.surveyProvider.GetSurveysAsync(Id); + if (result.IsSuccess) + { + return Ok(result.Surveys); + } + return NotFound(); + } + + [HttpPost] + public async Task PostSurveysAsync(Models.Survey survey) + { + var result = await this.surveyProvider.PostSurveyAsync(survey); + if (result.IsSuccess) + { + return Ok(result.Survey); + } + return BadRequest(result.ErrorMessage); + } + + [HttpPut("{Id}")] + public async Task PutSurveysAsync(int Id, Models.Survey survey) + { + var result = await this.surveyProvider.PutSurveyAsync(Id,survey); + if (result.IsSuccess) + { + return Ok(result.Survey); + } + if (result.ErrorMessage == "Not Found") + return NotFound(result.ErrorMessage); + + return BadRequest(result.ErrorMessage); + } + + [HttpDelete("{Id}")] + public async Task DeleteSurveysAsync(int Id) + { + var result = await this.surveyProvider.DeleteSurveyAsync(Id); + if (result.IsSuccess) + { + return Ok(result.Survey); + } + return NotFound(); + } + } +} diff --git a/DamageAssesmentApi/DamageAssesment.Api.Surveys/DamageAssesment.Api.Survey.csproj b/DamageAssesmentApi/DamageAssesment.Api.Surveys/DamageAssesment.Api.Survey.csproj new file mode 100644 index 0000000..53e8700 --- /dev/null +++ b/DamageAssesmentApi/DamageAssesment.Api.Surveys/DamageAssesment.Api.Survey.csproj @@ -0,0 +1,16 @@ + + + + net6.0 + enable + enable + + + + + + + + + + diff --git a/DamageAssesmentApi/DamageAssesment.Api.Surveys/Db/Survey.cs b/DamageAssesmentApi/DamageAssesment.Api.Surveys/Db/Survey.cs new file mode 100644 index 0000000..bff0339 --- /dev/null +++ b/DamageAssesmentApi/DamageAssesment.Api.Surveys/Db/Survey.cs @@ -0,0 +1,28 @@ +using System.ComponentModel.DataAnnotations; + +namespace DamageAssesment.Api.Surveys.Db +{ + public class Survey + { + [Key] + public int Id { get; set; } + + [StringLength(100)] + [Required] + public string Title { get; set; } + + //[StringLength(1000)] + //public string Description { get; set; } + + public bool IsEnabled { get; set; } + + public DateTime? StartDate { get; set; } + + public DateTime? EndDate { get; set; } + + //public DateTime CreatedDate { get; set; } + + //[StringLength(6)] + //public string EmployeeID { get; set; } + } +} diff --git a/DamageAssesmentApi/DamageAssesment.Api.Surveys/Db/SurveysDbContext.cs b/DamageAssesmentApi/DamageAssesment.Api.Surveys/Db/SurveysDbContext.cs new file mode 100644 index 0000000..9ff36cf --- /dev/null +++ b/DamageAssesmentApi/DamageAssesment.Api.Surveys/Db/SurveysDbContext.cs @@ -0,0 +1,14 @@ +using Microsoft.EntityFrameworkCore; + +namespace DamageAssesment.Api.Surveys.Db +{ + public class SurveysDbContext:DbContext + { + public SurveysDbContext(DbContextOptions options) : base(options) + { + + } + public DbSet Surveys { get; set; } + + } +} diff --git a/DamageAssesmentApi/DamageAssesment.Api.Surveys/Interfaces/ISurveyProvider.cs b/DamageAssesmentApi/DamageAssesment.Api.Surveys/Interfaces/ISurveyProvider.cs new file mode 100644 index 0000000..42c488e --- /dev/null +++ b/DamageAssesmentApi/DamageAssesment.Api.Surveys/Interfaces/ISurveyProvider.cs @@ -0,0 +1,12 @@ +namespace DamageAssesment.Api.Surveys.Interfaces +{ + public interface ISurveyProvider + { + Task<(bool IsSuccess, IEnumerable< Models.Survey> Surveys, string ErrorMessage)> GetSurveysAsync(); + Task<(bool IsSuccess, Models.Survey Surveys, string ErrorMessage)> GetSurveysAsync(int Id); + Task<(bool IsSuccess, Models.Survey Survey, string ErrorMessage)> PostSurveyAsync(Models.Survey Survey); + Task<(bool IsSuccess, Models.Survey Survey, string ErrorMessage)> PutSurveyAsync(int Id,Models.Survey Survey); + Task<(bool IsSuccess, Models.Survey Survey, string ErrorMessage)> DeleteSurveyAsync(int Id); + + } +} diff --git a/DamageAssesmentApi/DamageAssesment.Api.Surveys/Models/Survey.cs b/DamageAssesmentApi/DamageAssesment.Api.Surveys/Models/Survey.cs new file mode 100644 index 0000000..cd5691b --- /dev/null +++ b/DamageAssesmentApi/DamageAssesment.Api.Surveys/Models/Survey.cs @@ -0,0 +1,28 @@ +using System.ComponentModel.DataAnnotations; + +namespace DamageAssesment.Api.Surveys.Models +{ + public class Survey + { + [Key] + public int Id { get; set; } + + [StringLength(100)] + public string Title { get; set; } + + //[StringLength(1000)] + // public string? Description { get; set; } + + public bool IsEnabled { get; set; } + + public DateTime? StartDate { get; set; } + + public DateTime? EndDate { get; set; } + + //public DateTime CreatedDate { get; set; } + + //[StringLength(6)] + //public string EmployeeID { get; set; } + + } +} diff --git a/DamageAssesmentApi/DamageAssesment.Api.Surveys/Profiles/SurveysProfile.cs b/DamageAssesmentApi/DamageAssesment.Api.Surveys/Profiles/SurveysProfile.cs new file mode 100644 index 0000000..2cb043c --- /dev/null +++ b/DamageAssesmentApi/DamageAssesment.Api.Surveys/Profiles/SurveysProfile.cs @@ -0,0 +1,10 @@ +namespace DamageAssesment.Api.Surveys.Profiles +{ + public class SurveysProfile:AutoMapper.Profile + { + public SurveysProfile() { + CreateMap(); + CreateMap(); + } + } +} diff --git a/DamageAssesmentApi/DamageAssesment.Api.Surveys/Program.cs b/DamageAssesmentApi/DamageAssesment.Api.Surveys/Program.cs new file mode 100644 index 0000000..ebb638f --- /dev/null +++ b/DamageAssesmentApi/DamageAssesment.Api.Surveys/Program.cs @@ -0,0 +1,33 @@ +using DamageAssesment.Api.Surveys.Db; +using DamageAssesment.Api.Surveys.Interfaces; +using DamageAssesment.Api.Surveys.Providers; +using Microsoft.EntityFrameworkCore; + +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.AddScoped(); +builder.Services.AddAutoMapper(AppDomain.CurrentDomain.GetAssemblies()); +builder.Services.AddEndpointsApiExplorer(); +builder.Services.AddSwaggerGen(); +builder.Services.AddDbContext(option => +{ + option.UseInMemoryDatabase("Surveys"); +}); +var app = builder.Build(); + +// Configure the HTTP request pipeline. +if (app.Environment.IsDevelopment()) +{ + app.UseSwagger(); + app.UseSwaggerUI(); +} + +app.UseAuthorization(); + +app.MapControllers(); + +app.Run(); diff --git a/DamageAssesmentApi/DamageAssesment.Api.Surveys/Properties/launchSettings.json b/DamageAssesmentApi/DamageAssesment.Api.Surveys/Properties/launchSettings.json new file mode 100644 index 0000000..247b548 --- /dev/null +++ b/DamageAssesmentApi/DamageAssesment.Api.Surveys/Properties/launchSettings.json @@ -0,0 +1,31 @@ +{ + "$schema": "https://json.schemastore.org/launchsettings.json", + "iisSettings": { + "windowsAuthentication": false, + "anonymousAuthentication": true, + "iisExpress": { + "applicationUrl": "http://localhost:51498", + "sslPort": 0 + } + }, + "profiles": { + "DamageAssesment.Api.Surveys": { + "commandName": "Project", + "dotnetRunMessages": true, + "launchBrowser": true, + "launchUrl": "swagger", + "applicationUrl": "http://localhost:5009", + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development" + } + }, + "IIS Express": { + "commandName": "IISExpress", + "launchBrowser": true, + "launchUrl": "swagger", + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development" + } + } + } +} diff --git a/DamageAssesmentApi/DamageAssesment.Api.Surveys/Providers/SurveysProvider.cs b/DamageAssesmentApi/DamageAssesment.Api.Surveys/Providers/SurveysProvider.cs new file mode 100644 index 0000000..c85ed4c --- /dev/null +++ b/DamageAssesmentApi/DamageAssesment.Api.Surveys/Providers/SurveysProvider.cs @@ -0,0 +1,160 @@ +using AutoMapper; +using DamageAssesment.Api.Surveys.Db; +using DamageAssesment.Api.Surveys.Interfaces; +using Microsoft.EntityFrameworkCore; + +namespace DamageAssesment.Api.Surveys.Providers +{ + public class SurveysProvider : ISurveyProvider + { + private readonly SurveysDbContext surveyDbContext; + private readonly ILogger logger; + private readonly IMapper mapper; + + public SurveysProvider(SurveysDbContext surveysDbContext, ILogger logger, IMapper mapper) + { + this.surveyDbContext = surveysDbContext; + this.logger = logger; + this.mapper = mapper; + seedData(); + } + + private void seedData() + { + if (!surveyDbContext.Surveys.Any()) + { + surveyDbContext.Surveys.Add(new Db.Survey { Id = 1, Title = "Sample Survey Title:Damage Assesment 2014", IsEnabled = true, StartDate = DateTime.Now, EndDate = DateTime.Now.AddDays(90) }); + surveyDbContext.Surveys.Add(new Db.Survey { Id = 2, Title = "Sample Survey Title: Damage Assesment 2016", IsEnabled = true, StartDate = DateTime.Now, EndDate = DateTime.Now.AddDays(90) }); + surveyDbContext.Surveys.Add(new Db.Survey { Id = 3, Title = "Sample Survey Title: Damage Assesment 2018", IsEnabled = true, StartDate = DateTime.Now, EndDate = DateTime.Now.AddDays(90) }); + surveyDbContext.SaveChanges(); + } + } + + public async Task<(bool IsSuccess, IEnumerable Surveys, string ErrorMessage)> GetSurveysAsync() + { + try + { + logger?.LogInformation("Gell all Surveys from DB"); + var surveys = await surveyDbContext.Surveys.ToListAsync(); + if (surveys != null) + { + logger?.LogInformation($"{surveys.Count} Items(s) found"); + var result = mapper.Map, IEnumerable>(surveys); + 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.Survey Surveys, string ErrorMessage)> GetSurveysAsync(int Id) + { + try + { + logger?.LogInformation("Query Survey"); + var survey = await surveyDbContext.Surveys.SingleOrDefaultAsync(s => s.Id == Id); + if (survey != null) + { + logger?.LogInformation($"Survey Id: {Id} found"); + var result = mapper.Map(survey); + 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.Survey Survey, string ErrorMessage)> PostSurveyAsync(Models.Survey survey) + { + try + { + if (survey != null) + { + var surveys = await surveyDbContext.Surveys.ToListAsync(); + survey.Id = surveys.Count + 1; + surveyDbContext.Surveys.Add(mapper.Map(survey)); + surveyDbContext.SaveChanges(); + return (true, survey, "Successful"); + } + else + { + logger?.LogInformation($"Survey Id: {survey.Id} cannot be added"); + return (false, null, $"Survey Id: {survey.Id} cannot be added"); + } + } + catch (Exception ex) + { + logger?.LogError(ex.ToString()); + return (false, null, ex.Message); + } + } + + public async Task<(bool IsSuccess, Models.Survey Survey, string ErrorMessage)> PutSurveyAsync(int Id, Models.Survey survey) + { + try + { + if (survey != null) + { + var _survey = await surveyDbContext.Surveys.Where(s => s.Id == Id).SingleOrDefaultAsync(); + + if (_survey != null) + { + _survey.Title = survey.Title; + _survey.IsEnabled = survey.IsEnabled; + _survey.StartDate = survey.StartDate; + _survey.EndDate = survey.EndDate; + surveyDbContext.SaveChanges(); + return (true, mapper.Map(_survey), "Successful"); + } + else + { + logger?.LogInformation($"Survey Id : {Id} Not found"); + return (false, null, "Not Found"); + } + } + else + { + logger?.LogInformation($"Survey Id: {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.Survey Survey, string ErrorMessage)> DeleteSurveyAsync(int Id) + { + try + { + var survey = await surveyDbContext.Surveys.Where(x => x.Id == Id).SingleOrDefaultAsync(); + + if (survey != null) + { + surveyDbContext.Surveys.Remove(survey); + surveyDbContext.SaveChanges(); + return (true, mapper.Map(survey), $"Survey Id: {Id} deleted Successfuly"); + } + else + { + logger?.LogInformation($"Survey Id : {Id} Not found"); + return (false, null, "Not Found"); + } + } + catch (Exception ex) + { + logger?.LogError(ex.ToString()); + return (false, null, ex.Message); + } + } + } +} diff --git a/DamageAssesmentApi/DamageAssesment.Api.Surveys/appsettings.Development.json b/DamageAssesmentApi/DamageAssesment.Api.Surveys/appsettings.Development.json new file mode 100644 index 0000000..0c208ae --- /dev/null +++ b/DamageAssesmentApi/DamageAssesment.Api.Surveys/appsettings.Development.json @@ -0,0 +1,8 @@ +{ + "Logging": { + "LogLevel": { + "Default": "Information", + "Microsoft.AspNetCore": "Warning" + } + } +} diff --git a/DamageAssesmentApi/DamageAssesment.Api.Surveys/appsettings.json b/DamageAssesmentApi/DamageAssesment.Api.Surveys/appsettings.json new file mode 100644 index 0000000..10f68b8 --- /dev/null +++ b/DamageAssesmentApi/DamageAssesment.Api.Surveys/appsettings.json @@ -0,0 +1,9 @@ +{ + "Logging": { + "LogLevel": { + "Default": "Information", + "Microsoft.AspNetCore": "Warning" + } + }, + "AllowedHosts": "*" +} diff --git a/DamageAssesmentApi/DamageAssesment.SurveyResponses.Test/DamageAssesment.Api.SurveyResponses.Test.csproj b/DamageAssesmentApi/DamageAssesment.SurveyResponses.Test/DamageAssesment.Api.SurveyResponses.Test.csproj new file mode 100644 index 0000000..a384a67 --- /dev/null +++ b/DamageAssesmentApi/DamageAssesment.SurveyResponses.Test/DamageAssesment.Api.SurveyResponses.Test.csproj @@ -0,0 +1,30 @@ + + + + net6.0 + enable + enable + + false + true + + + + + + + + runtime; build; native; contentfiles; analyzers; buildtransitive + all + + + runtime; build; native; contentfiles; analyzers; buildtransitive + all + + + + + + + + diff --git a/DamageAssesmentApi/DamageAssesment.SurveyResponses.Test/MockData.cs b/DamageAssesmentApi/DamageAssesment.SurveyResponses.Test/MockData.cs new file mode 100644 index 0000000..d70772d --- /dev/null +++ b/DamageAssesmentApi/DamageAssesment.SurveyResponses.Test/MockData.cs @@ -0,0 +1,30 @@ + +using DamageAssesment.Api.SurveyResponses.Models; +using System.Collections.Generic; +using System.Text; + +namespace DamageAssesment.Api.SurveyResponses.Test +{ + public class MockData + { + public static async Task<(bool, SurveyResponse, string)> getOkResponse(SurveyResponse data) + { + return (true, data, null); + } + + public static async Task<(bool, dynamic, string)> getOkResponse() + { + return (true, new { }, null); + } + + public static async Task<(bool, Models.SurveyResponse, string)> getResponse() + { + return (false, null, null); + } + + public static async Task getSurveyResponseObject() + { + return new Models.SurveyResponse { EmployeeId = "Emp1", LocationId = "Loc1", SurveyId = 1, Id = 1 }; + } + } +} diff --git a/DamageAssesmentApi/DamageAssesment.SurveyResponses.Test/SurveyResponsesServiceTest.cs b/DamageAssesmentApi/DamageAssesment.SurveyResponses.Test/SurveyResponsesServiceTest.cs new file mode 100644 index 0000000..182ec5c --- /dev/null +++ b/DamageAssesmentApi/DamageAssesment.SurveyResponses.Test/SurveyResponsesServiceTest.cs @@ -0,0 +1,238 @@ +using DamageAssesment.Api.SurveyResponses.Controllers; +using DamageAssesment.Api.SurveyResponses.Interfaces; +using DamageAssesment.Api.SurveyResponses.Models; +using DamageAssesment.Api.SurveyResponses.Test; +using Microsoft.AspNetCore.Mvc; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Moq; +using Xunit; +using Xunit.Sdk; + +namespace DamageAssesment.SurveyResponses.Test +{ + public class SurveyResponsesServiceTest + { + Mock mockSurveyResponseService; + public SurveyResponsesServiceTest() + { + mockSurveyResponseService = new Mock(); + } + + [Fact(DisplayName = "Get SurveyResponses - Ok case")] + public async Task GetSurveyResponsesAsync_ShouldReturnStatusCode200() + { + SurveyResponse mockRequestObject = await MockData.getSurveyResponseObject(); + var mockResponse = await MockData.getOkResponse(mockRequestObject); + mockSurveyResponseService.Setup(service => service.GetSurveyResponsesAsync()).ReturnsAsync(mockResponse); + var surveyResponseProvider = new SurveyResponsesController(mockSurveyResponseService.Object); + var result = (OkObjectResult)await surveyResponseProvider.GetSurveyResponsesAsync(); + Assert.Equal(200, result.StatusCode); + } + + [Fact(DisplayName = "Get SurveyResponses - BadRequest case")] + public async Task GetSurveyResponsesAsync_ShouldReturnStatusCode204() + { + var mockResponse = await MockData.getResponse(); + mockSurveyResponseService.Setup(service => service.GetSurveyResponsesAsync()).ReturnsAsync(mockResponse); + var surveyResponseProvider = new SurveyResponsesController(mockSurveyResponseService.Object); + var result = (BadRequestObjectResult)await surveyResponseProvider.GetSurveyResponsesAsync(); + Assert.Equal(400, result.StatusCode); + } + + [Fact(DisplayName = "Get SurveyResponses by surveyId - Ok case")] + public async Task GetSurveyResponsesBySurveyAsync_ShouldReturnStatusCode200() + { + SurveyResponse mockRequestObject = await MockData.getSurveyResponseObject(); + var mockResponse = await MockData.getOkResponse(); + mockSurveyResponseService.Setup(service => service.GetSurveyResponsesBySurveyAsync(1)).ReturnsAsync(mockResponse); + var surveyResponseProvider = new SurveyResponsesController(mockSurveyResponseService.Object); + var result = (OkObjectResult)await surveyResponseProvider.GetSurveyResponsesAsync(1); + Assert.Equal(200, result.StatusCode); + } + + [Fact(DisplayName = "Get SurveyResponses by surveyId - NoContent case")] + public async Task GetSurveyResponsesBySurveyAsync_ShouldReturnStatusCode204() + { + var mockResponse = await MockData.getResponse(); + mockSurveyResponseService.Setup(service => service.GetSurveyResponsesBySurveyAsync(1)).ReturnsAsync(mockResponse); + var surveyResponseProvider = new SurveyResponsesController(mockSurveyResponseService.Object); + var result = (NoContentResult)await surveyResponseProvider.GetSurveyResponsesAsync(1); + Assert.Equal(204, result.StatusCode); + } + + + + + [Fact(DisplayName = "Get SurveyResponses by surveyId and locationId - Ok case")] + public async Task GetSurveyResponsesBySurveyLocationAsync_ShouldReturnStatusCode200() + { + SurveyResponse mockRequestObject = await MockData.getSurveyResponseObject(); + var mockResponse = await MockData.getOkResponse(); + mockSurveyResponseService.Setup(service => service.GetSurveyResponsesBySurveyAndLocationAsync(1, "Loc1")).ReturnsAsync(mockResponse); + var surveyResponseProvider = new SurveyResponsesController(mockSurveyResponseService.Object); + var result = (OkObjectResult)await surveyResponseProvider.GetSurveyResponsesBySurveyAndLocationAsync(1, "Loc1"); + Assert.Equal(200, result.StatusCode); + } + + [Fact(DisplayName = "Get SurveyResponses by surveyId and locationId - NoContent case")] + public async Task GetSurveyResponsesBySurveyLocationAsync_ShouldReturnStatusCode204() + { + var mockResponse = await MockData.getResponse(); + mockSurveyResponseService.Setup(service => service.GetSurveyResponsesBySurveyAndLocationAsync(1, "Loc1")).ReturnsAsync(mockResponse); + var surveyResponseProvider = new SurveyResponsesController(mockSurveyResponseService.Object); + var result = (NoContentResult)await surveyResponseProvider.GetSurveyResponsesBySurveyAndLocationAsync(1, "Lo1"); + Assert.Equal(204, result.StatusCode); + } + + [Fact(DisplayName = "Get SurveyResponses by surveyId and QuestionId and Answer - Ok case")] + public async Task GetSurveyResponsesBySurveyQuestionAnswerAsync_ShouldReturnStatusCode200() + { + SurveyResponse mockRequestObject = await MockData.getSurveyResponseObject(); + var mockResponse = await MockData.getOkResponse(); + mockSurveyResponseService.Setup(service => service.GetResponsesByAnswerAsync(1, 1, "Yes")).ReturnsAsync(mockResponse); + var surveyResponseProvider = new SurveyResponsesController(mockSurveyResponseService.Object); + var result = (OkObjectResult)await surveyResponseProvider.GetSurveyResponsesByAnswerAsyncAsync(1, 1, "Yes"); + Assert.Equal(200, result.StatusCode); + } + + [Fact(DisplayName = "Get SurveyResponses by surveyId and QuestionId and Answer - NoContent case")] + public async Task GetSurveyResponsesBySurveyQuestionAnswerAsync_ShouldReturnStatusCode204() + { + var mockResponse = await MockData.getResponse(); + mockSurveyResponseService.Setup(service => service.GetResponsesByAnswerAsync(1, 1, "Yes")).ReturnsAsync(mockResponse); + var surveyResponseProvider = new SurveyResponsesController(mockSurveyResponseService.Object); + var result = (NoContentResult)await surveyResponseProvider.GetSurveyResponsesByAnswerAsyncAsync(1, 1, "Yes"); + Assert.Equal(204, result.StatusCode); + } + + + [Fact(DisplayName = "Get SurveyResponses by region and surveyId - Ok case")] + public async Task GetSurveyResponsesByRegionSurveyAsync_ShouldReturnStatusCode200() + { + SurveyResponse mockRequestObject = await MockData.getSurveyResponseObject(); + var mockResponse = await MockData.getOkResponse(); + mockSurveyResponseService.Setup(service => service.GetAnswersByRegionAsync(1)).ReturnsAsync(mockResponse); + var surveyResponseProvider = new SurveyResponsesController(mockSurveyResponseService.Object); + var result = (OkObjectResult)await surveyResponseProvider.GetAnswersByRegionAsync(1); + Assert.Equal(200, result.StatusCode); + } + + [Fact(DisplayName = "Get SurveyResponses by region and surveyId - NoContent Case")] + public async Task GetSurveyResponsesByRegionSurveyAsync_ShouldReturnStatusCode204() + { + var mockResponse = await MockData.getResponse(); + mockSurveyResponseService.Setup(service => service.GetAnswersByRegionAsync(1)).ReturnsAsync(mockResponse); + var surveyResponseProvider = new SurveyResponsesController(mockSurveyResponseService.Object); + var result = (NoContentResult)await surveyResponseProvider.GetAnswersByRegionAsync(1); + Assert.Equal(204, result.StatusCode); + } + + [Fact(DisplayName = "Get SurveyResponses by maintenanceCenter and surveyId - Ok case")] + public async Task GetSurveyResponsesMaintenanceCenterSurveyAsync_ShouldReturnStatusCode200() + { + SurveyResponse mockRequestObject = await MockData.getSurveyResponseObject(); + var mockResponse = await MockData.getOkResponse(); + mockSurveyResponseService.Setup(service => service.GetSurveyResponsesByMaintenanceCenterAsync(1)).ReturnsAsync(mockResponse); + var surveyResponseProvider = new SurveyResponsesController(mockSurveyResponseService.Object); + var result = (OkObjectResult)await surveyResponseProvider.GetAnswersByMaintenaceCentersync(1); + Assert.Equal(200, result.StatusCode); + } + + [Fact(DisplayName = "Get SurveyResponses by maintenanceCenter and surveyId - No Content Case")] + public async Task GetSurveyResponsesMaintenanceCenterSurveyAsync_ShouldReturnStatusCode204() + { + var mockResponse = await MockData.getResponse(); + mockSurveyResponseService.Setup(service => service.GetSurveyResponsesByMaintenanceCenterAsync(1)).ReturnsAsync(mockResponse); + var surveyResponseProvider = new SurveyResponsesController(mockSurveyResponseService.Object); + var result = (NoContentResult)await surveyResponseProvider.GetAnswersByMaintenaceCentersync(1); + Assert.Equal(204, result.StatusCode); + } + + [Fact(DisplayName = "Get SurveyResponse by responseId- Ok case")] + public async Task GetSurveyResponsesByResponseIdyAsync_ShouldReturnStatusCode200() + { + SurveyResponse mockRequestObject = await MockData.getSurveyResponseObject(); + var mockResponse = await MockData.getOkResponse(); + mockSurveyResponseService.Setup(service => service.GetSurveyResponseByIdAsync(1)).ReturnsAsync(mockResponse); + var surveyResponseProvider = new SurveyResponsesController(mockSurveyResponseService.Object); + var result = (OkObjectResult)await surveyResponseProvider.GetSurveyResponseByIdAsync(1); + Assert.Equal(200, result.StatusCode); + } + + [Fact(DisplayName = "Get SurveyResponses by maintenanceCenter and surveyId - NoContent Case")] + public async Task GetSurveyResponsesByResponseIdyAsync_ShouldReturnStatusCode204() + { + var mockResponse = await MockData.getResponse(); + mockSurveyResponseService.Setup(service => service.GetSurveyResponseByIdAsync(1)).ReturnsAsync(mockResponse); + var surveyResponseProvider = new SurveyResponsesController(mockSurveyResponseService.Object); + var result = (NoContentResult)await surveyResponseProvider.GetSurveyResponseByIdAsync(1); + Assert.Equal(204, result.StatusCode); + } + + + [Fact(DisplayName = "Post SurveyResponses - Ok case")] + public async Task PostSurveyAsync_ShouldReturnStatusCode200() + { + SurveyResponse mockRequestObject = await MockData.getSurveyResponseObject(); + var mockResponse = await MockData.getOkResponse(mockRequestObject); + mockSurveyResponseService.Setup(service => service.PostSurveyResponseAsync(mockRequestObject)).ReturnsAsync(mockResponse); + var surveyResponseController = new SurveyResponsesController(mockSurveyResponseService.Object); + var result = (OkObjectResult)await surveyResponseController.PostSurveysAsync(mockRequestObject); + Assert.Equal(200, result.StatusCode); + } + + [Fact(DisplayName = "Post SurveyResponses - BadRequest case")] + public async Task PostSurveyAsync_ShouldReturnStatusCode400() + { + SurveyResponse mockRequestObject = await MockData.getSurveyResponseObject(); + var mockResponse = await MockData.getResponse(); + mockSurveyResponseService.Setup(service => service.PostSurveyResponseAsync(mockRequestObject)).ReturnsAsync(mockResponse); + var surveyResponseController = new SurveyResponsesController(mockSurveyResponseService.Object); + var result = (BadRequestObjectResult)await surveyResponseController.PostSurveysAsync(mockRequestObject); + Assert.Equal(400, result.StatusCode); + } + + [Fact(DisplayName = "Put SurveyResponses - Ok case")] + public async Task PutSurveyAsync_ShouldReturnStatusCode200() + { + SurveyResponse mockRequestObject = await MockData.getSurveyResponseObject(); + var mockResponse = await MockData.getOkResponse(mockRequestObject); + mockSurveyResponseService.Setup(service => service.PutSurveyResponseAsync(1, mockRequestObject)).ReturnsAsync(mockResponse); + var surveyResponseController = new SurveyResponsesController(mockSurveyResponseService.Object); + var result = (OkObjectResult)await surveyResponseController.PutSurveyResponseAsync(1, mockRequestObject); + Assert.Equal(200, result.StatusCode); + } + + [Fact(DisplayName = "Put SurveyResponses - BadRequest case")] + public async Task PutSurveyAsync_ShouldReturnStatusCode404() + { + SurveyResponse mockRequestObject = await MockData.getSurveyResponseObject(); + var mockResponse = await MockData.getResponse(); + mockSurveyResponseService.Setup(service => service.PutSurveyResponseAsync(1, mockRequestObject)).ReturnsAsync(mockResponse); ; + var surveyResponseController = new SurveyResponsesController(mockSurveyResponseService.Object); + var result = (BadRequestObjectResult)await surveyResponseController.PutSurveyResponseAsync(1, mockRequestObject); + Assert.Equal(400, result.StatusCode); + } + + [Fact(DisplayName = "Delete SurveyResponses - Ok case")] + public async Task DeleteSurveyAsync_ShouldReturnStatusCode200() + { + SurveyResponse mockRequestObject = await MockData.getSurveyResponseObject(); + var mockResponse = await MockData.getOkResponse(mockRequestObject); + mockSurveyResponseService.Setup(service => service.DeleteSurveyResponseAsync(1)).ReturnsAsync(mockResponse); + var surveyResponseController = new SurveyResponsesController(mockSurveyResponseService.Object); + var result = (OkObjectResult)await surveyResponseController.DeleteSurveyResponseAsync(1); + Assert.Equal(200, result.StatusCode); + } + + [Fact(DisplayName = "Delete SurveyResponses - NotFound case")] + public async Task DeleteSurveyAsync_ShouldReturnStatusCode404() + { + var mockResponse = await MockData.getResponse(); + mockSurveyResponseService.Setup(service => service.DeleteSurveyResponseAsync(1)).ReturnsAsync(mockResponse); ; + var surveyResponseController = new SurveyResponsesController(mockSurveyResponseService.Object); + var result = (NotFoundResult)await surveyResponseController.DeleteSurveyResponseAsync(1); + Assert.Equal(404, result.StatusCode); + } + } +} \ No newline at end of file diff --git a/DamageAssesmentApi/DamageAssesment.sln b/DamageAssesmentApi/DamageAssesment.sln new file mode 100644 index 0000000..a8b1fcc --- /dev/null +++ b/DamageAssesmentApi/DamageAssesment.sln @@ -0,0 +1,108 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 17 +VisualStudioVersion = 17.5.33530.505 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DamageAssesment.Api.Questions", "DamageAssesment.Api.Questions\DamageAssesment.Api.Questions.csproj", "{4C09E7D3-971D-423D-AE0F-C6E1671E5364}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DamageAssesment.Api.Answers", "DamageAssesment.Api.Answers\DamageAssesment.Api.Answers.csproj", "{3B279095-B7C5-4AF0-93F6-6D9601F55DAF}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DamageAssesment.Api.Attachments", "DamageAssesment.Api.Attachments\DamageAssesment.Api.Attachments.csproj", "{FF619F3A-D1BB-4934-A0E1-6EF7D0DAACD6}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{4CB40DC2-D9D2-4384-A7A6-9968F5C777A2}" + ProjectSection(SolutionItems) = preProject + ReadMe.txt = ReadMe.txt + ReadMe4Dev.txt = ReadMe4Dev.txt + EndProjectSection +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DamageAssesment.Api.Locations", "DamageAssesment.Api.Locations\DamageAssesment.Api.Locations.csproj", "{746C67BF-9949-4361-B5D2-358C7607750E}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DamageAssesment.Api.SurveyResponses", "DamageAssesment.Api.SurveyResponses\DamageAssesment.Api.SurveyResponses.csproj", "{D11808FE-AD1C-4BA6-87FD-9D18B2DC81F2}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DamageAssesment.Api.Questions.Test", "DamageAssesment.Api.QuestionsTest\DamageAssesment.Api.Questions.Test.csproj", "{35CD9231-034D-4999-BCFC-1786DD007ED2}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DamageAssesment.Api.Survey.Test", "DamageAssesment.Api.Surveys.Test\DamageAssesment.Api.Survey.Test.csproj", "{ADFB79E3-83C9-454F-A070-49D167BD28CC}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DamageAssesment.Api.SurveyResponses.Test", "DamageAssesment.SurveyResponses.Test\DamageAssesment.Api.SurveyResponses.Test.csproj", "{6F4B9C9D-CE5D-421A-876F-57D0FEDF8049}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DamageAssesment.Api.Attachments.Test", "DamageAssesment.Api.Attachments.Test\DamageAssesment.Api.Attachments.Test.csproj", "{730E5718-FCE1-42C0-AB76-EA020896A788}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DamageAssesment.Api.Locations.Test", "DamageAssesment.Api.Locations.Test\DamageAssesment.Api.Locations.Test.csproj", "{DA68AE47-6825-41ED-9107-5151822FB083}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DamageAssesment.Api.Survey", "DamageAssesment.Api.Surveys\DamageAssesment.Api.Survey.csproj", "{55481AED-6801-47DB-A176-A6FA92002081}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DamageAssesment.Api.Answers.Test", "DamageAssesment.Api.Answers.Test\DamageAssesment.Api.Answers.Test.csproj", "{594A47AC-DF50-47E5-903D-A856CADDF573}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DamageAssesment.Api.Employees", "DamageAssesment.Api.Employees\DamageAssesment.Api.Employees.csproj", "{FF47642A-F357-4972-A701-C21892BF88BD}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DamageAssesment.Api.Employees.Test", "DamageAssesment.Api.Employees.Test\DamageAssesment.Api.Employees.Test.csproj", "{D6BF9AE9-72FA-4726-A326-35A35D27FFB8}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {4C09E7D3-971D-423D-AE0F-C6E1671E5364}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {4C09E7D3-971D-423D-AE0F-C6E1671E5364}.Debug|Any CPU.Build.0 = Debug|Any CPU + {4C09E7D3-971D-423D-AE0F-C6E1671E5364}.Release|Any CPU.ActiveCfg = Release|Any CPU + {4C09E7D3-971D-423D-AE0F-C6E1671E5364}.Release|Any CPU.Build.0 = Release|Any CPU + {3B279095-B7C5-4AF0-93F6-6D9601F55DAF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {3B279095-B7C5-4AF0-93F6-6D9601F55DAF}.Debug|Any CPU.Build.0 = Debug|Any CPU + {3B279095-B7C5-4AF0-93F6-6D9601F55DAF}.Release|Any CPU.ActiveCfg = Release|Any CPU + {3B279095-B7C5-4AF0-93F6-6D9601F55DAF}.Release|Any CPU.Build.0 = Release|Any CPU + {FF619F3A-D1BB-4934-A0E1-6EF7D0DAACD6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {FF619F3A-D1BB-4934-A0E1-6EF7D0DAACD6}.Debug|Any CPU.Build.0 = Debug|Any CPU + {FF619F3A-D1BB-4934-A0E1-6EF7D0DAACD6}.Release|Any CPU.ActiveCfg = Release|Any CPU + {FF619F3A-D1BB-4934-A0E1-6EF7D0DAACD6}.Release|Any CPU.Build.0 = Release|Any CPU + {746C67BF-9949-4361-B5D2-358C7607750E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {746C67BF-9949-4361-B5D2-358C7607750E}.Debug|Any CPU.Build.0 = Debug|Any CPU + {746C67BF-9949-4361-B5D2-358C7607750E}.Release|Any CPU.ActiveCfg = Release|Any CPU + {746C67BF-9949-4361-B5D2-358C7607750E}.Release|Any CPU.Build.0 = Release|Any CPU + {D11808FE-AD1C-4BA6-87FD-9D18B2DC81F2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {D11808FE-AD1C-4BA6-87FD-9D18B2DC81F2}.Debug|Any CPU.Build.0 = Debug|Any CPU + {D11808FE-AD1C-4BA6-87FD-9D18B2DC81F2}.Release|Any CPU.ActiveCfg = Release|Any CPU + {D11808FE-AD1C-4BA6-87FD-9D18B2DC81F2}.Release|Any CPU.Build.0 = Release|Any CPU + {35CD9231-034D-4999-BCFC-1786DD007ED2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {35CD9231-034D-4999-BCFC-1786DD007ED2}.Release|Any CPU.ActiveCfg = Release|Any CPU + {35CD9231-034D-4999-BCFC-1786DD007ED2}.Release|Any CPU.Build.0 = Release|Any CPU + {ADFB79E3-83C9-454F-A070-49D167BD28CC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {ADFB79E3-83C9-454F-A070-49D167BD28CC}.Debug|Any CPU.Build.0 = Debug|Any CPU + {ADFB79E3-83C9-454F-A070-49D167BD28CC}.Release|Any CPU.ActiveCfg = Release|Any CPU + {ADFB79E3-83C9-454F-A070-49D167BD28CC}.Release|Any CPU.Build.0 = Release|Any CPU + {6F4B9C9D-CE5D-421A-876F-57D0FEDF8049}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {6F4B9C9D-CE5D-421A-876F-57D0FEDF8049}.Debug|Any CPU.Build.0 = Debug|Any CPU + {6F4B9C9D-CE5D-421A-876F-57D0FEDF8049}.Release|Any CPU.ActiveCfg = Release|Any CPU + {6F4B9C9D-CE5D-421A-876F-57D0FEDF8049}.Release|Any CPU.Build.0 = Release|Any CPU + {730E5718-FCE1-42C0-AB76-EA020896A788}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {730E5718-FCE1-42C0-AB76-EA020896A788}.Debug|Any CPU.Build.0 = Debug|Any CPU + {730E5718-FCE1-42C0-AB76-EA020896A788}.Release|Any CPU.ActiveCfg = Release|Any CPU + {730E5718-FCE1-42C0-AB76-EA020896A788}.Release|Any CPU.Build.0 = Release|Any CPU + {DA68AE47-6825-41ED-9107-5151822FB083}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {DA68AE47-6825-41ED-9107-5151822FB083}.Debug|Any CPU.Build.0 = Debug|Any CPU + {DA68AE47-6825-41ED-9107-5151822FB083}.Release|Any CPU.ActiveCfg = Release|Any CPU + {DA68AE47-6825-41ED-9107-5151822FB083}.Release|Any CPU.Build.0 = Release|Any CPU + {55481AED-6801-47DB-A176-A6FA92002081}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {55481AED-6801-47DB-A176-A6FA92002081}.Debug|Any CPU.Build.0 = Debug|Any CPU + {55481AED-6801-47DB-A176-A6FA92002081}.Release|Any CPU.ActiveCfg = Release|Any CPU + {55481AED-6801-47DB-A176-A6FA92002081}.Release|Any CPU.Build.0 = Release|Any CPU + {594A47AC-DF50-47E5-903D-A856CADDF573}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {594A47AC-DF50-47E5-903D-A856CADDF573}.Debug|Any CPU.Build.0 = Debug|Any CPU + {594A47AC-DF50-47E5-903D-A856CADDF573}.Release|Any CPU.ActiveCfg = Release|Any CPU + {594A47AC-DF50-47E5-903D-A856CADDF573}.Release|Any CPU.Build.0 = Release|Any CPU + {FF47642A-F357-4972-A701-C21892BF88BD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {FF47642A-F357-4972-A701-C21892BF88BD}.Debug|Any CPU.Build.0 = Debug|Any CPU + {FF47642A-F357-4972-A701-C21892BF88BD}.Release|Any CPU.ActiveCfg = Release|Any CPU + {FF47642A-F357-4972-A701-C21892BF88BD}.Release|Any CPU.Build.0 = Release|Any CPU + {D6BF9AE9-72FA-4726-A326-35A35D27FFB8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {D6BF9AE9-72FA-4726-A326-35A35D27FFB8}.Debug|Any CPU.Build.0 = Debug|Any CPU + {D6BF9AE9-72FA-4726-A326-35A35D27FFB8}.Release|Any CPU.ActiveCfg = Release|Any CPU + {D6BF9AE9-72FA-4726-A326-35A35D27FFB8}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {27389EB0-44BC-4BDE-A1CA-BFCB3816C7BD} + EndGlobalSection +EndGlobal diff --git a/README.md b/README.md index 0ca446a..a4579b6 100644 --- a/README.md +++ b/README.md @@ -1,20 +1,20 @@ -# Introduction -TODO: Give a short introduction of your project. Let this section explain the objectives or the motivation behind this project. - -# Getting Started -TODO: Guide users through getting your code up and running on their own system. In this section you can talk about: -1. Installation process -2. Software dependencies -3. Latest releases -4. API references - -# Build and Test -TODO: Describe and show how to build your code and run the tests. - -# Contribute -TODO: Explain how other users and developers can contribute to make your code better. - -If you want to learn more about creating good readme files then refer the following [guidelines](https://docs.microsoft.com/en-us/azure/devops/repos/git/create-a-readme?view=azure-devops). You can also seek inspiration from the below readme files: -- [ASP.NET Core](https://github.com/aspnet/Home) -- [Visual Studio Code](https://github.com/Microsoft/vscode) +# Introduction +TODO: Give a short introduction of your project. Let this section explain the objectives or the motivation behind this project. + +# Getting Started +TODO: Guide users through getting your code up and running on their own system. In this section you can talk about: +1. Installation process +2. Software dependencies +3. Latest releases +4. API references + +# Build and Test +TODO: Describe and show how to build your code and run the tests. + +# Contribute +TODO: Explain how other users and developers can contribute to make your code better. + +If you want to learn more about creating good readme files then refer the following [guidelines](https://www.visualstudio.com/en-us/docs/git/create-a-readme). You can also seek inspiration from the below readme files: +- [ASP.NET Core](https://github.com/aspnet/Home) +- [Visual Studio Code](https://github.com/Microsoft/vscode) - [Chakra Core](https://github.com/Microsoft/ChakraCore) \ No newline at end of file