diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..3e1f87d --- /dev/null +++ b/.gitignore @@ -0,0 +1,5 @@ +################################################################################ +# This .gitignore file was automatically created by Microsoft(R) Visual Studio. +################################################################################ + +/DamageAssesmentApi/nginx.conf diff --git a/DamageAssesmentApi/DamageAssesment.Api.Answers/Controllers/AnswersController.cs b/DamageAssesmentApi/DamageAssesment.Api.Answers/Controllers/AnswersController.cs index bbfc323..34a9fd9 100644 --- a/DamageAssesmentApi/DamageAssesment.Api.Answers/Controllers/AnswersController.cs +++ b/DamageAssesmentApi/DamageAssesment.Api.Answers/Controllers/AnswersController.cs @@ -5,7 +5,7 @@ using Microsoft.OpenApi.Any; namespace DamageAssesment.Api.Answers.Controllers { - [Route("api")] + //[Route("api")] [ApiController] public class AnswersController: ControllerBase { diff --git a/DamageAssesmentApi/DamageAssesment.Api.Answers/Dockerfile b/DamageAssesmentApi/DamageAssesment.Api.Answers/Dockerfile index 2ae373c..3a77a89 100644 --- a/DamageAssesmentApi/DamageAssesment.Api.Answers/Dockerfile +++ b/DamageAssesmentApi/DamageAssesment.Api.Answers/Dockerfile @@ -1,21 +1,39 @@ #See https://aka.ms/customizecontainer to learn how to customize your debug container and how Visual Studio uses this Dockerfile to build your images for faster debugging. +# Use the ASP.NET base image FROM mcr.microsoft.com/dotnet/aspnet:6.0 AS base WORKDIR /app EXPOSE 80 +# Use the SDK image for building FROM mcr.microsoft.com/dotnet/sdk:6.0 AS build WORKDIR /src + +# Copy the project file and restore dependencies COPY ["DamageAssesment.Api.Answers/DamageAssesment.Api.Answers.csproj", "DamageAssesment.Api.Answers/"] RUN dotnet restore "DamageAssesment.Api.Answers/DamageAssesment.Api.Answers.csproj" + +# Copy the source code COPY . . WORKDIR "/src/DamageAssesment.Api.Answers" + +# Build the application RUN dotnet build "DamageAssesment.Api.Answers.csproj" -c Release -o /app/build +# Publish the application FROM build AS publish RUN dotnet publish "DamageAssesment.Api.Answers.csproj" -c Release -o /app/publish /p:UseAppHost=false +# Set up the final image FROM base AS final WORKDIR /app + +# Copy the published files COPY --from=publish /app/publish . -ENTRYPOINT ["dotnet", "DamageAssesment.Api.Answers.dll"] \ No newline at end of file + +## Set up the volume and copy the XML comments +#VOLUME /xmlcomments +#COPY ["DamageAssesment.Api.Answers.xml", "/xmlcomments/DamageAssesment.Api.Answers.xml"] +# +# Specify the entry point for the container +ENTRYPOINT ["dotnet", "DamageAssesment.Api.Answers.dll"] diff --git a/DamageAssesmentApi/DamageAssesment.Api.Answers/Program.cs b/DamageAssesmentApi/DamageAssesment.Api.Answers/Program.cs index 84e8dc6..328c804 100644 --- a/DamageAssesmentApi/DamageAssesment.Api.Answers/Program.cs +++ b/DamageAssesmentApi/DamageAssesment.Api.Answers/Program.cs @@ -39,7 +39,7 @@ if (app.Environment.IsDevelopment()) app.UseSwaggerUI(options => { options.SwaggerEndpoint("/swagger/v1/swagger.json","" ); - // options.RoutePrefix = ""; // Serve Swagger UI at the root URL + }); } diff --git a/DamageAssesmentApi/DamageAssesment.Api.Attachments/Controllers/AttachmentsController.cs b/DamageAssesmentApi/DamageAssesment.Api.Attachments/Controllers/AttachmentsController.cs index 8050515..c798ebb 100644 --- a/DamageAssesmentApi/DamageAssesment.Api.Attachments/Controllers/AttachmentsController.cs +++ b/DamageAssesmentApi/DamageAssesment.Api.Attachments/Controllers/AttachmentsController.cs @@ -7,7 +7,7 @@ using System.Net.Http.Headers; namespace DamageAssesment.Api.Attachments.Controllers { - [Route("api")] + //[Route("api")] [ApiController] public class AttachmentsController : ControllerBase { 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/Dockerfile b/DamageAssesmentApi/DamageAssesment.Api.Attachments/Dockerfile index f3bdaa0..1af6dcd 100644 --- a/DamageAssesmentApi/DamageAssesment.Api.Attachments/Dockerfile +++ b/DamageAssesmentApi/DamageAssesment.Api.Attachments/Dockerfile @@ -1,31 +1,47 @@ #See https://aka.ms/customizecontainer to learn how to customize your debug container and how Visual Studio uses this Dockerfile to build your images for faster debugging. - +# Use the ASP.NET base image FROM mcr.microsoft.com/dotnet/aspnet:6.0 AS base WORKDIR /app EXPOSE 80 +# Use the SDK image for building FROM mcr.microsoft.com/dotnet/sdk:6.0 AS build WORKDIR /src + +# Copy the project file and restore dependencies COPY ["DamageAssesment.Api.Attachments/DamageAssesment.Api.Attachments.csproj", "DamageAssesment.Api.Attachments/"] RUN dotnet restore "DamageAssesment.Api.Attachments/DamageAssesment.Api.Attachments.csproj" + +# Copy the source code COPY . . WORKDIR "/src/DamageAssesment.Api.Attachments" + +# Build the application RUN dotnet build "DamageAssesment.Api.Attachments.csproj" -c Release -o /app/build +# Publish the application FROM build AS publish RUN dotnet publish "DamageAssesment.Api.Attachments.csproj" -c Release -o /app/publish /p:UseAppHost=false +# Set up the final image FROM base AS final WORKDIR /app + +# Copy the published files COPY --from=publish /app/publish . -# Copy the appsettings.json file to the container -#COPY appsettings.json . + # Create directories for attachments and set permissions RUN mkdir -p /app/DMS_Attachments/Active && \ mkdir -p /app/DMS_Attachments/Deleted && \ chown -R www-data:www-data /app/DMS_Attachments - # Update appsettings.json with the correct paths for attachments + +# Update appsettings.json with the correct paths for attachments RUN sed -i 's#"folderpath": "DMS_Attachments/Active"#"folderpath": "/app/DMS_Attachments/Active"#' appsettings.json && \ sed -i 's#"Deletepath": "DMS_Attachments/Deleted"#"Deletepath": "/app/DMS_Attachments/Deleted"#' appsettings.json -ENTRYPOINT ["dotnet", "DamageAssesment.Api.Attachments.dll"] \ No newline at end of file +## Set up the volume and copy the XML comments +#VOLUME /xmlcomments +#COPY ["DamageAssesment.Api.Attachments/bin/Release/net6.0/DamageAssesment.Api.Attachments.xml", "/xmlcomments/"] +# +# Specify the entry point for the container +ENTRYPOINT ["dotnet", "DamageAssesment.Api.Attachments.dll"] diff --git a/DamageAssesmentApi/DamageAssesment.Api.Employees/Controllers/EmployeesController.cs b/DamageAssesmentApi/DamageAssesment.Api.Employees/Controllers/EmployeesController.cs index 8d004e6..7aae5a3 100644 --- a/DamageAssesmentApi/DamageAssesment.Api.Employees/Controllers/EmployeesController.cs +++ b/DamageAssesmentApi/DamageAssesment.Api.Employees/Controllers/EmployeesController.cs @@ -4,7 +4,7 @@ using Microsoft.AspNetCore.Mvc; namespace DamageAssesment.Api.Employees.Controllers { - [Route("api")] + //[Route("api")] [ApiController] public class EmployeesController : ControllerBase { diff --git a/DamageAssesmentApi/DamageAssesment.Api.Employees/Dockerfile b/DamageAssesmentApi/DamageAssesment.Api.Employees/Dockerfile index cbc7d04..01194b9 100644 --- a/DamageAssesmentApi/DamageAssesment.Api.Employees/Dockerfile +++ b/DamageAssesmentApi/DamageAssesment.Api.Employees/Dockerfile @@ -1,21 +1,39 @@ #See https://aka.ms/customizecontainer to learn how to customize your debug container and how Visual Studio uses this Dockerfile to build your images for faster debugging. +# Use the ASP.NET base image FROM mcr.microsoft.com/dotnet/aspnet:6.0 AS base WORKDIR /app EXPOSE 80 +# Use the SDK image for building FROM mcr.microsoft.com/dotnet/sdk:6.0 AS build WORKDIR /src + +# Copy the project file and restore dependencies COPY ["DamageAssesment.Api.Employees/DamageAssesment.Api.Employees.csproj", "DamageAssesment.Api.Employees/"] RUN dotnet restore "DamageAssesment.Api.Employees/DamageAssesment.Api.Employees.csproj" + +# Copy the source code COPY . . WORKDIR "/src/DamageAssesment.Api.Employees" + +# Build the application RUN dotnet build "DamageAssesment.Api.Employees.csproj" -c Release -o /app/build +# Publish the application FROM build AS publish RUN dotnet publish "DamageAssesment.Api.Employees.csproj" -c Release -o /app/publish /p:UseAppHost=false +# Set up the final image FROM base AS final WORKDIR /app + +# Copy the published files COPY --from=publish /app/publish . -ENTRYPOINT ["dotnet", "DamageAssesment.Api.Employees.dll"] \ No newline at end of file + +## Set up the volume and copy the XML comments +#VOLUME /xmlcomments +#COPY ["DamageAssesment.Api.Employees.xml", "/xmlcomments/DamageAssesment.Api.Employees.xml"] + +# Specify the entry point for the container +ENTRYPOINT ["dotnet", "DamageAssesment.Api.Employees.dll"] diff --git a/DamageAssesmentApi/DamageAssesment.Api.Locations.Test/DamageAssesment.Api.Locations.Test.csproj b/DamageAssesmentApi/DamageAssesment.Api.Locations.Test/DamageAssesment.Api.Locations.Test.csproj index ee2a779..fb7b05b 100644 --- a/DamageAssesmentApi/DamageAssesment.Api.Locations.Test/DamageAssesment.Api.Locations.Test.csproj +++ b/DamageAssesmentApi/DamageAssesment.Api.Locations.Test/DamageAssesment.Api.Locations.Test.csproj @@ -1,4 +1,4 @@ - + net6.0 diff --git a/DamageAssesmentApi/DamageAssesment.Api.Locations/Controllers/LocationsController.cs b/DamageAssesmentApi/DamageAssesment.Api.Locations/Controllers/LocationsController.cs index 0ee489a..5100081 100644 --- a/DamageAssesmentApi/DamageAssesment.Api.Locations/Controllers/LocationsController.cs +++ b/DamageAssesmentApi/DamageAssesment.Api.Locations/Controllers/LocationsController.cs @@ -4,7 +4,7 @@ using Microsoft.AspNetCore.Mvc; namespace DamageAssesment.Api.Locations.Controllers { - [Route("api")] + //[Route("api")] [ApiController] public class LocationsController : ControllerBase { diff --git a/DamageAssesmentApi/DamageAssesment.Api.Locations/Controllers/RegionsController.cs b/DamageAssesmentApi/DamageAssesment.Api.Locations/Controllers/RegionsController.cs index 81725e4..aca9e18 100644 --- a/DamageAssesmentApi/DamageAssesment.Api.Locations/Controllers/RegionsController.cs +++ b/DamageAssesmentApi/DamageAssesment.Api.Locations/Controllers/RegionsController.cs @@ -3,7 +3,7 @@ using Microsoft.AspNetCore.Mvc; namespace DamageAssesment.Api.Locations.Controllers { - [Route("api/[controller]")] + //[Route("api/[controller]")] [ApiController] public class RegionsController : ControllerBase { diff --git a/DamageAssesmentApi/DamageAssesment.Api.Locations/Dockerfile b/DamageAssesmentApi/DamageAssesment.Api.Locations/Dockerfile index bb9aeb9..62c4fa8 100644 --- a/DamageAssesmentApi/DamageAssesment.Api.Locations/Dockerfile +++ b/DamageAssesmentApi/DamageAssesment.Api.Locations/Dockerfile @@ -1,21 +1,39 @@ #See https://aka.ms/customizecontainer to learn how to customize your debug container and how Visual Studio uses this Dockerfile to build your images for faster debugging. +# Use the ASP.NET base image FROM mcr.microsoft.com/dotnet/aspnet:6.0 AS base WORKDIR /app EXPOSE 80 +# Use the SDK image for building FROM mcr.microsoft.com/dotnet/sdk:6.0 AS build WORKDIR /src + +# Copy the project file and restore dependencies COPY ["DamageAssesment.Api.Locations/DamageAssesment.Api.Locations.csproj", "DamageAssesment.Api.Locations/"] RUN dotnet restore "DamageAssesment.Api.Locations/DamageAssesment.Api.Locations.csproj" + +# Copy the source code COPY . . WORKDIR "/src/DamageAssesment.Api.Locations" + +# Build the application RUN dotnet build "DamageAssesment.Api.Locations.csproj" -c Release -o /app/build +# Publish the application FROM build AS publish RUN dotnet publish "DamageAssesment.Api.Locations.csproj" -c Release -o /app/publish /p:UseAppHost=false +# Set up the final image FROM base AS final WORKDIR /app + +# Copy the published files COPY --from=publish /app/publish . -ENTRYPOINT ["dotnet", "DamageAssesment.Api.Locations.dll"] \ No newline at end of file + +## Set up the volume and copy the XML comments +#VOLUME /xmlcomments +#COPY ["DamageAssesment.Api.Locations.xml", "/xmlcomments/DamageAssesment.Api.Locations.xml"] + +# Specify the entry point for the container +ENTRYPOINT ["dotnet", "DamageAssesment.Api.Locations.dll"] diff --git a/DamageAssesmentApi/DamageAssesment.Api.Questions/Controllers/QuestionsController.cs b/DamageAssesmentApi/DamageAssesment.Api.Questions/Controllers/QuestionsController.cs index f7eb968..5739119 100644 --- a/DamageAssesmentApi/DamageAssesment.Api.Questions/Controllers/QuestionsController.cs +++ b/DamageAssesmentApi/DamageAssesment.Api.Questions/Controllers/QuestionsController.cs @@ -3,7 +3,7 @@ using Microsoft.AspNetCore.Mvc; namespace DamageAssesment.Api.Questions.Controllers { - [Route("api")] + //[Route("api")] [ApiController] public class QuestionsController : ControllerBase { diff --git a/DamageAssesmentApi/DamageAssesment.Api.Questions/Dockerfile b/DamageAssesmentApi/DamageAssesment.Api.Questions/Dockerfile index 11f44c9..4ff3723 100644 --- a/DamageAssesmentApi/DamageAssesment.Api.Questions/Dockerfile +++ b/DamageAssesmentApi/DamageAssesment.Api.Questions/Dockerfile @@ -1,21 +1,38 @@ #See https://aka.ms/customizecontainer to learn how to customize your debug container and how Visual Studio uses this Dockerfile to build your images for faster debugging. - +# Use the ASP.NET base image FROM mcr.microsoft.com/dotnet/aspnet:6.0 AS base WORKDIR /app EXPOSE 80 +# Use the SDK image for building FROM mcr.microsoft.com/dotnet/sdk:6.0 AS build WORKDIR /src + +# Copy the project file and restore dependencies COPY ["DamageAssesment.Api.Questions/DamageAssesment.Api.Questions.csproj", "DamageAssesment.Api.Questions/"] RUN dotnet restore "DamageAssesment.Api.Questions/DamageAssesment.Api.Questions.csproj" + +# Copy the source code COPY . . WORKDIR "/src/DamageAssesment.Api.Questions" + +# Build the application RUN dotnet build "DamageAssesment.Api.Questions.csproj" -c Release -o /app/build +# Publish the application FROM build AS publish RUN dotnet publish "DamageAssesment.Api.Questions.csproj" -c Release -o /app/publish /p:UseAppHost=false +# Set up the final image FROM base AS final WORKDIR /app + +# Copy the published files COPY --from=publish /app/publish . -ENTRYPOINT ["dotnet", "DamageAssesment.Api.Questions.dll"] \ No newline at end of file + +## Set up the volume and copy the XML comments +#VOLUME /xmlcomments +#COPY ["DamageAssesment.Api.Questions.xml", "/xmlcomments/DamageAssesment.Api.Questions.xml"] + +# Specify the entry point for the container +ENTRYPOINT ["dotnet", "DamageAssesment.Api.Questions.dll"] diff --git a/DamageAssesmentApi/DamageAssesment.Api.SurveyResponses/Controllers/SurveyResponsesController.cs b/DamageAssesmentApi/DamageAssesment.Api.SurveyResponses/Controllers/SurveyResponsesController.cs index c650d1d..9a52fa1 100644 --- a/DamageAssesmentApi/DamageAssesment.Api.SurveyResponses/Controllers/SurveyResponsesController.cs +++ b/DamageAssesmentApi/DamageAssesment.Api.SurveyResponses/Controllers/SurveyResponsesController.cs @@ -6,7 +6,7 @@ using Microsoft.Extensions.Configuration; namespace DamageAssesment.Api.SurveyResponses.Controllers { - [Route("api")] + //[Route("api")] [ApiController] public class SurveyResponsesController : ControllerBase { diff --git a/DamageAssesmentApi/DamageAssesment.Api.SurveyResponses/Dockerfile b/DamageAssesmentApi/DamageAssesment.Api.SurveyResponses/Dockerfile index 0001073..a02ca27 100644 --- a/DamageAssesmentApi/DamageAssesment.Api.SurveyResponses/Dockerfile +++ b/DamageAssesmentApi/DamageAssesment.Api.SurveyResponses/Dockerfile @@ -1,21 +1,41 @@ #See https://aka.ms/customizecontainer to learn how to customize your debug container and how Visual Studio uses this Dockerfile to build your images for faster debugging. +# Use the ASP.NET base image FROM mcr.microsoft.com/dotnet/aspnet:6.0 AS base WORKDIR /app EXPOSE 80 +# Use the SDK image for building FROM mcr.microsoft.com/dotnet/sdk:6.0 AS build WORKDIR /src + +# Copy the project file and restore dependencies COPY ["DamageAssesment.Api.SurveyResponses/DamageAssesment.Api.SurveyResponses.csproj", "DamageAssesment.Api.SurveyResponses/"] RUN dotnet restore "DamageAssesment.Api.SurveyResponses/DamageAssesment.Api.SurveyResponses.csproj" + +# Copy the source code COPY . . + +# Change the working directory to the project directory WORKDIR "/src/DamageAssesment.Api.SurveyResponses" + +# Build the application RUN dotnet build "DamageAssesment.Api.SurveyResponses.csproj" -c Release -o /app/build +# Publish the application FROM build AS publish RUN dotnet publish "DamageAssesment.Api.SurveyResponses.csproj" -c Release -o /app/publish /p:UseAppHost=false +# Set up the final image FROM base AS final WORKDIR /app + +# Copy the published files from the publish stage COPY --from=publish /app/publish . -ENTRYPOINT ["dotnet", "DamageAssesment.Api.SurveyResponses.dll"] \ No newline at end of file + +## Set up the volume and copy the XML comments +#VOLUME /xmlcomments +#COPY ["DamageAssesment.Api.SurveyResponses.xml", "/xmlcomments/DamageAssesment.Api.SurveyResponses.xml"] +# +# Specify the entry point for the container +ENTRYPOINT ["dotnet", "DamageAssesment.Api.SurveyResponses.dll"] 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/appsettings.json b/DamageAssesmentApi/DamageAssesment.Api.SurveyResponses/appsettings.json index 4e7bc46..73c3c3c 100644 --- a/DamageAssesmentApi/DamageAssesment.Api.SurveyResponses/appsettings.json +++ b/DamageAssesmentApi/DamageAssesment.Api.SurveyResponses/appsettings.json @@ -6,16 +6,6 @@ } }, "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" - - //}, "EndPointSettings": { "AnswerUrlBase": "http://damageassesment.api.answers:80", diff --git a/DamageAssesmentApi/DamageAssesment.Api.Surveys/Controllers/SurveysController.cs b/DamageAssesmentApi/DamageAssesment.Api.Surveys/Controllers/SurveysController.cs index eb96f87..0338575 100644 --- a/DamageAssesmentApi/DamageAssesment.Api.Surveys/Controllers/SurveysController.cs +++ b/DamageAssesmentApi/DamageAssesment.Api.Surveys/Controllers/SurveysController.cs @@ -3,7 +3,7 @@ using Microsoft.AspNetCore.Mvc; namespace DamageAssesment.Api.Surveys.Controllers { - [Route("api")] + //[Route("api")] [ApiController] public class SurveysController : ControllerBase { diff --git a/DamageAssesmentApi/DamageAssesment.Api.Surveys/Dockerfile b/DamageAssesmentApi/DamageAssesment.Api.Surveys/Dockerfile index dcf5f8c..4e176b4 100644 --- a/DamageAssesmentApi/DamageAssesment.Api.Surveys/Dockerfile +++ b/DamageAssesmentApi/DamageAssesment.Api.Surveys/Dockerfile @@ -1,9 +1,11 @@ -#See https://aka.ms/customizecontainer to learn how to customize your debug container and how Visual Studio uses this Dockerfile to build your images for faster debugging. +##See https://aka.ms/customizecontainer to learn how to customize your debug container and how Visual Studio uses this Dockerfile to build your images for faster debugging. +# Use the ASP.NET runtime image as the base image FROM mcr.microsoft.com/dotnet/aspnet:6.0 AS base WORKDIR /app EXPOSE 80 +# Use the .NET SDK image for the build stage FROM mcr.microsoft.com/dotnet/sdk:6.0 AS build WORKDIR /src COPY ["DamageAssesment.Api.Surveys/DamageAssesment.Api.Survey.csproj", "DamageAssesment.Api.Surveys/"] @@ -12,10 +14,12 @@ COPY . . WORKDIR "/src/DamageAssesment.Api.Surveys" RUN dotnet build "DamageAssesment.Api.Survey.csproj" -c Release -o /app/build +# Publish the application FROM build AS publish RUN dotnet publish "DamageAssesment.Api.Survey.csproj" -c Release -o /app/publish /p:UseAppHost=false +# Use the ASP.NET runtime image again for the final stage FROM base AS final WORKDIR /app COPY --from=publish /app/publish . -ENTRYPOINT ["dotnet", "DamageAssesment.Api.Survey.dll"] \ No newline at end of file +ENTRYPOINT ["dotnet", "DamageAssesment.Api.Survey.dll"] diff --git a/DamageAssesmentApi/DamageAssesment.Api.UsersAccess/Bases/ServiceProviderBase.cs b/DamageAssesmentApi/DamageAssesment.Api.UsersAccess/Bases/ServiceProviderBase.cs new file mode 100644 index 0000000..799f082 --- /dev/null +++ b/DamageAssesmentApi/DamageAssesment.Api.UsersAccess/Bases/ServiceProviderBase.cs @@ -0,0 +1,21 @@ +namespace DamageAssesment.Api.UsersAccess.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.UsersAccess/Controllers/UsersAccessController.cs b/DamageAssesmentApi/DamageAssesment.Api.UsersAccess/Controllers/UsersAccessController.cs new file mode 100644 index 0000000..5e16362 --- /dev/null +++ b/DamageAssesmentApi/DamageAssesment.Api.UsersAccess/Controllers/UsersAccessController.cs @@ -0,0 +1,97 @@ +using DamageAssesment.Api.UsersAccess.Interfaces; +using DamageAssesment.Api.UsersAccess.Models; +using Microsoft.AspNetCore.Mvc; + +namespace DamageAssesment.Api.UsersAccess.Controllers +{ + [Route("api")] + [ApiController] + public class UsersAccessController : ControllerBase + { + private IUsersAccessProvider userAccessProvider; + + public UsersAccessController(IUsersAccessProvider userAccessProvider) + { + this.userAccessProvider = userAccessProvider; + } + [HttpPost("authenticate")] + public async Task AuthenticateAsync(UserCredentials userCredentials) + { + var result = await userAccessProvider.AuthenticateAsync(userCredentials); + if (result.IsSuccess) + { + return Ok(result.TokenResponse); + } + return Unauthorized(result.ErrorMessage); + } + + [HttpPost("refreshToken")] + public async Task RefreshTokenAsync(TokenResponse tokenResponse) + { + var result = await userAccessProvider.RefreshTokenAsync(tokenResponse); + if (result.IsSuccess) + { + return Ok(result.TokenResponse); + } + return Unauthorized(result.ErrorMessage); + } + + [HttpGet("users")] + public async Task GetUsersAsync() + { + var result = await userAccessProvider.GetUsersAsync(); + if (result.IsSuccess) + { + return Ok(result.Users); + } + return NoContent(); + } + + [HttpGet("users/{Id}")] + public async Task GetUsersAsync(int Id) + { + var result = await userAccessProvider.GetUsersAsync(Id); + if (result.IsSuccess) + { + return Ok(result.User); + } + return NotFound(); + } + + [HttpPost("users")] + public async Task PostUserAsync(User user) + { + var result = await userAccessProvider.PostUserAsync(user); + if (result.IsSuccess) + { + return Ok(result.User); + } + return BadRequest(result.ErrorMessage); + } + + [HttpPut("users/{Id}")] + public async Task PutUserAsync(int Id, User user) + { + var result = await userAccessProvider.PutUserAsync(Id, user); + if (result.IsSuccess) + { + return Ok(result.User); + } + if (result.ErrorMessage == "Not Found") + return NotFound(result.ErrorMessage); + + return BadRequest(result.ErrorMessage); + } + + [HttpDelete("users/{Id}")] + public async Task DeleteSurveysAsync(int Id) + { + var result = await userAccessProvider.DeleteUserAsync(Id); + if (result.IsSuccess) + { + return Ok(result.User); + } + return NotFound(); + } + } +} diff --git a/DamageAssesmentApi/DamageAssesment.Api.UsersAccess/DamageAssesment.Api.UsersAccess.csproj b/DamageAssesmentApi/DamageAssesment.Api.UsersAccess/DamageAssesment.Api.UsersAccess.csproj new file mode 100644 index 0000000..d56ba51 --- /dev/null +++ b/DamageAssesmentApi/DamageAssesment.Api.UsersAccess/DamageAssesment.Api.UsersAccess.csproj @@ -0,0 +1,19 @@ + + + + net6.0 + enable + enable + + + + + + + + + + + + + diff --git a/DamageAssesmentApi/DamageAssesment.Api.UsersAccess/Db/Role.cs b/DamageAssesmentApi/DamageAssesment.Api.UsersAccess/Db/Role.cs new file mode 100644 index 0000000..93e522a --- /dev/null +++ b/DamageAssesmentApi/DamageAssesment.Api.UsersAccess/Db/Role.cs @@ -0,0 +1,21 @@ +using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations.Schema; +using System.Text.Json.Serialization; + +namespace DamageAssesment.Api.UsersAccess.Db +{ + public class Role + { + [Key] + public int Id { get; set; } + + [StringLength(100)] + [Required] + public string Name { get; set; } + + // add a status field + + [StringLength(100)] + public string? Description { get; set; } + } +} diff --git a/DamageAssesmentApi/DamageAssesment.Api.UsersAccess/Db/Token.cs b/DamageAssesmentApi/DamageAssesment.Api.UsersAccess/Db/Token.cs new file mode 100644 index 0000000..cfea1e2 --- /dev/null +++ b/DamageAssesmentApi/DamageAssesment.Api.UsersAccess/Db/Token.cs @@ -0,0 +1,17 @@ +using Microsoft.EntityFrameworkCore.Metadata.Internal; +using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations.Schema; + +namespace DamageAssesment.Api.UsersAccess.Db +{ + public class Token + { + [Key] + public string Id { get; set; } + [Required] + [ForeignKey("User")] + public int UserId { get; set; } + public string? RefreshToken { get; set; } + public bool? IsActive { get; set; } + } +} diff --git a/DamageAssesmentApi/DamageAssesment.Api.UsersAccess/Db/User.cs b/DamageAssesmentApi/DamageAssesment.Api.UsersAccess/Db/User.cs new file mode 100644 index 0000000..d5fc4ee --- /dev/null +++ b/DamageAssesmentApi/DamageAssesment.Api.UsersAccess/Db/User.cs @@ -0,0 +1,27 @@ +using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations.Schema; +using System.Text.Json.Serialization; + +namespace DamageAssesment.Api.UsersAccess.Db +{ + public class User + { + [Key] + public int Id { get; set; } + + [ForeignKey("Employee")] + public string EmployeeId { get; set; } + + [ForeignKey("Role")] + [Required] + public int RoleId { get; set; } + [Required] + public bool? IsActive { get; set; } = true; + + [Required] + public DateTime? CreateDate { get; set; } = DateTime.Now; + + public DateTime? UpdateDate { get; set; } + + } +} diff --git a/DamageAssesmentApi/DamageAssesment.Api.UsersAccess/Db/UsersAccessDbContext.cs b/DamageAssesmentApi/DamageAssesment.Api.UsersAccess/Db/UsersAccessDbContext.cs new file mode 100644 index 0000000..a46a10d --- /dev/null +++ b/DamageAssesmentApi/DamageAssesment.Api.UsersAccess/Db/UsersAccessDbContext.cs @@ -0,0 +1,17 @@ +using Microsoft.EntityFrameworkCore; + +namespace DamageAssesment.Api.UsersAccess.Db +{ + public class UsersAccessDbContext:DbContext + { + public DbSet Users { get; set; } + public DbSet Roles { get; set; } + public DbSet Tokens { get; set; } + public UsersAccessDbContext(DbContextOptions options) : base(options) + { + + } + + + } +} diff --git a/DamageAssesmentApi/DamageAssesment.Api.UsersAccess/Interfaces/IEmployeeServiceProvider.cs b/DamageAssesmentApi/DamageAssesment.Api.UsersAccess/Interfaces/IEmployeeServiceProvider.cs new file mode 100644 index 0000000..fc35b00 --- /dev/null +++ b/DamageAssesmentApi/DamageAssesment.Api.UsersAccess/Interfaces/IEmployeeServiceProvider.cs @@ -0,0 +1,10 @@ +using DamageAssesment.Api.UsersAccess.Models; + +namespace DamageAssesment.Api.UsersAccess.Interfaces +{ + public interface IEmployeeServiceProvider + { + Task> getEmployeesAsync(); + Task getEmployeeAsync(string employeeID); + } +} diff --git a/DamageAssesmentApi/DamageAssesment.Api.UsersAccess/Interfaces/IRoleProvider.cs b/DamageAssesmentApi/DamageAssesment.Api.UsersAccess/Interfaces/IRoleProvider.cs new file mode 100644 index 0000000..6ca0209 --- /dev/null +++ b/DamageAssesmentApi/DamageAssesment.Api.UsersAccess/Interfaces/IRoleProvider.cs @@ -0,0 +1,12 @@ +namespace DamageAssesment.Api.UsersAccess.Interfaces +{ + public interface IRoleProvider + { + Task<(bool IsSuccess, IEnumerable< Models.Role> Roles, string ErrorMessage)> GetRolesAsync(); + Task<(bool IsSuccess, Models.Role Roles, string ErrorMessage)> GetRolesAsync(int Id); + Task<(bool IsSuccess, Models.Role Role, string ErrorMessage)> PostRoleAsync(Models.Role Role); + Task<(bool IsSuccess, Models.Role Role, string ErrorMessage)> PutRoleAsync(int Id,Models.Role Role); + Task<(bool IsSuccess, Models.Role Role, string ErrorMessage)> DeleteRoleAsync(int Id); + + } +} diff --git a/DamageAssesmentApi/DamageAssesment.Api.UsersAccess/Interfaces/ITokenServiceProvider.cs b/DamageAssesmentApi/DamageAssesment.Api.UsersAccess/Interfaces/ITokenServiceProvider.cs new file mode 100644 index 0000000..58574b7 --- /dev/null +++ b/DamageAssesmentApi/DamageAssesment.Api.UsersAccess/Interfaces/ITokenServiceProvider.cs @@ -0,0 +1,11 @@ +using DamageAssesment.Api.UsersAccess.Models; +using System.Security.Claims; + +namespace DamageAssesment.Api.UsersAccess.Interfaces +{ + public interface ITokenServiceProvider + { + Task GenerateToken(User user); + Task TokenAuthenticate(User user, Claim[] claims); + } +} \ No newline at end of file diff --git a/DamageAssesmentApi/DamageAssesment.Api.UsersAccess/Interfaces/IUsersAccessProvider.cs b/DamageAssesmentApi/DamageAssesment.Api.UsersAccess/Interfaces/IUsersAccessProvider.cs new file mode 100644 index 0000000..7e39e11 --- /dev/null +++ b/DamageAssesmentApi/DamageAssesment.Api.UsersAccess/Interfaces/IUsersAccessProvider.cs @@ -0,0 +1,16 @@ +using DamageAssesment.Api.UsersAccess.Models; + +namespace DamageAssesment.Api.UsersAccess.Interfaces +{ + public interface IUsersAccessProvider + { + public Task<(bool IsSuccess, IEnumerable< Models.User> Users, string ErrorMessage)> GetUsersAsync(); + public Task<(bool IsSuccess, Models.User User, string ErrorMessage)> GetUsersAsync(int Id); + public Task<(bool IsSuccess, Models.User User, string ErrorMessage)> PostUserAsync(Models.User User); + public Task<(bool IsSuccess, Models.User User, string ErrorMessage)> PutUserAsync(int Id,Models.User User); + public Task<(bool IsSuccess, Models.User User, string ErrorMessage)> DeleteUserAsync(int Id); + public Task<(bool IsSuccess, IEnumerable Roles, string ErrorMessage)> GetRolesAsync(); + public Task<(bool IsSuccess, Models.TokenResponse TokenResponse, string ErrorMessage)> AuthenticateAsync(UserCredentials userCredentials); + public Task<(bool IsSuccess, Models.TokenResponse TokenResponse, string ErrorMessage)>RefreshTokenAsync(TokenResponse tokenResponse); + } +} diff --git a/DamageAssesmentApi/DamageAssesment.Api.UsersAccess/Models/Employee.cs b/DamageAssesmentApi/DamageAssesment.Api.UsersAccess/Models/Employee.cs new file mode 100644 index 0000000..e14f27d --- /dev/null +++ b/DamageAssesmentApi/DamageAssesment.Api.UsersAccess/Models/Employee.cs @@ -0,0 +1,21 @@ +using System.ComponentModel.DataAnnotations; + +namespace DamageAssesment.Api.UsersAccess.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.UsersAccess/Models/JwtSettings.cs b/DamageAssesmentApi/DamageAssesment.Api.UsersAccess/Models/JwtSettings.cs new file mode 100644 index 0000000..3f9dadf --- /dev/null +++ b/DamageAssesmentApi/DamageAssesment.Api.UsersAccess/Models/JwtSettings.cs @@ -0,0 +1,9 @@ +using System.ComponentModel.DataAnnotations; +namespace DamageAssesment.Api.UsersAccess.Models +{ + + public class JwtSettings + { + public string securitykey { get; set; } + } +} \ No newline at end of file diff --git a/DamageAssesmentApi/DamageAssesment.Api.UsersAccess/Models/Role.cs b/DamageAssesmentApi/DamageAssesment.Api.UsersAccess/Models/Role.cs new file mode 100644 index 0000000..809e677 --- /dev/null +++ b/DamageAssesmentApi/DamageAssesment.Api.UsersAccess/Models/Role.cs @@ -0,0 +1,9 @@ +using System.ComponentModel.DataAnnotations; +namespace DamageAssesment.Api.UsersAccess.Models +{ + public class Role { + public int Id { get; set; } + public string Name { get; set; } + public string? Description { get; set; } + } +} diff --git a/DamageAssesmentApi/DamageAssesment.Api.UsersAccess/Models/Token.cs b/DamageAssesmentApi/DamageAssesment.Api.UsersAccess/Models/Token.cs new file mode 100644 index 0000000..9c46d81 --- /dev/null +++ b/DamageAssesmentApi/DamageAssesment.Api.UsersAccess/Models/Token.cs @@ -0,0 +1,10 @@ +namespace DamageAssesment.Api.UsersAccess.Models +{ + public class Token + { + public string Id { get; set; } + public int UserId { get; set; } + public string? RefreshToken { get; set; } + public bool? IsActive { get; set; } + } +} diff --git a/DamageAssesmentApi/DamageAssesment.Api.UsersAccess/Models/TokenResponse.cs b/DamageAssesmentApi/DamageAssesment.Api.UsersAccess/Models/TokenResponse.cs new file mode 100644 index 0000000..4d0b6da --- /dev/null +++ b/DamageAssesmentApi/DamageAssesment.Api.UsersAccess/Models/TokenResponse.cs @@ -0,0 +1,8 @@ +namespace DamageAssesment.Api.UsersAccess.Models +{ + public class TokenResponse + { + public string? jwttoken { get; set; } + public string? refreshtoken { get; set; } + } +} \ No newline at end of file diff --git a/DamageAssesmentApi/DamageAssesment.Api.UsersAccess/Models/User.cs b/DamageAssesmentApi/DamageAssesment.Api.UsersAccess/Models/User.cs new file mode 100644 index 0000000..f3c9971 --- /dev/null +++ b/DamageAssesmentApi/DamageAssesment.Api.UsersAccess/Models/User.cs @@ -0,0 +1,12 @@ +namespace DamageAssesment.Api.UsersAccess.Models +{ + public class User + { + public int Id { get; set; } + public string EmployeeId { get; set; } + public int RoleId { get; set; } + public bool? IsActive { get; set; } + public DateTime? CreateDate { get; set; } + public DateTime? UpdateDate { get; set; } + } +} diff --git a/DamageAssesmentApi/DamageAssesment.Api.UsersAccess/Models/UserCredentials.cs b/DamageAssesmentApi/DamageAssesment.Api.UsersAccess/Models/UserCredentials.cs new file mode 100644 index 0000000..a23a43b --- /dev/null +++ b/DamageAssesmentApi/DamageAssesment.Api.UsersAccess/Models/UserCredentials.cs @@ -0,0 +1,5 @@ +public class UserCredentials +{ + public string? username { get; set; } + // public string? password { get; set; } +} \ No newline at end of file diff --git a/DamageAssesmentApi/DamageAssesment.Api.UsersAccess/Profiles/UsersAccessProfile.cs b/DamageAssesmentApi/DamageAssesment.Api.UsersAccess/Profiles/UsersAccessProfile.cs new file mode 100644 index 0000000..bf744eb --- /dev/null +++ b/DamageAssesmentApi/DamageAssesment.Api.UsersAccess/Profiles/UsersAccessProfile.cs @@ -0,0 +1,14 @@ +namespace DamageAssesment.Api.UsersAccess.Profiles +{ + public class UsersAccessProfile : AutoMapper.Profile + { + public UsersAccessProfile() + { + CreateMap(); + CreateMap(); + + CreateMap(); + CreateMap(); + } + } +} diff --git a/DamageAssesmentApi/DamageAssesment.Api.UsersAccess/Program.cs b/DamageAssesmentApi/DamageAssesment.Api.UsersAccess/Program.cs new file mode 100644 index 0000000..a7fb1ac --- /dev/null +++ b/DamageAssesmentApi/DamageAssesment.Api.UsersAccess/Program.cs @@ -0,0 +1,77 @@ +using DamageAssesment.Api.UsersAccess.Db; +using DamageAssesment.Api.UsersAccess.Interfaces; +using DamageAssesment.Api.UsersAccess.Providers; +using DamageAssesment.Api.UsersAccess.Models; +using Microsoft.AspNetCore.Authentication.JwtBearer; +using Microsoft.EntityFrameworkCore; +using Microsoft.IdentityModel.Tokens; +using System.Text; +using Polly; +using DamageAssesment.Api.SurveyResponses.Providers; + +const int maxApiCallRetries = 3; +const int intervalToRetry = 2; //2 seconds +const int maxRetryForCircuitBraker = 5; +const int intervalForCircuitBraker = 5; //5 seconds + +var builder = WebApplication.CreateBuilder(args); + +// Add services to the container. +var authkey = builder.Configuration.GetValue("JwtSettings:securitykey"); +builder.Services.AddAuthentication(item => +{ + item.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme; + item.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme; +}).AddJwtBearer(item => +{ + item.RequireHttpsMetadata = true; + item.SaveToken = true; + item.TokenValidationParameters = new TokenValidationParameters() + { + ValidateIssuerSigningKey = true, + IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(authkey)), + ValidateIssuer = false, + ValidateAudience = false, + ClockSkew = TimeSpan.Zero + }; +}); + +var _jwtsettings = builder.Configuration.GetSection("JwtSettings"); +builder.Services.Configure(_jwtsettings); + + + +builder.Services.AddHttpClient(). + AddTransientHttpErrorPolicy(policy => policy.WaitAndRetryAsync(maxApiCallRetries, _ => TimeSpan.FromSeconds(intervalToRetry))). + AddTransientHttpErrorPolicy(policy => policy.CircuitBreakerAsync(maxRetryForCircuitBraker, TimeSpan.FromSeconds(intervalForCircuitBraker))); + +builder.Services.AddControllers(); +// Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle +builder.Services.AddScoped(); +builder.Services.AddScoped(); +builder.Services.AddAutoMapper(AppDomain.CurrentDomain.GetAssemblies()); +builder.Services.AddEndpointsApiExplorer(); +builder.Services.AddSwaggerGen(); +builder.Services.AddDbContext(option => +{ + option.UseInMemoryDatabase("UsersAccess"); +}); + + + + +var app = builder.Build(); + +// Configure the HTTP request pipeline. +if (app.Environment.IsDevelopment()) +{ + app.UseSwagger(); + app.UseSwaggerUI(); +} + +app.UseAuthentication(); +app.UseAuthorization(); + +app.MapControllers(); + +app.Run(); diff --git a/DamageAssesmentApi/DamageAssesment.Api.UsersAccess/Properties/launchSettings.json b/DamageAssesmentApi/DamageAssesment.Api.UsersAccess/Properties/launchSettings.json new file mode 100644 index 0000000..859e680 --- /dev/null +++ b/DamageAssesmentApi/DamageAssesment.Api.UsersAccess/Properties/launchSettings.json @@ -0,0 +1,31 @@ +{ + "$schema": "https://json.schemastore.org/launchsettings.json", + "iisSettings": { + "windowsAuthentication": false, + "anonymousAuthentication": true, + "iisExpress": { + "applicationUrl": "http://localhost:28382", + "sslPort": 0 + } + }, + "profiles": { + "DamageAssesment.Api.Users": { + "commandName": "Project", + "dotnetRunMessages": true, + "launchBrowser": true, + "launchUrl": "swagger", + "applicationUrl": "http://localhost:5027", + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development" + } + }, + "IIS Express": { + "commandName": "IISExpress", + "launchBrowser": true, + "launchUrl": "swagger", + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development" + } + } + } +} diff --git a/DamageAssesmentApi/DamageAssesment.Api.UsersAccess/Providers/EmployeeServiceProvider.cs b/DamageAssesmentApi/DamageAssesment.Api.UsersAccess/Providers/EmployeeServiceProvider.cs new file mode 100644 index 0000000..ace59ee --- /dev/null +++ b/DamageAssesmentApi/DamageAssesment.Api.UsersAccess/Providers/EmployeeServiceProvider.cs @@ -0,0 +1,58 @@ +using DamageAssesment.Api.UsersAccess.Bases; +using DamageAssesment.Api.UsersAccess.Interfaces; +using DamageAssesment.Api.UsersAccess.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.UsersAccess/Providers/TokenServiceProvider.cs b/DamageAssesmentApi/DamageAssesment.Api.UsersAccess/Providers/TokenServiceProvider.cs new file mode 100644 index 0000000..a77d6bc --- /dev/null +++ b/DamageAssesmentApi/DamageAssesment.Api.UsersAccess/Providers/TokenServiceProvider.cs @@ -0,0 +1,57 @@ +using System.IdentityModel.Tokens.Jwt; +using System.Security.Claims; +using System.Security.Cryptography; +using System.Text; +using DamageAssesment.Api.UsersAccess.Db; +using DamageAssesment.Api.UsersAccess.Interfaces; +using DamageAssesment.Api.UsersAccess.Models; +using Microsoft.EntityFrameworkCore; +using Microsoft.Extensions.Options; +using Microsoft.IdentityModel.Tokens; + +public class TokenServiceProvider : ITokenServiceProvider +{ + private readonly UsersAccessDbContext usersAccessDbContext; + private readonly JwtSettings jwtSettings; + public TokenServiceProvider(IOptions options,UsersAccessDbContext usersAccessDbContext) + { + this.usersAccessDbContext = usersAccessDbContext; + this.jwtSettings = options.Value; + } + public async Task GenerateToken(DamageAssesment.Api.UsersAccess.Models.User user) + { + var randomnumber = new byte[32]; + using (var ramdomnumbergenerator = RandomNumberGenerator.Create()) + { + ramdomnumbergenerator.GetBytes(randomnumber); + string refreshtoken = Convert.ToBase64String(randomnumber); + var token = await usersAccessDbContext.Tokens.FirstOrDefaultAsync(item => item.UserId == user.Id); + if (token != null) + { + token.RefreshToken = refreshtoken; + } + else + { + usersAccessDbContext.Tokens.Add(new DamageAssesment.Api.UsersAccess.Db.Token() + { + Id = new Random().Next().ToString(), + UserId = user.Id, + RefreshToken = refreshtoken, + IsActive = true + }); + } + await usersAccessDbContext.SaveChangesAsync(); + + return refreshtoken; + } + } + + public async Task TokenAuthenticate(DamageAssesment.Api.UsersAccess.Models.User user, Claim[] claims) + { + var token = new JwtSecurityToken(claims: claims, expires: DateTime.Now.AddSeconds(20), + signingCredentials: new SigningCredentials(new SymmetricSecurityKey(Encoding.UTF8.GetBytes(jwtSettings.securitykey)), SecurityAlgorithms.HmacSha256) + ); + var jwttoken = new JwtSecurityTokenHandler().WriteToken(token); + return new TokenResponse() { jwttoken = jwttoken, refreshtoken = await GenerateToken(user) }; + } +} \ No newline at end of file diff --git a/DamageAssesmentApi/DamageAssesment.Api.UsersAccess/Providers/UserAccessProvider.cs b/DamageAssesmentApi/DamageAssesment.Api.UsersAccess/Providers/UserAccessProvider.cs new file mode 100644 index 0000000..6188d92 --- /dev/null +++ b/DamageAssesmentApi/DamageAssesment.Api.UsersAccess/Providers/UserAccessProvider.cs @@ -0,0 +1,341 @@ +using AutoMapper; +using DamageAssesment.Api.UsersAccess.Db; +using DamageAssesment.Api.UsersAccess.Interfaces; +using DamageAssesment.Api.UsersAccess.Models; +using Microsoft.EntityFrameworkCore; +using Microsoft.Extensions.Options; +using Microsoft.IdentityModel.Tokens; +using System.Data; +using System.IdentityModel.Tokens.Jwt; +using System.Security.Claims; +using System.Text; + +namespace DamageAssesment.Api.UsersAccess.Providers +{ + public class UsersAccessProvider : IUsersAccessProvider + { + private readonly UsersAccessDbContext userAccessDbContext; + private readonly ILogger logger; + private readonly IMapper mapper; + private readonly IEmployeeServiceProvider employeeServiceProvider; + private readonly JwtSettings jwtSettings; + private readonly ITokenServiceProvider tokenServiceProvider; + + public UsersAccessProvider(IOptions options, ITokenServiceProvider tokenServiceProvider, UsersAccessDbContext userAccessDbContext, IEmployeeServiceProvider employeeServiceProvider, ILogger logger, IMapper mapper) + { + this.userAccessDbContext = userAccessDbContext; + this.employeeServiceProvider = employeeServiceProvider; + this.logger = logger; + this.mapper = mapper; + jwtSettings = options.Value; + this.tokenServiceProvider = tokenServiceProvider; + seedData(); + } + + private void seedData() + { + if (!userAccessDbContext.Users.Any()) + { + userAccessDbContext.Users.Add(new Db.User { Id = 1, EmployeeId = "Emp1", RoleId = 1 }); + userAccessDbContext.Users.Add(new Db.User { Id = 2, EmployeeId = "Emp2", RoleId = 2 }); + userAccessDbContext.Users.Add(new Db.User { Id = 3, EmployeeId = "Emp3", RoleId = 3 }); + userAccessDbContext.SaveChanges(); + } + + if (!userAccessDbContext.Roles.Any()) + { + userAccessDbContext.Roles.Add(new Db.Role { Id = 1, Name = "admin" }); + userAccessDbContext.Roles.Add(new Db.Role { Id = 2, Name = "user" }); + userAccessDbContext.Roles.Add(new Db.Role { Id = 3, Name = "survey" }); + userAccessDbContext.Roles.Add(new Db.Role { Id = 4, Name = "report" }); + userAccessDbContext.Roles.Add(new Db.Role { Id = 5, Name = "document" }); + userAccessDbContext.SaveChanges(); + } + } + + public async Task<(bool IsSuccess, IEnumerable Users, string ErrorMessage)> GetUsersAsync() + { + try + { + logger?.LogInformation("Gell all Users from DB"); + var users = await userAccessDbContext.Users.ToListAsync(); + if (users != null) + { + logger?.LogInformation($"{users.Count} Items(s) found"); + var result = mapper.Map, IEnumerable>(users); + 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.User User, string ErrorMessage)> GetUsersAsync(int Id) + { + try + { + logger?.LogInformation("Querying Users table"); + var user = await userAccessDbContext.Users.SingleOrDefaultAsync(s => s.Id == Id); + if (user != null) + { + logger?.LogInformation($"User Id: {Id} found"); + var result = mapper.Map(user); + 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.User User, string ErrorMessage)> PostUserAsync(Models.User user) + { + try + { + if (user != null) + { + var users = await userAccessDbContext.Users.ToListAsync(); + int count = users.Where(u => u.EmployeeId == user.EmployeeId).Count(); + if (count == 0) + { + user.Id = users.Count + 1; + userAccessDbContext.Users.Add(mapper.Map(user)); + await userAccessDbContext.SaveChangesAsync(); + return (true, user, "Successful"); + } + else + { + logger?.LogInformation($"Employee Id: {user.EmployeeId} is already exist"); + return (false, null, $"Employee Id: {user.EmployeeId} is already exist"); + } + } + else + { + logger?.LogInformation($"Employee Id: {user.EmployeeId} cannot be added"); + return (false, null, $"Employee Id: {user.EmployeeId} cannot be added"); + } + } + catch (Exception ex) + { + logger?.LogError(ex.ToString()); + return (false, null, ex.Message); + } + } + + public async Task<(bool IsSuccess, Models.User User, string ErrorMessage)> PutUserAsync(int Id, Models.User user) + { + try + { + if (user != null) + { + var _user = await userAccessDbContext.Users.Where(s => s.Id == Id).SingleOrDefaultAsync(); + + if (_user != null) + { + int count = userAccessDbContext.Users.Where(u => u.Id != user.Id && u.EmployeeId == user.EmployeeId).Count(); + if (count == 0) + { + _user.EmployeeId = user.EmployeeId; + _user.RoleId = user.RoleId; + _user.IsActive = user.IsActive; + _user.UpdateDate = DateTime.Now; + await userAccessDbContext.SaveChangesAsync(); + + + logger?.LogInformation($"Employee Id: {user.EmployeeId} updated successfuly"); + return (true, mapper.Map(_user), $"Employee Id: {_user.EmployeeId} updated successfuly"); + } + else + { + logger?.LogInformation($"Employee Id: {user.EmployeeId} is already exist"); + return (false, null, $"Employee Id: {user.EmployeeId} is already exist"); + } + } + else + { + logger?.LogInformation($"User Id : {Id} Not found"); + return (false, null, "Not Found"); + } + } + else + { + logger?.LogInformation($"User 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.User User, string ErrorMessage)> DeleteUserAsync(int Id) + { + try + { + var user = await userAccessDbContext.Users.Where(x => x.Id == Id).SingleOrDefaultAsync(); + + if (user != null) + { + userAccessDbContext.Users.Remove(user); + await userAccessDbContext.SaveChangesAsync(); + logger?.LogInformation($"User Id: {Id} deleted Successfuly"); + return (true, mapper.Map(user), $"User Id: {Id} deleted Successfuly"); + } + else + { + logger?.LogInformation($"User Id : {Id} Not found"); + return (false, null, "Not Found"); + } + } + catch (Exception ex) + { + logger?.LogError(ex.ToString()); + return (false, null, ex.Message); + } + } + + public async Task<(bool IsSuccess, TokenResponse TokenResponse, string ErrorMessage)> AuthenticateAsync(UserCredentials userCredentials) + { + + if (userCredentials != null) + { + //implementation for dadeschools authentication + + var employee = await employeeServiceProvider.getEmployeeAsync(userCredentials.username); + + if (employee != null) + { + var result = await GetUsersAsync(); + + if (result.IsSuccess) + { + var user = result.Users.Where(x => x.IsActive == true && x.EmployeeId.ToLower().Equals(userCredentials.username.ToLower())).SingleOrDefault(); + + if (user != null) + { + + var r = await GetRolesAsync(); + var role = r.Roles.Where(x => x.Id == user.RoleId).SingleOrDefault(); + + var authClaims = new List { + new Claim(ClaimTypes.Name, user.EmployeeId), + new Claim(ClaimTypes.Role, role.Name), + new Claim(JwtRegisteredClaimNames.Jti,Guid.NewGuid().ToString()) + + }; + + /// Generate Token + var tokenhandler = new JwtSecurityTokenHandler(); + var tokenkey = Encoding.UTF8.GetBytes(jwtSettings.securitykey); + var tokendesc = new SecurityTokenDescriptor + { + Audience = "", + NotBefore = DateTime.Now, + Subject = new ClaimsIdentity(authClaims), + Expires = DateTime.Now.AddMinutes(30), + SigningCredentials = new SigningCredentials(new SymmetricSecurityKey(tokenkey), SecurityAlgorithms.HmacSha256) + }; + var token = tokenhandler.CreateToken(tokendesc); + string finaltoken = tokenhandler.WriteToken(token); + + var response = new TokenResponse() { jwttoken = finaltoken, refreshtoken = await tokenServiceProvider.GenerateToken(user) }; + + + return (true, response, "Authentication success and token issued."); + + } + else + { + return (false, null, "user inactive or not exist."); + } + } + else + { + return (false, null, "users list empty."); + } + } + else + { + return (false, null, "Employee not exist."); + } + } + else + { + return (false, null, "Credentials are required to authenticate."); + + } + + } + public async Task<(bool IsSuccess, IEnumerable Roles, string ErrorMessage)> GetRolesAsync() + { + try + { + logger?.LogInformation("Gell all Roles from DB"); + var roles = await userAccessDbContext.Roles.ToListAsync(); + if (roles != null) + { + logger?.LogInformation($"{roles.Count} Items(s) found"); + var result = mapper.Map, IEnumerable>(roles); + 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.TokenResponse TokenResponse, string ErrorMessage)> RefreshTokenAsync(TokenResponse tokenResponse) + { + //Generate token + var tokenhandler = new JwtSecurityTokenHandler(); + var tokenkey = Encoding.UTF8.GetBytes(this.jwtSettings.securitykey); + SecurityToken securityToken; + var principal = tokenhandler.ValidateToken(tokenResponse.jwttoken, new TokenValidationParameters + { + ValidateIssuerSigningKey = true, + IssuerSigningKey = new SymmetricSecurityKey(tokenkey), + ValidateIssuer = false, + ValidateAudience = false, + + }, out securityToken); + + var token = securityToken as JwtSecurityToken; + if (token != null && !token.Header.Alg.Equals(SecurityAlgorithms.HmacSha256)) + { + return (false, null, "Unauthorized"); + } + var username = principal.Identity?.Name; + + var tokens = await userAccessDbContext.Tokens.ToListAsync(); + var users = await userAccessDbContext.Users.ToListAsync(); + + var user = (from u in users + join t in tokens + on u.Id equals t.UserId + where u.EmployeeId == username + && t.RefreshToken == tokenResponse.refreshtoken + select u).FirstOrDefault(); + + if (user == null) + return (false, null, "Invalid Token Response object provided"); + + var _user = mapper.Map(user); + var response = tokenServiceProvider.TokenAuthenticate(_user, principal.Claims.ToArray()).Result; + return (true, response, "Token authenticated and refreshed."); + } + + + } +} diff --git a/DamageAssesmentApi/DamageAssesment.Api.UsersAccess/appsettings.json b/DamageAssesmentApi/DamageAssesment.Api.UsersAccess/appsettings.json new file mode 100644 index 0000000..4a1b1b5 --- /dev/null +++ b/DamageAssesmentApi/DamageAssesment.Api.UsersAccess/appsettings.json @@ -0,0 +1,15 @@ +{ + "JwtSettings": { + "securitykey": "bWlhbWkgZGFkZSBzY2hvb2xzIHNlY3JldCBrZXk=" + }, + "Logging": { + "LogLevel": { + "Default": "Information", + "Microsoft.AspNetCore": "Warning" + } + }, + "EndPointSettings": { + "EmployeeUrlBase": "http://localhost:5135" + }, + "AllowedHosts": "*" +} diff --git a/DamageAssesmentApi/default-local.conf b/DamageAssesmentApi/default-local.conf deleted file mode 100644 index c0db4a3..0000000 --- a/DamageAssesmentApi/default-local.conf +++ /dev/null @@ -1,45 +0,0 @@ - - - -server { - - listen 80; - server_name dev-services.damageasessment.net; - - location /service1 { - - rewrite /service1/(.*) /$1 break; - proxy_pass http://localhost:80/; # Replace with the address of your .NET Core application - } - location /service2 { - - rewrite /service2/(.*) /$1 break; - proxy_pass http://localhost:80/; # Replace with the address of your .NET Core application - } - location /service3 { - - rewrite /service3/(.*) /$1 break; - proxy_pass http://localhost:80/; # Replace with the address of your .NET Core application - } - location /service4 { - - rewrite /service4/(.*) /$1 break; - proxy_pass http://localhost:80/; # Replace with the address of your .NET Core application - } - location /service5 { - - rewrite /service5/(.*) /$1 break; - proxy_pass http://localhost:80/; # Replace with the address of your .NET Core application - } - location /service6 { - - rewrite /service6/(.*) /$1 break; - proxy_pass http://localhost:80/; # Replace with the address of your .NET Core application - } - location /service7 { - - rewrite /service7/(.*) /$1 break; - proxy_pass http://localhost:80/; # Replace with the address of your .NET Core application - } - -} diff --git a/DamageAssesmentApi/default_Local.conf b/DamageAssesmentApi/default_Local.conf new file mode 100644 index 0000000..6e04779 --- /dev/null +++ b/DamageAssesmentApi/default_Local.conf @@ -0,0 +1,49 @@ + + + +server { + + listen 80 default_server; + # server_name _; + root /var/www/html; + + # Add index.php to the list if you are using PHP + # index index.html index.htm index.nginx-debian.html; + + location /service1 { + + rewrite /service1/(.*) /$1 break; + proxy_pass http://127.0.0.1:6001/; # Replace with the address of your .NET Core application + } + location /service2 { + + rewrite /service2/(.*) /$1 break; + proxy_pass http://127.0.0.1:6002/; # Replace with the address of your .NET Core application + } + location /service3 { + + rewrite /service3/(.*) /$1 break; + proxy_pass http://127.0.0.1:6003/; # Replace with the address of your .NET Core application + } + location /service4 { + + rewrite /service4/(.*) /$1 break; + proxy_pass http://127.0.0.1:6004/; # Replace with the address of your .NET Core application + } + location /service5 { + + rewrite /service5/(.*) /$1 break; + proxy_pass http://127.0.0.1:6005/; # Replace with the address of your .NET Core application + } + location /service6 { + + rewrite /service6/(.*) /$1 break; + proxy_pass http://127.0.0.1:6006/; # Replace with the address of your .NET Core application + } + location /service7 { + + rewrite /service7/(.*) /$1 break; + proxy_pass http://127.0.0.1:6007/; # Replace with the address of your .NET Core application + } + +} diff --git a/DamageAssesmentApi/docker-compose.dcproj b/DamageAssesmentApi/docker-compose.dcproj index 325679e..ba3eaf4 100644 --- a/DamageAssesmentApi/docker-compose.dcproj +++ b/DamageAssesmentApi/docker-compose.dcproj @@ -9,13 +9,12 @@ damageassesment.api.answers - + docker-compose.yml - \ No newline at end of file diff --git a/DamageAssesmentApi/docker-compose.override.yml b/DamageAssesmentApi/docker-compose.override.yml index 4f1bab1..3d878dd 100644 --- a/DamageAssesmentApi/docker-compose.override.yml +++ b/DamageAssesmentApi/docker-compose.override.yml @@ -1,58 +1,53 @@ version: '3.4' services: - nginx: - container_name: my-nginx - image: nginx:latest - restart: always - ports: - - "80:80" - volumes: - - ./default.conf:/etc/nginx/conf.d/default-local.conf - #- ./certs:/etc/nginx/certs - #- ./error.log:/var/log/nginx/error.log + #nginx: + # container_name: my-nginx + # image: nginx:latest + # restart: always + # ports: + # - "80:80" + # volumes: + # - ./default.conf:/etc/nginx/conf.d/default.conf damageassesment.api.answers: environment: - ASPNETCORE_ENVIRONMENT=Development ports: - - "80" + - "6001:80" + damageassesment.api.attachments: environment: - ASPNETCORE_ENVIRONMENT=Development ports: - - "80" - + - "6002:80" + damageassesment.api.employees: environment: - ASPNETCORE_ENVIRONMENT=Development ports: - - "80" - - + - "6003:80" + damageassesment.api.locations: environment: - ASPNETCORE_ENVIRONMENT=Development ports: - - "80" - - + - "6004:80" + damageassesment.api.questions: environment: - ASPNETCORE_ENVIRONMENT=Development ports: - - "80" - - + - "6005:80" + damageassesment.api.survey: environment: - ASPNETCORE_ENVIRONMENT=Development ports: - - "80" - - + - "6006:80" + damageassesment.api.surveyresponses: environment: - ASPNETCORE_ENVIRONMENT=Development @@ -63,5 +58,5 @@ services: - services__Attachments=http://damageassesment.api.attachments:80 - services__Surveys=http://damageassesment.api.survey:80 ports: - - "80" - + - "6007:80" + \ No newline at end of file diff --git a/DamageAssesmentApi/nginx.conf b/DamageAssesmentApi/nginx.conf deleted file mode 100644 index 13145bc..0000000 --- a/DamageAssesmentApi/nginx.conf +++ /dev/null @@ -1,86 +0,0 @@ -user www-data; -worker_processes auto; -pid /run/nginx.pid; -include /etc/nginx/modules-enabled/*.conf; - -events { - worker_connections 768; - # multi_accept on; -} - -http { - - ## - # Basic Settings - ## - - sendfile on; - tcp_nopush on; - tcp_nodelay on; - keepalive_timeout 65; - types_hash_max_size 2048; - # server_tokens off; - - # server_names_hash_bucket_size 64; - # server_name_in_redirect off; - - include /etc/nginx/mime.types; - default_type application/octet-stream; - - ## - # SSL Settings - ## - - ssl_protocols TLSv1 TLSv1.1 TLSv1.2 TLSv1.3; # Dropping SSLv3, ref: POODLE - ssl_prefer_server_ciphers on; - - ## - # Logging Settings - ## - - access_log /var/log/nginx/access.log; - error_log /var/log/nginx/error.log; - - ## - # Gzip Settings - ## - - gzip on; - - # gzip_vary on; - # gzip_proxied any; - # gzip_comp_level 6; - # gzip_buffers 16 8k; - # gzip_http_version 1.1; - # gzip_types text/plain text/css application/json application/javascript text/xml application/xml application/xml+rss text/javascript; - - ## - # Virtual Host Configs - ## - - #include /etc/nginx/conf.d/*.conf; - #include /etc/nginx/sites-enabled/*; - include /etc/nginx/sites-available/*; -} - - -#mail { -# # See sample authentication script at: -# # http://wiki.nginx.org/ImapAuthenticateWithApachePhpScript -# -# # auth_http localhost/auth.php; -# # pop3_capabilities "TOP" "USER"; -# # imap_capabilities "IMAP4rev1" "UIDPLUS"; -# -# server { -# listen localhost:110; -# protocol pop3; -# proxy on; -# } -# -# server { -# listen localhost:143; -# protocol imap; -# proxy on; -# } -#}