diff --git a/DamageAssesmentApi/DamageAssesment.Api.Answers/Controllers/AnswersController.cs b/DamageAssesmentApi/DamageAssesment.Api.Answers/Controllers/AnswersController.cs index fe225b6..8130de4 100644 --- a/DamageAssesmentApi/DamageAssesment.Api.Answers/Controllers/AnswersController.cs +++ b/DamageAssesmentApi/DamageAssesment.Api.Answers/Controllers/AnswersController.cs @@ -1,7 +1,6 @@ using DamageAssesment.Api.Answers.Interfaces; +using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; -using Microsoft.EntityFrameworkCore; -using Microsoft.OpenApi.Any; namespace DamageAssesment.Api.Answers.Controllers { @@ -16,7 +15,7 @@ namespace DamageAssesment.Api.Answers.Controllers /// /// Get all answers /// - + [Authorize(Roles = "admin")] [HttpGet("answers")] public async Task GetAnswersAsync() { @@ -32,7 +31,7 @@ namespace DamageAssesment.Api.Answers.Controllers /// Get an answer based on answerId. /// - + [Authorize(Roles = "admin")] [HttpGet("answers/{id}")] public async Task GetAnswerByIdAsync(int id) { @@ -48,6 +47,7 @@ namespace DamageAssesment.Api.Answers.Controllers /// /// Get all answers based on responseId. /// + [Authorize(Roles = "admin")] [HttpGet("answers/byresponse/{responseid}")] public async Task GetAnswersByResponseId(int responseid) { @@ -61,7 +61,7 @@ namespace DamageAssesment.Api.Answers.Controllers /// /// Get all answers based on questionId. /// - + [Authorize(Roles = "admin")] [HttpGet("answers/byquestion/{questionid}")] public async Task AnswersByQuestionId(int questionid) { @@ -75,7 +75,7 @@ namespace DamageAssesment.Api.Answers.Controllers /// /// Update an existing answer. /// - + [Authorize(Roles = "admin")] [HttpPut("answers")] public async Task UpdateAnswer(Models.Answer answer) { @@ -96,7 +96,7 @@ namespace DamageAssesment.Api.Answers.Controllers /// /// Save a new answer. /// - + [Authorize(Roles = "admin")] [HttpPost("answers")] public async Task CreateAnswer(Models.Answer answer) { @@ -114,7 +114,7 @@ namespace DamageAssesment.Api.Answers.Controllers /// /// Delete an existing answer. /// - + [Authorize(Roles = "admin")] [HttpDelete("answers/{id}")] public async Task DeleteAnswer(int id) { diff --git a/DamageAssesmentApi/DamageAssesment.Api.Answers/Program.cs b/DamageAssesmentApi/DamageAssesment.Api.Answers/Program.cs index 0a38399..77e7544 100644 --- a/DamageAssesmentApi/DamageAssesment.Api.Answers/Program.cs +++ b/DamageAssesmentApi/DamageAssesment.Api.Answers/Program.cs @@ -1,23 +1,73 @@ using DamageAssesment.Api.Answers.Db; using DamageAssesment.Api.Answers.Interfaces; using DamageAssesment.Api.Answers.Providers; +using Microsoft.AspNetCore.Authentication.JwtBearer; using Microsoft.EntityFrameworkCore; +using Microsoft.IdentityModel.Tokens; +using Microsoft.OpenApi.Models; using System.Reflection; +using System.Text; var builder = WebApplication.CreateBuilder(args); - +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 + }; +}); // Add services to the container. builder.Services.AddControllers(); // Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle builder.Services.AddEndpointsApiExplorer(); //builder.Services.AddSwaggerGen(); -builder.Services.AddSwaggerGen(c => +builder.Services.AddSwaggerGen(options => { // Include XML comments from your assembly var xmlFile = $"{Assembly.GetExecutingAssembly().GetName().Name}.xml"; var xmlPath = Path.Combine(AppContext.BaseDirectory, xmlFile); - c.IncludeXmlComments(xmlPath); + options.IncludeXmlComments(xmlPath); + + OpenApiSecurityScheme securityDefinition = new OpenApiSecurityScheme() + { + Name = "Bearer", + BearerFormat = "JWT", + Scheme = "bearer", + Description = "Specify the authorization token.", + In = ParameterLocation.Header, + Type = SecuritySchemeType.Http, + }; + + options.AddSecurityDefinition("jwt_auth", securityDefinition); + + // Make sure swagger UI requires a Bearer token specified + OpenApiSecurityScheme securityScheme = new OpenApiSecurityScheme() + { + Reference = new OpenApiReference() + { + Id = "jwt_auth", + Type = ReferenceType.SecurityScheme + } + }; + + OpenApiSecurityRequirement securityRequirements = new OpenApiSecurityRequirement() + { + {securityScheme, new string[] { }}, + }; + + options.AddSecurityRequirement(securityRequirements); }); builder.Services.AddScoped(); builder.Services.AddAutoMapper(AppDomain.CurrentDomain.GetAssemblies()); //4/30 @@ -35,7 +85,7 @@ if (app.Environment.IsDevelopment()) app.UseSwagger(); app.UseSwaggerUI(); } - +app.UseAuthentication(); app.UseAuthorization(); app.MapControllers(); diff --git a/DamageAssesmentApi/DamageAssesment.Api.Answers/appsettings.json b/DamageAssesmentApi/DamageAssesment.Api.Answers/appsettings.json index fbe7ccb..b759c3e 100644 --- a/DamageAssesmentApi/DamageAssesment.Api.Answers/appsettings.json +++ b/DamageAssesmentApi/DamageAssesment.Api.Answers/appsettings.json @@ -10,9 +10,8 @@ }, "AllowedHosts": "*", "ConnectionStrings": { - //"AnswerConnection": "Server=DESKTOP-OF5DPLQ\\SQLEXPRESS;Database=da_survey_dev;Trusted_Connection=True;TrustServerCertificate=True;" - // "AnswerConnection": "Server=localhost,1433;Database=da_survey_dev;User Id=sa;Password=Password123;TrustServerCertificate=True;", - "AnswerConnection": "Server=207.180.248.35;Database=da_survey_dev;User Id=sa;Password=YourStrongPassw0rd;TrustServerCertificate=True;" + "AnswerConnection": "Server=DESKTOP-OF5DPLQ\\SQLEXPRESS;Database=da_survey_dev;Trusted_Connection=True;TrustServerCertificate=True;" + //"AnswerConnection": "Server=tcp:da-dev.database.windows.net,1433;Initial Catalog=da-dev-db;Encrypt=True;User ID=admin-dev;Password=b3tgRABw8LGE75k;TrustServerCertificate=False;Connection Timeout=30;" } } diff --git a/DamageAssesmentApi/DamageAssesment.Api.Attachments.Test/AttachmentsServiceTest.cs b/DamageAssesmentApi/DamageAssesment.Api.Attachments.Test/AttachmentsServiceTest.cs index 1b3ff31..8dd9ba8 100644 --- a/DamageAssesmentApi/DamageAssesment.Api.Attachments.Test/AttachmentsServiceTest.cs +++ b/DamageAssesmentApi/DamageAssesment.Api.Attachments.Test/AttachmentsServiceTest.cs @@ -33,7 +33,7 @@ namespace DamageAssesment.Api.Attachments.Test public async Task GetAttachmentsAsync_ShouldReturnStatusCode204() { var mockAttachmentService = new Mock(); - var mockUploadService = new Mock(); + var mockUploadService = new Mock(); var mockResponse = await MockData.getNoContentResponse(); mockAttachmentService.Setup(service => service.GetAttachmentsAsync()).ReturnsAsync(mockResponse); @@ -47,7 +47,7 @@ namespace DamageAssesment.Api.Attachments.Test public async Task GetAttachmentAsync_ShouldReturnStatusCode200() { var mockAttachmentService = new Mock(); - var mockUploadService = new Mock(); + var mockUploadService = new Mock(); var mockResponse = await MockData.getOkResponse(1); mockAttachmentService.Setup(service => service.GetAttachmentByIdAsync(1)).ReturnsAsync(mockResponse); @@ -61,7 +61,7 @@ namespace DamageAssesment.Api.Attachments.Test public async Task GetAttachmentAsync_ShouldReturnStatusCode404() { var mockAttachmentService = new Mock(); - var mockUploadService = 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); @@ -73,7 +73,7 @@ namespace DamageAssesment.Api.Attachments.Test public async Task PostAttachmentAsync_ShouldReturnStatusCode200() { var mockAttachmentService = new Mock(); - var mockUploadService = new Mock(); + var mockUploadService = new Mock(); var mockResponse = await MockData.getOkResponse(); var AttachmentResponse = await MockData.GetAttachmentInfo(0); var mockInputAttachment = await MockData.getInputAttachmentData(); @@ -89,7 +89,7 @@ namespace DamageAssesment.Api.Attachments.Test public async Task PostAttachmentAsync_ShouldReturnStatusCode400() { var mockAttachmentService = new Mock(); - var mockUploadService = new Mock(); + var mockUploadService = new Mock(); var mockInputAttachment = await MockData.getInputAttachmentData(); var mockResponse = await MockData.getBadRequestResponse(); mockAttachmentService.Setup(service => service.PostAttachmentAsync(mockInputAttachment)).ReturnsAsync(mockResponse); @@ -105,7 +105,7 @@ namespace DamageAssesment.Api.Attachments.Test public async Task PutAttachmentAsync_ShouldReturnStatusCode200() { var mockAttachmentService = new Mock(); - var mockUploadService = new Mock(); + var mockUploadService = new Mock(); var mockResponse = await MockData.getOkResponse(); var AttachmentResponse = await MockData.GetAttachmentInfo(1); var mockInputAttachment = await MockData.getInputAttachmentData(); @@ -121,7 +121,7 @@ namespace DamageAssesment.Api.Attachments.Test public async Task PutAttachmentAsync_ShouldReturnStatusCode400() { var mockAttachmentService = new Mock(); - var mockUploadService = new Mock(); + var mockUploadService = new Mock(); var mockInputAttachment = await MockData.getInputAttachmentData(); var mockResponse = await MockData.getBadRequestResponse(); mockAttachmentService.Setup(service => service.PostAttachmentAsync(mockInputAttachment)).ReturnsAsync(mockResponse); @@ -136,7 +136,7 @@ namespace DamageAssesment.Api.Attachments.Test public async Task DeleteAttachmentAsync_ShouldReturnStatusCode200() { var mockAttachmentService = new Mock(); - var mockUploadService = 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("")); @@ -150,7 +150,7 @@ namespace DamageAssesment.Api.Attachments.Test public async Task DeleteAttachmentAsync_ShouldReturnStatusCode404() { var mockAttachmentService = new Mock(); - var mockUploadService = 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); diff --git a/DamageAssesmentApi/DamageAssesment.Api.Attachments/Controllers/AttachmentsController.cs b/DamageAssesmentApi/DamageAssesment.Api.Attachments/Controllers/AttachmentsController.cs index 16c223c..f20f380 100644 --- a/DamageAssesmentApi/DamageAssesment.Api.Attachments/Controllers/AttachmentsController.cs +++ b/DamageAssesmentApi/DamageAssesment.Api.Attachments/Controllers/AttachmentsController.cs @@ -1,6 +1,7 @@ using Azure; using DamageAssesment.Api.Attachments.Interfaces; using DamageAssesment.Api.Attachments.Models; +using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc; using System.Net.Http.Headers; @@ -12,16 +13,17 @@ namespace DamageAssesment.Api.Attachments.Controllers { private IAttachmentsProvider AttachmentProvider; private IUploadService UploadService; + private IAzureBlobService azureBlobService; - public AttachmentsController(IAttachmentsProvider AttachmentsProvider, IUploadService uploadService) + public AttachmentsController(IAttachmentsProvider AttachmentsProvider, IUploadService UploadService) { this.AttachmentProvider = AttachmentsProvider; - this.UploadService = uploadService; + this.UploadService = UploadService; } /// /// Get all attachments. /// - + [Authorize(Roles = "admin")] [HttpGet("attachments")] public async Task GetAttachmentsAsync() { @@ -37,6 +39,7 @@ namespace DamageAssesment.Api.Attachments.Controllers /// /// Get all attachments by attachmentId. /// + [Authorize(Roles = "admin")] [HttpGet("attachments/{id}")] public async Task GetAttachmentbyIdAsync(int id) { @@ -80,7 +83,7 @@ namespace DamageAssesment.Api.Attachments.Controllers /// /// Save new Attachment(s) /// - + [Authorize(Roles = "admin")] [HttpPost("attachments"), DisableRequestSizeLimit] public async Task UploadAttachmentAsync(AttachmentInfo attachmentInfo) { @@ -89,7 +92,7 @@ namespace DamageAssesment.Api.Attachments.Controllers if (attachmentInfo.Answers.Count > 0) { var Attachments = await this.AttachmentProvider.GetAttachmentCounter(); - List attachments = UploadService.UploadAttachment(attachmentInfo.ResponseId, Attachments.counter, attachmentInfo.Answers); + List attachments = UploadService.UploadAttachment(attachmentInfo.ResponseId, Attachments.counter, attachmentInfo.Answers); var result = await this.AttachmentProvider.PostAttachmentAsync(attachments); if (result.IsSuccess) { @@ -107,7 +110,7 @@ namespace DamageAssesment.Api.Attachments.Controllers /// /// Modify an new attachment. /// - + [Authorize(Roles = "admin")] [HttpPut("attachments"), DisableRequestSizeLimit] public async Task UpdateAttachmentAsync(AttachmentInfo attachmentInfo) { @@ -118,7 +121,7 @@ namespace DamageAssesment.Api.Attachments.Controllers var res = await this.AttachmentProvider.GetAttachmentInfo(attachmentInfo.Answers); if (res.IsSuccess) { - List attachments = UploadService.UpdateAttachments(attachmentInfo.ResponseId, attachmentInfo.Answers, res.Attachments); + List attachments = UploadService.UpdateAttachments(attachmentInfo.ResponseId, attachmentInfo.Answers, res.Attachments); var result = await this.AttachmentProvider.PutAttachmentAsync(attachments); if (result.IsSuccess) { @@ -138,6 +141,7 @@ namespace DamageAssesment.Api.Attachments.Controllers /// /// Delete an existing attachment. /// + [Authorize(Roles = "admin")] [HttpDelete("attachments/{id}")] public async Task DeleteAttachment(int id) { diff --git a/DamageAssesmentApi/DamageAssesment.Api.Attachments/Interfaces/IAzureBlobService.cs b/DamageAssesmentApi/DamageAssesment.Api.Attachments/Interfaces/IAzureBlobService.cs index f15ed9e..39e892d 100644 --- a/DamageAssesmentApi/DamageAssesment.Api.Attachments/Interfaces/IAzureBlobService.cs +++ b/DamageAssesmentApi/DamageAssesment.Api.Attachments/Interfaces/IAzureBlobService.cs @@ -1,10 +1,15 @@ using Azure.Storage.Blobs.Models; +using DamageAssesment.Api.Attachments.Models; namespace DamageAssesment.Api.Attachments.Interfaces { public interface IAzureBlobService { Task>> UploadFiles(List files); - void DeleteFile(string path); + Task> UploadAttachment(int responseId, int answerId, int counter, List postedFile); + Task> UploadAttachment(int responseId, int counter, List answers); + Task> UpdateAttachments(int responseId, List answers, IEnumerable attachments); + void Deletefile(string path); + void Movefile(string path); } } diff --git a/DamageAssesmentApi/DamageAssesment.Api.Attachments/Program.cs b/DamageAssesmentApi/DamageAssesment.Api.Attachments/Program.cs index 4fd2e59..62cf0cb 100644 --- a/DamageAssesmentApi/DamageAssesment.Api.Attachments/Program.cs +++ b/DamageAssesmentApi/DamageAssesment.Api.Attachments/Program.cs @@ -1,25 +1,75 @@ using DamageAssesment.Api.Attachments.Db; using DamageAssesment.Api.Attachments.Interfaces; using DamageAssesment.Api.Attachments.Providers; +using Microsoft.AspNetCore.Authentication.JwtBearer; using Microsoft.AspNetCore.Http.Features; using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.FileProviders; +using Microsoft.IdentityModel.Tokens; +using Microsoft.OpenApi.Models; using System.Reflection; +using System.Text; var builder = WebApplication.CreateBuilder(args); - +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 + }; +}); // Add services to the container. builder.Services.AddControllers(); // Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle builder.Services.AddEndpointsApiExplorer(); //builder.Services.AddSwaggerGen(); -builder.Services.AddSwaggerGen(c => +builder.Services.AddSwaggerGen(options => { // Include XML comments from your assembly var xmlFile = $"{Assembly.GetExecutingAssembly().GetName().Name}.xml"; var xmlPath = Path.Combine(AppContext.BaseDirectory, xmlFile); - c.IncludeXmlComments(xmlPath); + options.IncludeXmlComments(xmlPath); + + OpenApiSecurityScheme securityDefinition = new OpenApiSecurityScheme() + { + Name = "Bearer", + BearerFormat = "JWT", + Scheme = "bearer", + Description = "Specify the authorization token.", + In = ParameterLocation.Header, + Type = SecuritySchemeType.Http, + }; + + options.AddSecurityDefinition("jwt_auth", securityDefinition); + + // Make sure swagger UI requires a Bearer token specified + OpenApiSecurityScheme securityScheme = new OpenApiSecurityScheme() + { + Reference = new OpenApiReference() + { + Id = "jwt_auth", + Type = ReferenceType.SecurityScheme + } + }; + + OpenApiSecurityRequirement securityRequirements = new OpenApiSecurityRequirement() + { + {securityScheme, new string[] { }}, + }; + + options.AddSecurityRequirement(securityRequirements); }); builder.Services.AddScoped(); builder.Services.AddScoped(); @@ -45,6 +95,7 @@ if (app.Environment.IsDevelopment()) app.UseSwaggerUI(); } +app.UseAuthentication(); app.UseAuthorization(); app.UseHttpsRedirection(); diff --git a/DamageAssesmentApi/DamageAssesment.Api.Attachments/Providers/AzureBlobService.cs b/DamageAssesmentApi/DamageAssesment.Api.Attachments/Providers/AzureBlobService.cs index 4e30b42..2cb4558 100644 --- a/DamageAssesmentApi/DamageAssesment.Api.Attachments/Providers/AzureBlobService.cs +++ b/DamageAssesmentApi/DamageAssesment.Api.Attachments/Providers/AzureBlobService.cs @@ -3,6 +3,9 @@ using Azure.Storage.Blobs; using Azure.Storage.Blobs.Models; using Azure.Storage.Blobs.Specialized; using DamageAssesment.Api.Attachments.Interfaces; +using DamageAssesment.Api.Attachments.Models; +using System.Diagnostics.Metrics; +using System.Text; namespace DamageAssesment.Api.Attachments.Providers { @@ -10,11 +13,95 @@ namespace DamageAssesment.Api.Attachments.Providers { BlobServiceClient _blobClient; BlobContainerClient _containerClient; - string azureConnectionString = ""; - public AzureBlobService() + string azureConnectionString; + private string uploadpath = ""; + private string Deletepath = ""; + public AzureBlobService(IConfiguration configuration) { - _blobClient = new BlobServiceClient(azureConnectionString); - _containerClient = _blobClient.GetBlobContainerClient("apiimages"); + uploadpath = configuration.GetValue("Fileupload:folderpath"); + Deletepath = configuration.GetValue("Fileupload:Deletepath"); + _blobClient = new BlobServiceClient(configuration.GetValue("Fileupload:BlobConnectionString")); + _containerClient = _blobClient.GetBlobContainerClient(configuration.GetValue("Fileupload:BlobContainerName")); + } + public async Task> UploadAttachment(int responseId, int answerId, int counter, List postedFile) + { + var pathToSave = Path.Combine(uploadpath, "Response-" + responseId); + String fullDirectoryPath = Path.Combine(pathToSave, "Answer-" + answerId); + 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 stream = item.OpenReadStream(); + BlobClient client = _containerClient.GetBlobClient(fullDirectoryPath + "/" + fileName); + string dbPath = fullDirectoryPath + "/" + fileName; + var result = await client.UploadAsync(stream, true); + attachments.Add(new Models.Attachment { AnswerId = answerId, ResponseId = responseId, IsDeleted = false, FileName = UserfileName, URI = dbPath }); + } + return attachments; + } + public async Task> 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(uploadpath, "Response-" + responseId); + String fullDirectoryPath = Path.Combine(pathToSave, "Answer-" + answerId); + foreach (var file in item.postedFiles) + { + counter++; + + var UserfileName = Path.GetFileName(file.FileName); + var fileName = String.Format("Attachment_{0}{1}", counter, file.FileExtension); + byte[] byteArray = Convert.FromBase64String(file.FileContent); + MemoryStream stream = new MemoryStream(byteArray); + BlobClient client = _containerClient.GetBlobClient(fullDirectoryPath + "/" + fileName); + string dbPath = fullDirectoryPath + "/" + fileName; + var result = await client.UploadAsync(stream, true); + attachments.Add(new Models.Attachment { AnswerId = answerId, ResponseId = responseId, IsDeleted = false, FileName = UserfileName, URI = dbPath }); + } + } + return attachments; + } + catch (Exception ex) + { + return new List(); + } + + + } + public async Task> UpdateAttachments(int responseId, List answers, IEnumerable attachments) + { + List Dbattachments = new List(); + foreach (Models.Attachment searchFile in attachments) + { + Movefile(searchFile.URI); + } + foreach (var item in answers) + { + int answerId = item.AnswerId; + var pathToSave = Path.Combine(uploadpath, "Response-" + responseId); + String fullDirectoryPath = Path.Combine(pathToSave, "Answer-" + answerId); + 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); + byte[] byteArray = Convert.FromBase64String(file.FileContent); + MemoryStream stream = new MemoryStream(byteArray); + BlobClient client = _containerClient.GetBlobClient(fullDirectoryPath + "/" + fileName); + string dbPath = fullDirectoryPath + "/" + fileName; + var result = await client.UploadAsync(stream, true); + Dbattachments.Add(new Models.Attachment { Id = attachment.Id, AnswerId = answerId, ResponseId = responseId, IsDeleted = false, FileName = UserfileName, URI = dbPath }); + } + } + return Dbattachments; } public async Task>> UploadFiles(List files) @@ -35,10 +122,52 @@ namespace DamageAssesment.Api.Attachments.Providers return azureResponse; } - public void DeleteFile(string url) + public string getMovefilename(string movefilename) { - var blob = _containerClient.GetBlockBlobClient(url); - blob.DeleteIfExists(); + var list = movefilename.Split('.'); + if (list.Length > 0) + list[list.Length - 1] = DateTime.Now.ToShortDateString().Replace("/", "_") + "_" + DateTime.Now.ToShortTimeString().Replace("/", "_") + "." + list[list.Length - 1]; + return string.Join("_", list); + } + public void Movefile(string path) + { + try + { + if (path != "") + { + string MovePath = getMovefilename(path.Replace(uploadpath, Deletepath)); + // Get references to the source and destination blobs + BlobClient sourceBlobClient = _containerClient.GetBlobClient(path); + BlobClient destinationBlobClient = _containerClient.GetBlobClient(MovePath); + // Start the copy operation from the source to the destination + destinationBlobClient.StartCopyFromUri(sourceBlobClient.Uri); + + // Check if the copy operation completed successfully + WaitForCopyToComplete(destinationBlobClient); + + // Delete the source blob after a successful copy + sourceBlobClient.DeleteIfExists(); + } + } + catch (Exception ex) + { + + } + } + static void WaitForCopyToComplete(BlobClient blobClient) + { + BlobProperties properties = blobClient.GetProperties(); + + while (properties.CopyStatus == CopyStatus.Pending) + { + Task.Delay(TimeSpan.FromSeconds(1)); + properties = blobClient.GetProperties(); + } + } + public void Deletefile(string url) + { + BlobClient sourceBlobClient = _containerClient.GetBlobClient(url); + sourceBlobClient.DeleteIfExists(); } } } \ No newline at end of file diff --git a/DamageAssesmentApi/DamageAssesment.Api.Attachments/appsettings.json b/DamageAssesmentApi/DamageAssesment.Api.Attachments/appsettings.json index c894752..a664e43 100644 --- a/DamageAssesmentApi/DamageAssesment.Api.Attachments/appsettings.json +++ b/DamageAssesmentApi/DamageAssesment.Api.Attachments/appsettings.json @@ -11,12 +11,14 @@ "AllowedHosts": "*", "Fileupload": { "folderpath": "DMS_Attachments/Active", - "Deletepath": "DMS_Attachments/Deleted" + "Deletepath": "DMS_Attachments/Deleted", + "BlobConnectionString": "DefaultEndpointsProtocol=https;AccountName=damagedoculink;AccountKey=blynpwrAQtthEneXC5f4vFewJ3tPV+QZUt1AX3nefZScPPjkr5hMoC18B9ni6/ZYdhRiERPQw+hB+AStonf+iw==;EndpointSuffix=core.windows.net", + "BlobContainerName": "doculinks" }, "ConnectionStrings": { - //"AttachmentConnection": "Server=DESKTOP-OF5DPLQ\\SQLEXPRESS;Database=da_survey_dev;Trusted_Connection=True;TrustServerCertificate=True;" - // "AttachmentConnection": "Server=localhost,1433;Database=da_survey_dev;User Id=sa;Password=Password123;TrustServerCertificate=True;" - "AttachmentConnection": "Server=207.180.248.35;Database=da_survey_dev;User Id=sa;Password=YourStrongPassw0rd;TrustServerCertificate=True;" + "AttachmentConnection": "Server=DESKTOP-OF5DPLQ\\SQLEXPRESS;Database=da_survey_dev;Trusted_Connection=True;TrustServerCertificate=True;" + //"AttachmentConnection": "Server=tcp:da-dev.database.windows.net,1433;Initial Catalog=da-dev-db;Encrypt=True;User ID=admin-dev;Password=b3tgRABw8LGE75k;TrustServerCertificate=False;Connection Timeout=30;" + } } \ No newline at end of file diff --git a/DamageAssesmentApi/DamageAssesment.Api.DocuLinks.Test/DoculinkServiceTest.cs b/DamageAssesmentApi/DamageAssesment.Api.DocuLinks.Test/DoculinkServiceTest.cs index 14ddaaa..d7253e0 100644 --- a/DamageAssesmentApi/DamageAssesment.Api.DocuLinks.Test/DoculinkServiceTest.cs +++ b/DamageAssesmentApi/DamageAssesment.Api.DocuLinks.Test/DoculinkServiceTest.cs @@ -17,7 +17,7 @@ namespace DamageAssesment.Api.DocuLinks.Test var mockDocumentService = new Mock(); var mockUploadService = new Mock(); var mockResponse = await MockData.getNoContentResponses(); - mockDocumentService.Setup(service => service.GetdocumentsByLinkAsync("forms","en",null)).ReturnsAsync(mockResponse); + mockDocumentService.Setup(service => service.GetdocumentsByLinkAsync("forms", "en", null)).ReturnsAsync(mockResponse); var DocumentProvider = new DoculinkController(mockDocumentService.Object, mockUploadService.Object); var result = (NoContentResult)await DocumentProvider.GetDocumentsAsync("", "", null); @@ -44,10 +44,10 @@ namespace DamageAssesment.Api.DocuLinks.Test var mockDocumentService = new Mock(); var mockUploadService = new Mock(); var mockResponse = await MockData.getOkResponses(); - mockDocumentService.Setup(service => service.GetdocumentsByLinkAsync("forms","en", null)).ReturnsAsync(mockResponse); + mockDocumentService.Setup(service => service.GetdocumentsByLinkAsync("forms", "en", null)).ReturnsAsync(mockResponse); var DocumentProvider = new DoculinkController(mockDocumentService.Object, mockUploadService.Object); - var result = (OkObjectResult)await DocumentProvider.GetDocumentsAsync("forms","en", null); + var result = (OkObjectResult)await DocumentProvider.GetDocumentsAsync("forms", "en", null); Assert.Equal(200, result.StatusCode); } @@ -97,7 +97,7 @@ namespace DamageAssesment.Api.DocuLinks.Test var mockDocumentService = new Mock(); var mockUploadService = new Mock(); var mockResponse = await MockData.getOkResponse(1); - mockDocumentService.Setup(service => service.GetDocumentAsync(1,"forms","en")).ReturnsAsync(mockResponse); + mockDocumentService.Setup(service => service.GetDocumentAsync(1, "forms", "en")).ReturnsAsync(mockResponse); var DocumentProvider = new DoculinkController(mockDocumentService.Object, mockUploadService.Object); var result = (OkObjectResult)await DocumentProvider.GetDocumentAsync(1, "forms", "en"); @@ -154,9 +154,9 @@ namespace DamageAssesment.Api.DocuLinks.Test var mockResponse = await MockData.getOkResponse(1); var mockInputDocument = await MockData.getInputDocumentData(); var DocumentResponse = await MockData.GetDocuLinksInfo(1); - mockDocumentService.Setup(service => service.UpdateDocumentAsync(1,mockInputDocument)).ReturnsAsync(mockResponse); + mockDocumentService.Setup(service => service.UpdateDocumentAsync(1, mockInputDocument)).ReturnsAsync(mockResponse); var DocumentProvider = new DoculinkController(mockDocumentService.Object, mockUploadService.Object); - var result = (NotFoundResult)await DocumentProvider.UpdateDocument(1,DocumentResponse); + var result = (NotFoundResult)await DocumentProvider.UpdateDocument(1, DocumentResponse); Assert.Equal(404, result.StatusCode); } @@ -168,9 +168,9 @@ namespace DamageAssesment.Api.DocuLinks.Test var mockUploadService = new Mock(); var mockResponse = await MockData.getBadRequestResponse(); var mockInputDocument = await MockData.getInputDocumentData(); - mockDocumentService.Setup(service => service.UpdateDocumentAsync(99,mockInputDocument)).ReturnsAsync(mockResponse); + mockDocumentService.Setup(service => service.UpdateDocumentAsync(99, mockInputDocument)).ReturnsAsync(mockResponse); var DocumentProvider = new DoculinkController(mockDocumentService.Object, mockUploadService.Object); - var result = (BadRequestObjectResult)await DocumentProvider.UpdateDocument(99,null); + var result = (BadRequestObjectResult)await DocumentProvider.UpdateDocument(99, null); Assert.Equal(400, result.StatusCode); } @@ -235,7 +235,7 @@ namespace DamageAssesment.Api.DocuLinks.Test var mockDocumentService = new Mock(); var mockUploadService = new Mock(); var mockResponse = await LinkTypeMockData.getOkResponse(1); - mockDocumentService.Setup(service => service.GetLinkTypeAsync(1,"en")).ReturnsAsync(mockResponse); + mockDocumentService.Setup(service => service.GetLinkTypeAsync(1, "en")).ReturnsAsync(mockResponse); var DocumentProvider = new DoculinkController(mockDocumentService.Object, mockUploadService.Object); var result = (OkObjectResult)await DocumentProvider.GetLinkTypeAsync(1, "en"); @@ -290,9 +290,9 @@ namespace DamageAssesment.Api.DocuLinks.Test var mockUploadService = new Mock(); var mockResponse = await LinkTypeMockData.getOkResponse(1); var mockInputDocument = await LinkTypeMockData.getInputLinkData(1); - mockDocumentService.Setup(service => service.UpdateLinkTypeAsync(1,mockInputDocument)).ReturnsAsync(mockResponse); + mockDocumentService.Setup(service => service.UpdateLinkTypeAsync(1, mockInputDocument)).ReturnsAsync(mockResponse); var DocumentProvider = new DoculinkController(mockDocumentService.Object, mockUploadService.Object); - var result = (OkObjectResult)await DocumentProvider.UpdateLinkType(1,mockInputDocument); + var result = (OkObjectResult)await DocumentProvider.UpdateLinkType(1, mockInputDocument); Assert.Equal(200, result.StatusCode); } @@ -304,9 +304,9 @@ namespace DamageAssesment.Api.DocuLinks.Test var mockUploadService = new Mock(); var mockResponse = await LinkTypeMockData.getNotFoundResponse(); var mockInputDocument = await LinkTypeMockData.getInputLinkData(99); - mockDocumentService.Setup(service => service.UpdateLinkTypeAsync(99,mockInputDocument)).ReturnsAsync(mockResponse); + mockDocumentService.Setup(service => service.UpdateLinkTypeAsync(99, mockInputDocument)).ReturnsAsync(mockResponse); var DocumentProvider = new DoculinkController(mockDocumentService.Object, mockUploadService.Object); - var result = (NotFoundObjectResult)await DocumentProvider.UpdateLinkType(99,mockInputDocument); + var result = (NotFoundObjectResult)await DocumentProvider.UpdateLinkType(99, mockInputDocument); Assert.Equal(404, result.StatusCode); } @@ -318,7 +318,7 @@ namespace DamageAssesment.Api.DocuLinks.Test var mockUploadService = new Mock(); var mockResponse = await LinkTypeMockData.getBadRequestResponse(); var mockInputDocument = await LinkTypeMockData.getInputLinkData(1); - mockDocumentService.Setup(service => service.UpdateLinkTypeAsync(1,mockInputDocument)).ReturnsAsync(mockResponse); + mockDocumentService.Setup(service => service.UpdateLinkTypeAsync(1, mockInputDocument)).ReturnsAsync(mockResponse); var DocumentProvider = new DoculinkController(mockDocumentService.Object, mockUploadService.Object); var result = (BadRequestObjectResult)await DocumentProvider.UpdateLinkType(1, mockInputDocument); diff --git a/DamageAssesmentApi/DamageAssesment.Api.DocuLinks.Test/MockData.cs b/DamageAssesmentApi/DamageAssesment.Api.DocuLinks.Test/MockData.cs index 23ffae4..e5e2d67 100644 --- a/DamageAssesmentApi/DamageAssesment.Api.DocuLinks.Test/MockData.cs +++ b/DamageAssesmentApi/DamageAssesment.Api.DocuLinks.Test/MockData.cs @@ -14,25 +14,27 @@ namespace DamageAssesment.Api.DocuLinks.Test public static async Task<(bool, List, string)> getOkResponses() { List list = new List(); - + for (int i = 1; i < 4; i++) { Dictionary dicttitle = new Dictionary(); - Dictionary dictdesc = new Dictionary(); + Dictionary dictdesc = new Dictionary(); dicttitle.Add("en", "test"); dicttitle.Add("fr", "tester"); - dictdesc.Add("en", "test"); dictdesc.Add("fr", "tester"); + dictdesc.Add("en", "test"); dictdesc.Add("fr", "tester"); List DocuLinksTranslations = new List(); DocuLinksTranslations.Add(new DoculinkTranslation() { Language = "en", - title = "tel"+i, - description = "Sample"+i + title = "tel" + i, + description = "Sample" + i }); List doclinksAttachments = new List(); doclinksAttachments.Add(new DoculinkAttachments() { - docName = "",Path="www.google.com", - IsAttachments=false,CustomOrder=1 + docName = "", + Path = "www.google.com", + IsAttachments = false, + CustomOrder = 1 }); list.Add(new DocuLinks.Models.ResDoculink() { @@ -40,10 +42,10 @@ namespace DamageAssesment.Api.DocuLinks.Test Id = i, linkTypeId = i, IsActive = true, - titles= dicttitle, - description=dictdesc, - CustomOrder=i, - doclinksAttachments= doclinksAttachments + titles = dicttitle, + description = dictdesc, + CustomOrder = i, + doclinksAttachments = doclinksAttachments }); } List doculinks = list.GroupBy(a => a.linkTypeId).Select(a => new ResDoculinks() { linkTypeId = a.Key, doculinks = a.ToList() }).ToList(); @@ -120,8 +122,8 @@ namespace DamageAssesment.Api.DocuLinks.Test { List fileModels = new List(); - fileModels.Add( new FileModel() { FileName = "Sample", FileContent = "c2FtcGxl", FileExtension = ".txt",IsAttachments=true,CustomOrder=1 }); - return new ReqDoculink() { Id=id, linkTypeId = 1, CustomOrder = 1, Files = fileModels }; + fileModels.Add(new FileModel() { FileName = "Sample", FileContent = "c2FtcGxl", FileExtension = ".txt", IsAttachments = true, CustomOrder = 1 }); + return new ReqDoculink() { Id = id, linkTypeId = 1, CustomOrder = 1, Files = fileModels }; } public static async Task getInputDocumentData() { @@ -131,7 +133,7 @@ namespace DamageAssesment.Api.DocuLinks.Test Language = "en", title = "tel", description = "Sample" - }); + }); List doclinksAttachments = new List(); doclinksAttachments.Add(new DoculinkAttachments() { @@ -145,9 +147,9 @@ namespace DamageAssesment.Api.DocuLinks.Test Id = 1, linkTypeId = 1, IsActive = true, - CustomOrder=1, + CustomOrder = 1, documentsTranslations = DocuLinksTranslations, - doclinksAttachments= doclinksAttachments + doclinksAttachments = doclinksAttachments }; } public static async Task> getInputDocuLinksData() diff --git a/DamageAssesmentApi/DamageAssesment.Api.DocuLinks/Controllers/DoculinkController.cs b/DamageAssesmentApi/DamageAssesment.Api.DocuLinks/Controllers/DoculinkController.cs index 99d00a8..f151186 100644 --- a/DamageAssesmentApi/DamageAssesment.Api.DocuLinks/Controllers/DoculinkController.cs +++ b/DamageAssesmentApi/DamageAssesment.Api.DocuLinks/Controllers/DoculinkController.cs @@ -2,6 +2,7 @@ using DamageAssesment.Api.DocuLinks.Interfaces; using DamageAssesment.Api.DocuLinks.Models; using DamageAssesment.Api.DocuLinks.Providers; +using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc; @@ -12,18 +13,20 @@ namespace DamageAssesment.Api.DocuLinks.Controllers { private readonly IDoculinkProvider documentsProvider; private readonly IUploadService uploadService; + private readonly IAzureBlobService azureBlobService; - public DoculinkController(IDoculinkProvider documentsProvider,IUploadService uploadService) + public DoculinkController(IDoculinkProvider documentsProvider, IUploadService uploadService) { this.documentsProvider = documentsProvider; - this.uploadService = uploadService; + this.uploadService = uploadService; } /// /// Get all Doculink type. /// [HttpGet] + [Authorize(Roles = "admin")] [Route("doculinks/types")] [Route("doculinks/types/{language:alpha}")] public async Task GetLinkTypesAsync(string? language) @@ -38,6 +41,7 @@ namespace DamageAssesment.Api.DocuLinks.Controllers /// /// Get a Doculink type by id. /// + [Authorize(Roles = "admin")] [HttpGet] [Route("doculinks/types/{id}")] [Route("doculinks/types/{id}/{language:alpha}")] @@ -53,6 +57,7 @@ namespace DamageAssesment.Api.DocuLinks.Controllers /// /// Update a existing Doculink type. /// + [Authorize(Roles = "admin")] [HttpPut] [Route("doculinks/types/{id}")] public async Task UpdateLinkType(int id,Models.LinkType linkType) @@ -74,6 +79,7 @@ namespace DamageAssesment.Api.DocuLinks.Controllers /// /// Create a new Doculink type. /// + [Authorize(Roles = "admin")] [HttpPost] [Route("doculinks/types")] public async Task CreateLinkType(Models.LinkType linkType) @@ -92,6 +98,7 @@ namespace DamageAssesment.Api.DocuLinks.Controllers /// /// Delete a existing Doculink type by id. /// + [Authorize(Roles = "admin")] [HttpDelete] [Route("doculinks/types/{id}")] public async Task DeleteLinkType(int id) @@ -104,9 +111,10 @@ namespace DamageAssesment.Api.DocuLinks.Controllers return NotFound(); } /// - /// Get all Doculink. + /// Get all documents. /// - /// + + [Authorize(Roles = "admin")] [Route("doculinks")] [Route("doculinks/{linktype:alpha}")] [Route("doculinks/{linktype:alpha}/{language:alpha}")] @@ -154,6 +162,7 @@ namespace DamageAssesment.Api.DocuLinks.Controllers /// /// Get a Doculink by id. /// + [Authorize(Roles = "admin")] [HttpGet] [Route("doculinks/{id}")] [Route("doculinks/{id}/{linktype:alpha}")] @@ -170,6 +179,7 @@ namespace DamageAssesment.Api.DocuLinks.Controllers /// /// update existing doclink. /// + [Authorize(Roles = "admin")] [HttpPut] [Route("doculinks/{id}")] public async Task UpdateDocument(int id,ReqDoculink documentInfo) @@ -180,7 +190,7 @@ namespace DamageAssesment.Api.DocuLinks.Controllers if (dbdoc.IsSuccess) { var documents = await this.documentsProvider.GetDocumentCounter(); - Models.Doculink DocuLink= uploadService.UpdateDocuments(documents.counter,dbdoc.Document, documentInfo); + Models.Doculink DocuLink= uploadService.UpdateDocuments(documents.counter,dbdoc.Document, documentInfo); var result = await this.documentsProvider.UpdateDocumentAsync(id, DocuLink); if (result.IsSuccess) { @@ -195,6 +205,7 @@ namespace DamageAssesment.Api.DocuLinks.Controllers /// /// Create new doclink. /// + // [Authorize(Roles = "admin")] [HttpPost] [Route("doculinks")] public async Task CreateDocument(ReqDoculink documentInfo) @@ -203,8 +214,8 @@ namespace DamageAssesment.Api.DocuLinks.Controllers { if (documentInfo != null) { - var documents = await this.documentsProvider.GetDocumentCounter(); - Models.Doculink DocuLink= uploadService.UploadDocument(documents.counter, documentInfo); + //var documents = await this.documentsProvider.GetDocumentCounter(); + Models.Doculink DocuLink= uploadService.UploadDocument(1, documentInfo); var result = await this.documentsProvider.PostDocumentAsync(DocuLink); if (result.IsSuccess) { @@ -222,6 +233,7 @@ namespace DamageAssesment.Api.DocuLinks.Controllers /// /// Delete Doculink by id. /// + [Authorize(Roles = "admin")] [HttpDelete] [Route("doculinks/{id}")] public async Task DeleteDocument(int id) diff --git a/DamageAssesmentApi/DamageAssesment.Api.DocuLinks/DamageAssesment.Api.DocuLinks.csproj b/DamageAssesmentApi/DamageAssesment.Api.DocuLinks/DamageAssesment.Api.DocuLinks.csproj index 45347ee..7058f27 100644 --- a/DamageAssesmentApi/DamageAssesment.Api.DocuLinks/DamageAssesment.Api.DocuLinks.csproj +++ b/DamageAssesmentApi/DamageAssesment.Api.DocuLinks/DamageAssesment.Api.DocuLinks.csproj @@ -11,7 +11,8 @@ - + + diff --git a/DamageAssesmentApi/DamageAssesment.Api.DocuLinks/Db/DoculinkDbContext.cs b/DamageAssesmentApi/DamageAssesment.Api.DocuLinks/Db/DoculinkDbContext.cs index f24303e..7eeec65 100644 --- a/DamageAssesmentApi/DamageAssesment.Api.DocuLinks/Db/DoculinkDbContext.cs +++ b/DamageAssesmentApi/DamageAssesment.Api.DocuLinks/Db/DoculinkDbContext.cs @@ -15,7 +15,7 @@ namespace DamageAssesment.Api.DocuLinks.Db protected override void OnConfiguring(DbContextOptionsBuilder options) { // connect to sql server with connection string from app settings - options.UseSqlServer(_Configuration.GetConnectionString("DoculinConnection")); + options.UseSqlServer(_Configuration.GetConnectionString("DoculinkConnection")); } public DbSet Documents { get; set; } public DbSet LinkTypes { get; set; } diff --git a/DamageAssesmentApi/DamageAssesment.Api.DocuLinks/Interfaces/IAzureBlobService.cs b/DamageAssesmentApi/DamageAssesment.Api.DocuLinks/Interfaces/IAzureBlobService.cs index 844945e..043d8a1 100644 --- a/DamageAssesmentApi/DamageAssesment.Api.DocuLinks/Interfaces/IAzureBlobService.cs +++ b/DamageAssesmentApi/DamageAssesment.Api.DocuLinks/Interfaces/IAzureBlobService.cs @@ -1,10 +1,14 @@ using Azure.Storage.Blobs.Models; +using DamageAssesment.Api.DocuLinks.Models; namespace DamageAssesment.Api.DocuLinks.Interfaces { public interface IAzureBlobService { Task>> UploadFiles(List files); + Task UploadDocument(int counter, ReqDoculink documentInfo); + Task UpdateDocuments(int counter, Models.Doculink document, ReqDoculink documentInfo); void DeleteFile(string path); + void Movefile(string path); } } diff --git a/DamageAssesmentApi/DamageAssesment.Api.DocuLinks/Program.cs b/DamageAssesmentApi/DamageAssesment.Api.DocuLinks/Program.cs index f28dd76..cdd5a72 100644 --- a/DamageAssesmentApi/DamageAssesment.Api.DocuLinks/Program.cs +++ b/DamageAssesmentApi/DamageAssesment.Api.DocuLinks/Program.cs @@ -2,19 +2,69 @@ using DamageAssesment.Api.DocuLinks.Db; using DamageAssesment.Api.DocuLinks.Interfaces; using DamageAssesment.Api.DocuLinks.Providers; using Microsoft.EntityFrameworkCore; +using Microsoft.AspNetCore.Authentication.JwtBearer; +using Microsoft.IdentityModel.Tokens; using System.Reflection; +using System.Text; +using Microsoft.OpenApi.Models; 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 + }; +}); builder.Services.AddControllers(); -builder.Services.AddSwaggerGen(c => +builder.Services.AddSwaggerGen(options => { // Include XML comments from your assembly var xmlFile = $"{Assembly.GetExecutingAssembly().GetName().Name}.xml"; var xmlPath = Path.Combine(AppContext.BaseDirectory, xmlFile); - c.IncludeXmlComments(xmlPath); + options.IncludeXmlComments(xmlPath); + + OpenApiSecurityScheme securityDefinition = new OpenApiSecurityScheme() + { + Name = "Bearer", + BearerFormat = "JWT", + Scheme = "bearer", + Description = "Specify the authorization token.", + In = ParameterLocation.Header, + Type = SecuritySchemeType.Http, + }; + + options.AddSecurityDefinition("jwt_auth", securityDefinition); + + // Make sure swagger UI requires a Bearer token specified + OpenApiSecurityScheme securityScheme = new OpenApiSecurityScheme() + { + Reference = new OpenApiReference() + { + Id = "jwt_auth", + Type = ReferenceType.SecurityScheme + } + }; + + OpenApiSecurityRequirement securityRequirements = new OpenApiSecurityRequirement() + { + {securityScheme, new string[] { }}, + }; + + options.AddSecurityRequirement(securityRequirements); }); // Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle builder.Services.AddEndpointsApiExplorer(); @@ -25,7 +75,7 @@ builder.Services.AddScoped(); builder.Services.AddAutoMapper(AppDomain.CurrentDomain.GetAssemblies()); //4/30 builder.Services.AddDbContext(option => { - option.UseSqlServer("DoculinConnection"); + option.UseSqlServer("DoculinkConnection"); }); var app = builder.Build(); @@ -36,6 +86,7 @@ if (app.Environment.IsDevelopment()) app.UseSwaggerUI(); } +app.UseAuthentication(); app.UseAuthorization(); app.MapControllers(); diff --git a/DamageAssesmentApi/DamageAssesment.Api.DocuLinks/Providers/AzureBlobService.cs b/DamageAssesmentApi/DamageAssesment.Api.DocuLinks/Providers/AzureBlobService.cs index bfa2ca4..9931de2 100644 --- a/DamageAssesmentApi/DamageAssesment.Api.DocuLinks/Providers/AzureBlobService.cs +++ b/DamageAssesmentApi/DamageAssesment.Api.DocuLinks/Providers/AzureBlobService.cs @@ -1,8 +1,17 @@  +using Azure; using Azure.Storage.Blobs; using Azure.Storage.Blobs.Models; using Azure.Storage.Blobs.Specialized; using DamageAssesment.Api.DocuLinks.Interfaces; +using DamageAssesment.Api.DocuLinks.Models; +using Microsoft.AspNetCore.Mvc.Filters; +using Microsoft.Extensions.Configuration; +using Microsoft.VisualBasic; +using System.ComponentModel; +using System.IO; +using System.Text; +using System.Threading.Tasks; namespace DamageAssesment.Api.DocuLinks.Providers { @@ -10,11 +19,111 @@ namespace DamageAssesment.Api.DocuLinks.Providers { BlobServiceClient _blobClient; BlobContainerClient _containerClient; - string azureConnectionString = ""; - public AzureBlobService() + string azureConnectionString; + private string uploadpath = ""; + private string Deletepath = ""; + public AzureBlobService(IConfiguration configuration) { - _blobClient = new BlobServiceClient(azureConnectionString); - _containerClient = _blobClient.GetBlobContainerClient("apiimages"); + uploadpath = configuration.GetValue("Fileupload:folderpath"); + Deletepath = configuration.GetValue("Fileupload:Deletepath"); + _blobClient = new BlobServiceClient(configuration.GetValue("Fileupload:BlobConnectionString")); + _containerClient = _blobClient.GetBlobContainerClient(configuration.GetValue("Fileupload:BlobContainerName")); + } + public async Task UploadDocument(int counter, ReqDoculink documentInfo) + { + Models.Doculink Documents = new Models.Doculink(); + List attachments = new List(); + try + { + string path = "", UserfileName = ""; + if (documentInfo.Files != null) + { + + int counter1 = 1; + foreach (var item in documentInfo.Files) + { + if (item.IsAttachments) + { + UserfileName = Path.GetFileName(item.FileName); + var fileName = String.Format("Document_{0}_{1}{2}", counter, counter1, item.FileExtension); + byte[] byteArray = Convert.FromBase64String(item.FileContent); + MemoryStream stream = new MemoryStream(byteArray); + BlobClient client = _containerClient.GetBlobClient(uploadpath + "/" + fileName); + var result = await client.UploadAsync(stream, true); + path = uploadpath + "/" + fileName; + counter1++; + } + else + path = item.url; + attachments.Add(new Models.DoculinkAttachments { docName = UserfileName, Path = path, IsAttachments = item.IsAttachments, CustomOrder = item.CustomOrder }); + } + } + Documents = new Models.Doculink() + { + linkTypeId = documentInfo.linkTypeId, + documentsTranslations = documentInfo.documentsTranslations, + doclinksAttachments = attachments, + IsDeleted = false, + CustomOrder = documentInfo.CustomOrder, + IsActive = true + }; + + return Documents; + } + catch (Exception ex) + { + return new Models.Doculink(); + } + + + } + + public async Task UpdateDocuments(int counter, Models.Doculink document, ReqDoculink documentInfo) + { + try + { + foreach (var item in document.doclinksAttachments) + { + Movefile(item.Path); + } + string path = "", UserfileName = ""; + List attachments = new List(); + int counter1 = 1; + foreach (var item in documentInfo.Files) + { + if (item.IsAttachments) + { + UserfileName = Path.GetFileName(item.FileName); + var fileName = String.Format("Document_{0}_{1}{2)", document.Id, counter1, item.FileExtension); + byte[] byteArray = Encoding.UTF8.GetBytes(item.FileContent); + MemoryStream stream = new MemoryStream(byteArray); + BlobClient client = _containerClient.GetBlobClient(uploadpath + "/" + fileName); + path = uploadpath + "/" + fileName; + var result = await client.UploadAsync(stream, true); + counter1++; + } + else + path = item.url; + attachments.Add(new Models.DoculinkAttachments { docName = UserfileName, Path = path, IsAttachments = item.IsAttachments, CustomOrder = item.CustomOrder }); + } + Models.Doculink Documents = new Models.Doculink() + { + Id = documentInfo.Id, + linkTypeId = documentInfo.linkTypeId, + documentsTranslations = documentInfo.documentsTranslations, + IsActive = true, + IsDeleted = false, + CustomOrder = documentInfo.CustomOrder, + doclinksAttachments = attachments + }; + + return Documents; + } + + catch (Exception ex) + { + return new Models.Doculink(); + } } public async Task>> UploadFiles(List files) @@ -35,10 +144,52 @@ namespace DamageAssesment.Api.DocuLinks.Providers return azureResponse; } + public string getMovefilename(string movefilename) + { + var list = movefilename.Split('.'); + if (list.Length > 0) + list[list.Length - 1] = DateTime.Now.ToShortDateString().Replace("/", "_") +"_"+ DateTime.Now.ToShortTimeString().Replace("/", "_")+"." + list[list.Length - 1]; + return string.Join("_", list); + } + public void Movefile(string path) + { + try + { + if (path != "") + { + string MovePath = getMovefilename(path.Replace(uploadpath, Deletepath)); + // Get references to the source and destination blobs + BlobClient sourceBlobClient = _containerClient.GetBlobClient(path); + BlobClient destinationBlobClient = _containerClient.GetBlobClient(MovePath); + // Start the copy operation from the source to the destination + destinationBlobClient.StartCopyFromUri(sourceBlobClient.Uri); + + // Check if the copy operation completed successfully + WaitForCopyToComplete(destinationBlobClient); + + // Delete the source blob after a successful copy + sourceBlobClient.DeleteIfExists(); + } + } + catch(Exception ex) + { + + } + } + static void WaitForCopyToComplete(BlobClient blobClient) + { + BlobProperties properties = blobClient.GetProperties(); + + while (properties.CopyStatus == CopyStatus.Pending) + { + Task.Delay(TimeSpan.FromSeconds(1)); + properties = blobClient.GetProperties(); + } + } public void DeleteFile(string url) { - var blob = _containerClient.GetBlockBlobClient(url); - blob.DeleteIfExists(); + BlobClient sourceBlobClient = _containerClient.GetBlobClient(url); + sourceBlobClient.DeleteIfExists(); } } } \ No newline at end of file diff --git a/DamageAssesmentApi/DamageAssesment.Api.DocuLinks/Providers/DoculinkProvider.cs b/DamageAssesmentApi/DamageAssesment.Api.DocuLinks/Providers/DoculinkProvider.cs index 371b8b3..1228982 100644 --- a/DamageAssesmentApi/DamageAssesment.Api.DocuLinks/Providers/DoculinkProvider.cs +++ b/DamageAssesmentApi/DamageAssesment.Api.DocuLinks/Providers/DoculinkProvider.cs @@ -21,20 +21,22 @@ namespace DamageAssesment.Api.DocuLinks.Providers private DoculinkDbContext DocumentDbContext; private ILogger logger; private IUploadService uploadservice; + private IAzureBlobService azureBlobService; private IMapper mapper; - public DoculinkProvider(DoculinkDbContext DocumentDbContext, ILogger logger, IMapper mapper, IUploadService uploadservice) + public DoculinkProvider(DoculinkDbContext DocumentDbContext, ILogger logger, IMapper mapper, IUploadService uploadservice, IAzureBlobService azureBlobService) { this.DocumentDbContext = DocumentDbContext; this.logger = logger; this.mapper = mapper; this.uploadservice = uploadservice; - SeedData(); + this.azureBlobService = azureBlobService; + //SeedData(); } - private void SeedData() + private async Task SeedDataAsync() { if (!DocumentDbContext.LinkTypes.Any()) { diff --git a/DamageAssesmentApi/DamageAssesment.Api.DocuLinks/Providers/UploadService.cs b/DamageAssesmentApi/DamageAssesment.Api.DocuLinks/Providers/UploadService.cs index 807a2e0..0e71850 100644 --- a/DamageAssesmentApi/DamageAssesment.Api.DocuLinks/Providers/UploadService.cs +++ b/DamageAssesmentApi/DamageAssesment.Api.DocuLinks/Providers/UploadService.cs @@ -80,15 +80,16 @@ namespace DamageAssesment.Api.DocuLinks.Providers string path = "", UserfileName = ""; List attachments = new List(); + int counter1 = 1; foreach (var item in documentInfo.Files) { - counter++; if (item.IsAttachments) { UserfileName = Path.GetFileName(item.FileName); - var fileName = String.Format("Document_{0}{1}", counter, item.FileExtension); + var fileName = String.Format("Document_{0}_{1}{2}", document.Id, counter1, item.FileExtension); path = Path.Combine(fullDirectoryPath, fileName); File.WriteAllBytes(path, Convert.FromBase64String(item.FileContent)); + counter1++; } else path = item.url; diff --git a/DamageAssesmentApi/DamageAssesment.Api.DocuLinks/appsettings.json b/DamageAssesmentApi/DamageAssesment.Api.DocuLinks/appsettings.json index a513807..998c8de 100644 --- a/DamageAssesmentApi/DamageAssesment.Api.DocuLinks/appsettings.json +++ b/DamageAssesmentApi/DamageAssesment.Api.DocuLinks/appsettings.json @@ -1,4 +1,7 @@ { + "JwtSettings": { + "securitykey": "bWlhbWkgZGFkZSBzY2hvb2xzIHNlY3JldCBrZXk=" + }, "Logging": { "LogLevel": { "Default": "Information", @@ -7,13 +10,14 @@ }, "AllowedHosts": "*", "ConnectionStrings": { - //"DoculinConnection": "Server=DESKTOP-OF5DPLQ\\SQLEXPRESS;Database=da_survey_dev;Trusted_Connection=True;TrustServerCertificate=True;", - //"DoculinConnection": "Server=localhost,1433;Database=da_survey_dev;User Id=sa;Password=Password123;TrustServerCertificate=True;" - "DoculinConnection": "Server=207.180.248.35;Database=da_survey_dev;User Id=sa;Password=YourStrongPassw0rd;TrustServerCertificate=True;" + "DoculinkConnection": "Server=DESKTOP-OF5DPLQ\\SQLEXPRESS;Database=da_survey_dev;Trusted_Connection=True;TrustServerCertificate=True;" + //"DoculinkConnection": "Server=tcp:da-dev.database.windows.net,1433;Initial Catalog=da-dev-db;Encrypt=True;User ID=admin-dev;Password=b3tgRABw8LGE75k;TrustServerCertificate=False;Connection Timeout=30;" }, "Fileupload": { "folderpath": "DASA_Documents/Active", - "Deletepath": "DASA_Documents/Deleted" + "Deletepath": "DASA_Documents/Deleted", + "BlobConnectionString": "DefaultEndpointsProtocol=https;AccountName=damagedoculink;AccountKey=blynpwrAQtthEneXC5f4vFewJ3tPV+QZUt1AX3nefZScPPjkr5hMoC18B9ni6/ZYdhRiERPQw+hB+AStonf+iw==;EndpointSuffix=core.windows.net", + "BlobContainerName": "doculinks" } } diff --git a/DamageAssesmentApi/DamageAssesment.Api.Employees/Controllers/EmployeesController.cs b/DamageAssesmentApi/DamageAssesment.Api.Employees/Controllers/EmployeesController.cs index 05901c5..f247d17 100644 --- a/DamageAssesmentApi/DamageAssesment.Api.Employees/Controllers/EmployeesController.cs +++ b/DamageAssesmentApi/DamageAssesment.Api.Employees/Controllers/EmployeesController.cs @@ -1,4 +1,5 @@ using DamageAssesment.Api.Employees.Interfaces; +using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc; @@ -18,7 +19,7 @@ namespace DamageAssesment.Api.Employees.Controllers /// /// GET request for retrieving employees. /// - + [Authorize(Roles = "admin")] [HttpGet("employees")] public async Task GetEmployeesAsync() { @@ -35,7 +36,7 @@ namespace DamageAssesment.Api.Employees.Controllers /// /// GET request for retrieving an employee by ID. /// - + [Authorize(Roles = "admin")] [HttpGet("employees/{id}")] public async Task GetEmployeeByIdAsync(int id) { @@ -48,11 +49,12 @@ namespace DamageAssesment.Api.Employees.Controllers return NotFound(); } - + /// /// PUT request for updating an existing employee. /// /// The updated employee object. + [Authorize(Roles = "admin")] [HttpPut("employees/{id}")] public async Task UpdateEmployee(int id, Models.Employee Employee) { @@ -75,6 +77,7 @@ namespace DamageAssesment.Api.Employees.Controllers /// POST request for creating a new employee. /// /// The employee information for creating a new employee. + [Authorize(Roles = "admin")] [HttpPost("employees")] public async Task CreateEmployee(Models.Employee Employee) { @@ -93,6 +96,7 @@ namespace DamageAssesment.Api.Employees.Controllers /// DELETE request for deleting an existing employee. /// /// The ID of the employee to be deleted. + [Authorize(Roles = "admin")] [HttpDelete("employees/{id}")] public async Task DeleteEmployee(int id) { diff --git a/DamageAssesmentApi/DamageAssesment.Api.Employees/Program.cs b/DamageAssesmentApi/DamageAssesment.Api.Employees/Program.cs index 7d61871..0702b58 100644 --- a/DamageAssesmentApi/DamageAssesment.Api.Employees/Program.cs +++ b/DamageAssesmentApi/DamageAssesment.Api.Employees/Program.cs @@ -1,23 +1,74 @@ using DamageAssesment.Api.Employees.Db; using DamageAssesment.Api.Employees.Interfaces; using DamageAssesment.Api.Employees.Providers; +using Microsoft.AspNetCore.Authentication.JwtBearer; using Microsoft.EntityFrameworkCore; +using Microsoft.IdentityModel.Tokens; +using Microsoft.OpenApi.Models; using System.Reflection; +using System.Text; 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 + }; +}); builder.Services.AddControllers(); // Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle builder.Services.AddEndpointsApiExplorer(); //builder.Services.AddSwaggerGen(); -builder.Services.AddSwaggerGen(c => +builder.Services.AddSwaggerGen(options => { // Include XML comments from your assembly var xmlFile = $"{Assembly.GetExecutingAssembly().GetName().Name}.xml"; var xmlPath = Path.Combine(AppContext.BaseDirectory, xmlFile); - c.IncludeXmlComments(xmlPath); + options.IncludeXmlComments(xmlPath); + + OpenApiSecurityScheme securityDefinition = new OpenApiSecurityScheme() + { + Name = "Bearer", + BearerFormat = "JWT", + Scheme = "bearer", + Description = "Specify the authorization token.", + In = ParameterLocation.Header, + Type = SecuritySchemeType.Http, + }; + + options.AddSecurityDefinition("jwt_auth", securityDefinition); + + // Make sure swagger UI requires a Bearer token specified + OpenApiSecurityScheme securityScheme = new OpenApiSecurityScheme() + { + Reference = new OpenApiReference() + { + Id = "jwt_auth", + Type = ReferenceType.SecurityScheme + } + }; + + OpenApiSecurityRequirement securityRequirements = new OpenApiSecurityRequirement() + { + {securityScheme, new string[] { }}, + }; + + options.AddSecurityRequirement(securityRequirements); }); builder.Services.AddScoped(); @@ -43,6 +94,7 @@ if (app.Environment.IsDevelopment()) } } +app.UseAuthentication(); app.UseAuthorization(); app.MapControllers(); diff --git a/DamageAssesmentApi/DamageAssesment.Api.Employees/appsettings.json b/DamageAssesmentApi/DamageAssesment.Api.Employees/appsettings.json index b442e2b..36ccc0e 100644 --- a/DamageAssesmentApi/DamageAssesment.Api.Employees/appsettings.json +++ b/DamageAssesmentApi/DamageAssesment.Api.Employees/appsettings.json @@ -9,15 +9,9 @@ } }, "AllowedHosts": "*", - "settings": { - "endpoint1": "xxx", - "endpoint2": "xxx", - "endpoint3": "xxx" - }, "ConnectionStrings": { - //"EmployeeConnection": "Server=DESKTOP-OF5DPLQ\\SQLEXPRESS;Database=da_survey_dev;Trusted_Connection=True;TrustServerCertificate=True;", - //"EmployeeConnection": "Server=localhost,1433;Database=da_survey_dev;User Id=sa;Password=Password123;TrustServerCertificate=True;" - "EmployeeConnection": "Server=207.180.248.35;Database=da_survey_dev;User Id=sa;Password=YourStrongPassw0rd;TrustServerCertificate=True;" + "EmployeeConnection": "Server=DESKTOP-OF5DPLQ\\SQLEXPRESS;Database=da_survey_dev;Trusted_Connection=True;TrustServerCertificate=True;" + //"EmployeeConnection": "Server=tcp:da-dev.database.windows.net,1433;Initial Catalog=da-dev-db;Encrypt=True;User ID=admin-dev;Password=b3tgRABw8LGE75k;TrustServerCertificate=False;Connection Timeout=30;" } } diff --git a/DamageAssesmentApi/DamageAssesment.Api.Locations/Controllers/LocationsController.cs b/DamageAssesmentApi/DamageAssesment.Api.Locations/Controllers/LocationsController.cs index cea800d..8de7678 100644 --- a/DamageAssesmentApi/DamageAssesment.Api.Locations/Controllers/LocationsController.cs +++ b/DamageAssesmentApi/DamageAssesment.Api.Locations/Controllers/LocationsController.cs @@ -1,4 +1,5 @@ using DamageAssesment.Api.Locations.Interfaces; +using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc; @@ -15,7 +16,7 @@ namespace DamageAssesment.Api.Locations.Controllers /// /// Get all locations. /// - + [Authorize(Roles = "admin")] [HttpGet("locations")] public async Task GetLocationsAsync() { @@ -31,7 +32,7 @@ namespace DamageAssesment.Api.Locations.Controllers /// /// Get all locations based on locationdId. /// - + [Authorize(Roles = "admin")] [HttpGet("locations/{id}")] public async Task GetLocationByIdAsync(int id) { @@ -47,7 +48,7 @@ namespace DamageAssesment.Api.Locations.Controllers /// /// Update a Location. /// - + [Authorize(Roles = "admin")] [HttpPut("locations/{id}")] public async Task UpdateLocation(int id, Models.Location Location) { @@ -65,7 +66,7 @@ namespace DamageAssesment.Api.Locations.Controllers /// /// Save a new location. /// - + [Authorize(Roles = "admin")] [HttpPost("locations")] public async Task CreateLocation(Models.Location Location) { @@ -83,7 +84,7 @@ namespace DamageAssesment.Api.Locations.Controllers /// /// Delete an existing location. /// - + [Authorize(Roles = "admin")] [HttpDelete("locations/{id}")] public async Task DeleteLocation(int id) { diff --git a/DamageAssesmentApi/DamageAssesment.Api.Locations/Controllers/RegionsController.cs b/DamageAssesmentApi/DamageAssesment.Api.Locations/Controllers/RegionsController.cs index 172043c..d7fe03c 100644 --- a/DamageAssesmentApi/DamageAssesment.Api.Locations/Controllers/RegionsController.cs +++ b/DamageAssesmentApi/DamageAssesment.Api.Locations/Controllers/RegionsController.cs @@ -1,4 +1,5 @@ using DamageAssesment.Api.Locations.Interfaces; +using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; namespace DamageAssesment.Api.Locations.Controllers @@ -15,7 +16,7 @@ namespace DamageAssesment.Api.Locations.Controllers /// /// Get all regions.2 /// - + [Authorize(Roles = "admin")] [HttpGet("regions")] public async Task GetRegionsAsync() { @@ -29,7 +30,7 @@ namespace DamageAssesment.Api.Locations.Controllers /// /// GET request for retrieving a region by its ID. /// - + [Authorize(Roles = "admin")] [HttpGet("regions/{id}")] public async Task GetRegionAsync(int id) { @@ -43,7 +44,7 @@ namespace DamageAssesment.Api.Locations.Controllers /// /// POST request for creating a new region. /// - + [Authorize(Roles = "admin")] [HttpPost("regions")] public async Task PostRegionAsync(Models.Region region) { @@ -57,7 +58,7 @@ namespace DamageAssesment.Api.Locations.Controllers /// /// PUT request for updating an existing region. /// - + [Authorize(Roles = "admin")] [HttpPut("regions/{id}")] public async Task PutRegionAsync(int id, Models.Region region) { @@ -75,7 +76,7 @@ namespace DamageAssesment.Api.Locations.Controllers /// DELETE request for deleting a region based on ID. /// - + [Authorize(Roles = "admin")] [HttpDelete("regions/{id}")] public async Task DeleteRegionAsync(int id) { diff --git a/DamageAssesmentApi/DamageAssesment.Api.Locations/Program.cs b/DamageAssesmentApi/DamageAssesment.Api.Locations/Program.cs index f8136bd..cf4c0d2 100644 --- a/DamageAssesmentApi/DamageAssesment.Api.Locations/Program.cs +++ b/DamageAssesmentApi/DamageAssesment.Api.Locations/Program.cs @@ -1,23 +1,73 @@ using DamageAssesment.Api.Locations.Db; using DamageAssesment.Api.Locations.Interfaces; using DamageAssesment.Api.Locations.Providers; +using Microsoft.AspNetCore.Authentication.JwtBearer; using Microsoft.EntityFrameworkCore; +using Microsoft.IdentityModel.Tokens; +using Microsoft.OpenApi.Models; using System.Reflection; +using System.Text; 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 + }; +}); builder.Services.AddControllers(); // Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle builder.Services.AddEndpointsApiExplorer(); //builder.Services.AddSwaggerGen(); -builder.Services.AddSwaggerGen(c => +builder.Services.AddSwaggerGen(options => { // Include XML comments from your assembly var xmlFile = $"{Assembly.GetExecutingAssembly().GetName().Name}.xml"; var xmlPath = Path.Combine(AppContext.BaseDirectory, xmlFile); - c.IncludeXmlComments(xmlPath); + options.IncludeXmlComments(xmlPath); + + OpenApiSecurityScheme securityDefinition = new OpenApiSecurityScheme() + { + Name = "Bearer", + BearerFormat = "JWT", + Scheme = "bearer", + Description = "Specify the authorization token.", + In = ParameterLocation.Header, + Type = SecuritySchemeType.Http, + }; + + options.AddSecurityDefinition("jwt_auth", securityDefinition); + + // Make sure swagger UI requires a Bearer token specified + OpenApiSecurityScheme securityScheme = new OpenApiSecurityScheme() + { + Reference = new OpenApiReference() + { + Id = "jwt_auth", + Type = ReferenceType.SecurityScheme + } + }; + + OpenApiSecurityRequirement securityRequirements = new OpenApiSecurityRequirement() + { + {securityScheme, new string[] { }}, + }; + + options.AddSecurityRequirement(securityRequirements); }); builder.Services.AddScoped(); builder.Services.AddScoped(); @@ -26,7 +76,10 @@ builder.Services.AddDbContext(option => { option.UseSqlServer("LocationConnection"); }); + + var app = builder.Build(); +// Add services to the container. // Configure the HTTP request pipeline. if (app.Environment.IsDevelopment()) @@ -44,6 +97,7 @@ if (app.Environment.IsDevelopment()) } } +app.UseAuthentication(); app.UseAuthorization(); app.MapControllers(); diff --git a/DamageAssesmentApi/DamageAssesment.Api.Locations/appsettings.json b/DamageAssesmentApi/DamageAssesment.Api.Locations/appsettings.json index 22611e3..bceef58 100644 --- a/DamageAssesmentApi/DamageAssesment.Api.Locations/appsettings.json +++ b/DamageAssesmentApi/DamageAssesment.Api.Locations/appsettings.json @@ -9,10 +9,12 @@ } }, "AllowedHosts": "*", + //"ConnectionStrings": { + // "LocationConnection": "Server=DESKTOP-OF5DPLQ\\SQLEXPRESS;Database=da_survey_dev;Trusted_Connection=True;TrustServerCertificate=True;" + //}, "ConnectionStrings": { - //"LocationConnection": "Server=DESKTOP-OF5DPLQ\\SQLEXPRESS;Database=da_survey_dev;Trusted_Connection=True;TrustServerCertificate=True;", - // "LocationConnection": "Server=localhost,1433;Database=da_survey_dev;User Id=sa;Password=Password123;TrustServerCertificate=True;" - "LocationConnection": "Server=207.180.248.35;Database=da_survey_dev;User Id=sa;Password=YourStrongPassw0rd;TrustServerCertificate=True;" + "LocationConnection": "Server=DESKTOP-OF5DPLQ\\SQLEXPRESS;Database=da_survey_dev;Trusted_Connection=True;TrustServerCertificate=True;" + //"LocationConnection": "Server=tcp:da-dev.database.windows.net,1433;Initial Catalog=da-dev-db;Encrypt=True;User ID=admin-dev;Password=b3tgRABw8LGE75k;TrustServerCertificate=False;Connection Timeout=30;" } } diff --git a/DamageAssesmentApi/DamageAssesment.Api.Questions/Controllers/QuestionsController.cs b/DamageAssesmentApi/DamageAssesment.Api.Questions/Controllers/QuestionsController.cs index 7dec941..1171b0d 100644 --- a/DamageAssesmentApi/DamageAssesment.Api.Questions/Controllers/QuestionsController.cs +++ b/DamageAssesmentApi/DamageAssesment.Api.Questions/Controllers/QuestionsController.cs @@ -1,4 +1,5 @@ using DamageAssesment.Api.Questions.Interfaces; +using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; namespace DamageAssesment.Api.Questions.Controllers @@ -10,16 +11,13 @@ namespace DamageAssesment.Api.Questions.Controllers public QuestionsController(IQuestionsProvider questionsProvider) { - this.questionsProvider = questionsProvider; - } - /// /// GET request for retrieving questions. /// - - // get all questions + //get all questions + [Authorize(Roles = "admin,survey,user,report")] [Route("questions")] [Route("questions/{language:alpha}")] [HttpGet] @@ -37,6 +35,7 @@ namespace DamageAssesment.Api.Questions.Controllers /// /// GET request for retrieving a question by ID. /// + [Authorize(Roles = "admin,survey,user,report")] [Route("questions/{id}/{language:alpha}")] [Route("questions/{id:int}")] [HttpGet] @@ -55,6 +54,7 @@ namespace DamageAssesment.Api.Questions.Controllers /// GET request for retrieving survey questions based on a survey ID. /// Uri: {Optional language}/GetSurveyQuestions/{surveyId} :Default returns question in all languages /// + [Authorize(Roles = "admin,survey,user,report")] [Route("questions/bysurvey/{surveyId:int}")] [Route("questions/bysurvey/{surveyId:int}/{language:alpha}")] [HttpGet] @@ -71,6 +71,7 @@ namespace DamageAssesment.Api.Questions.Controllers /// PUT request for updating a question (multilingual). /// + [Authorize(Roles = "admin")] [HttpPut("questions")] public async Task UpdateQuestion(Models.Question question) { @@ -92,6 +93,7 @@ namespace DamageAssesment.Api.Questions.Controllers /// POST request for creating a new question (multilingual). /// + [Authorize(Roles = "admin")] [HttpPost("questions")] public async Task CreateQuestion(Models.Question question) { @@ -110,6 +112,7 @@ namespace DamageAssesment.Api.Questions.Controllers /// DELETE request for deleting a question based on ID. /// + [Authorize(Roles = "admin")] [HttpDelete("questions/{id}")] public async Task DeleteQuestion(int id) { @@ -125,6 +128,7 @@ namespace DamageAssesment.Api.Questions.Controllers /// GET request for retrieving question categories. /// + [Authorize(Roles = "admin,user,report")] [HttpGet("questions/categories")] [HttpGet("questions/categories/{language:alpha}")] public async Task GetQuestionCategoriesAsync(string? language) @@ -139,7 +143,7 @@ namespace DamageAssesment.Api.Questions.Controllers /// /// GET request for retrieving a question category by ID. /// - + [Authorize(Roles = "admin,report")] [HttpGet("questions/categories/{id:int}")] [HttpGet("questions/categories/{id:int}/{language:alpha}")] public async Task GetQuestionCategoryAsync(int id,string? language) @@ -156,7 +160,7 @@ namespace DamageAssesment.Api.Questions.Controllers /// /// PUT request for updating a question category. /// - + [Authorize(Roles = "admin,survey,report")] [HttpPut("questions/categories")] public async Task UpdateQuestionCategory(Models.QuestionCategory questionCategory) { @@ -178,6 +182,7 @@ namespace DamageAssesment.Api.Questions.Controllers /// POST request for creating a new question category. /// + [Authorize(Roles = "admin")] [HttpPost("questions/categories")] public async Task CreateQuestionCategory(Models.QuestionCategory questionCategory) { @@ -196,6 +201,7 @@ namespace DamageAssesment.Api.Questions.Controllers /// DELETE request for deleting a question category based on ID. /// + [Authorize(Roles = "admin")] [HttpDelete("questions/categories/{id}")] public async Task DeleteQuestionCategory(int id) { diff --git a/DamageAssesmentApi/DamageAssesment.Api.Questions/Models/Question.cs b/DamageAssesmentApi/DamageAssesment.Api.Questions/Models/Question.cs index b6c1668..f7fe7fb 100644 --- a/DamageAssesmentApi/DamageAssesment.Api.Questions/Models/Question.cs +++ b/DamageAssesmentApi/DamageAssesment.Api.Questions/Models/Question.cs @@ -12,7 +12,7 @@ public bool IsRequired { get; set; } public bool Comment { get; set; } public bool Key { get; set; } - public int? SurveyId { get; set; } + public int SurveyId { get; set; } public int CategoryId { get; set; } } } diff --git a/DamageAssesmentApi/DamageAssesment.Api.Questions/Program.cs b/DamageAssesmentApi/DamageAssesment.Api.Questions/Program.cs index c47a38d..dfd6a07 100644 --- a/DamageAssesmentApi/DamageAssesment.Api.Questions/Program.cs +++ b/DamageAssesmentApi/DamageAssesment.Api.Questions/Program.cs @@ -1,11 +1,33 @@ using DamageAssesment.Api.Questions.Db; using DamageAssesment.Api.Questions.Interfaces; using DamageAssesment.Api.Questions.Providers; +using Microsoft.AspNetCore.Authentication.JwtBearer; using Microsoft.EntityFrameworkCore; +using Microsoft.IdentityModel.Tokens; +using Microsoft.OpenApi.Models; using System.Reflection; +using System.Text; 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 + }; +}); // Add services to the container. builder.Services.AddControllers(); @@ -17,13 +39,41 @@ builder.Services.AddAutoMapper(AppDomain.CurrentDomain.GetAssemblies()); builder.Services.AddEndpointsApiExplorer(); //builder.Services.AddSwaggerGen(); -builder.Services.AddSwaggerGen(c => +builder.Services.AddSwaggerGen(options => { // Include XML comments from your assembly var xmlFile = $"{Assembly.GetExecutingAssembly().GetName().Name}.xml"; var xmlPath = Path.Combine(AppContext.BaseDirectory, xmlFile); - c.IncludeXmlComments(xmlPath); + options.IncludeXmlComments(xmlPath); + + OpenApiSecurityScheme securityDefinition = new OpenApiSecurityScheme() + { + Name = "Bearer", + BearerFormat = "JWT", + Scheme = "bearer", + Description = "Specify the authorization token.", + In = ParameterLocation.Header, + Type = SecuritySchemeType.Http, + }; + + options.AddSecurityDefinition("jwt_auth", securityDefinition); + + // Make sure swagger UI requires a Bearer token specified + OpenApiSecurityScheme securityScheme = new OpenApiSecurityScheme() + { + Reference = new OpenApiReference() + { + Id = "jwt_auth", + Type = ReferenceType.SecurityScheme + } + }; + OpenApiSecurityRequirement securityRequirements = new OpenApiSecurityRequirement() + { + {securityScheme, new string[] { }}, + }; + options.AddSecurityRequirement(securityRequirements); }); + builder.Services.AddDbContext(option => { option.UseSqlServer("QuestionConnection"); @@ -43,7 +93,7 @@ if (app.Environment.IsDevelopment()) questionProvider.SeedData(); } } - +app.UseAuthentication(); app.UseAuthorization(); app.MapControllers(); diff --git a/DamageAssesmentApi/DamageAssesment.Api.Questions/appsettings.json b/DamageAssesmentApi/DamageAssesment.Api.Questions/appsettings.json index 3d3bbda..e59b6ea 100644 --- a/DamageAssesmentApi/DamageAssesment.Api.Questions/appsettings.json +++ b/DamageAssesmentApi/DamageAssesment.Api.Questions/appsettings.json @@ -10,9 +10,8 @@ }, "AllowedHosts": "*", "ConnectionStrings": { - //"QuestionConnection": "Server=DESKTOP-OF5DPLQ\\SQLEXPRESS;Database=da_survey_dev;Trusted_Connection=True;TrustServerCertificate=True;" - // "QuestionConnection": "Server=localhost,1433;Database=da_survey_dev;User Id=sa;Password=Password123;TrustServerCertificate=True;" - "QuestionConnection": "Server=207.180.248.35;Database=da_survey_dev;User Id=sa;Password=YourStrongPassw0rd;TrustServerCertificate=True;" + "QuestionConnection": "Server=DESKTOP-OF5DPLQ\\SQLEXPRESS;Database=da_survey_dev;Trusted_Connection=True;TrustServerCertificate=True;" + //"QuestionConnection": "Server=tcp:da-dev.database.windows.net,1433;Initial Catalog=da-dev-db;Encrypt=True;User ID=admin-dev;Password=b3tgRABw8LGE75k;TrustServerCertificate=False;Connection Timeout=30;" } } diff --git a/DamageAssesmentApi/DamageAssesment.Api.Responses.Test/SurveyResponsesServiceTest.cs b/DamageAssesmentApi/DamageAssesment.Api.Responses.Test/SurveyResponsesServiceTest.cs index 48cec58..59c764d 100644 --- a/DamageAssesmentApi/DamageAssesment.Api.Responses.Test/SurveyResponsesServiceTest.cs +++ b/DamageAssesmentApi/DamageAssesment.Api.Responses.Test/SurveyResponsesServiceTest.cs @@ -23,17 +23,16 @@ namespace DamageAssesment.SurveyResponses.Test SurveyResponse mockRequestObject = await MockData.getSurveyResponseObject(); var mockResponse = await MockData.getOkResponse(mockRequestObject); mockSurveyResponseService.Setup(service => service.GetSurveyResponsesAsync(1)).ReturnsAsync(mockResponse); - var surveyResponseProvider = new SurveyResponsesController(mockSurveyResponseService.Object); + var surveyResponseProvider = new ResponsesController(mockSurveyResponseService.Object); var result = (OkObjectResult)await surveyResponseProvider.GetSurveyResponsesAsync(1); Assert.Equal(200, result.StatusCode); } - [Fact(DisplayName = "Get Responses - BadRequest case")] public async Task GetSurveyResponsesAsync_ShouldReturnStatusCode204() { var mockResponse = await MockData.getResponse(); mockSurveyResponseService.Setup(service => service.GetSurveyResponsesAsync(1)).ReturnsAsync(mockResponse); - var surveyResponseProvider = new SurveyResponsesController(mockSurveyResponseService.Object); + var surveyResponseProvider = new ResponsesController(mockSurveyResponseService.Object); var result = (BadRequestObjectResult)await surveyResponseProvider.GetSurveyResponsesAsync(1); Assert.Equal(400, result.StatusCode); } @@ -43,9 +42,9 @@ namespace DamageAssesment.SurveyResponses.Test { SurveyResponse mockRequestObject = await MockData.getSurveyResponseObject(); var mockResponse = await MockData.getOkResponse(); - mockSurveyResponseService.Setup(service => service.GetSurveyResponsesBySurveyAsync(1,1)).ReturnsAsync(mockResponse); - var surveyResponseProvider = new SurveyResponsesController(mockSurveyResponseService.Object); - var result = (OkObjectResult)await surveyResponseProvider.GetSurveyResponsesAsync(1,1); + mockSurveyResponseService.Setup(service => service.GetSurveyResponsesBySurveyAsync(1, 1)).ReturnsAsync(mockResponse); + var surveyResponseProvider = new ResponsesController(mockSurveyResponseService.Object); + var result = (OkObjectResult)await surveyResponseProvider.GetSurveyResponsesAsync(1, 1); Assert.Equal(200, result.StatusCode); } @@ -53,9 +52,9 @@ namespace DamageAssesment.SurveyResponses.Test public async Task GetSurveyResponsesBySurveyAsync_ShouldReturnStatusCode204() { var mockResponse = await MockData.getResponse(); - mockSurveyResponseService.Setup(service => service.GetSurveyResponsesBySurveyAsync(1,1)).ReturnsAsync(mockResponse); - var surveyResponseProvider = new SurveyResponsesController(mockSurveyResponseService.Object); - var result = (NoContentResult)await surveyResponseProvider.GetSurveyResponsesAsync(1,1); + mockSurveyResponseService.Setup(service => service.GetSurveyResponsesBySurveyAsync(1, 1)).ReturnsAsync(mockResponse); + var surveyResponseProvider = new ResponsesController(mockSurveyResponseService.Object); + var result = (NoContentResult)await surveyResponseProvider.GetSurveyResponsesAsync(1, 1); Assert.Equal(204, result.StatusCode); } @@ -67,9 +66,9 @@ namespace DamageAssesment.SurveyResponses.Test { SurveyResponse mockRequestObject = await MockData.getSurveyResponseObject(); var mockResponse = await MockData.getOkResponse(); - mockSurveyResponseService.Setup(service => service.GetSurveyResponsesBySurveyAndLocationAsync(1, 1,1)).ReturnsAsync(mockResponse); - var surveyResponseProvider = new SurveyResponsesController(mockSurveyResponseService.Object); - var result = (OkObjectResult)await surveyResponseProvider.GetSurveyResponsesBySurveyAndLocationAsync(1, 1,1); + mockSurveyResponseService.Setup(service => service.GetSurveyResponsesBySurveyAndLocationAsync(1, 1, 1)).ReturnsAsync(mockResponse); + var surveyResponseProvider = new ResponsesController(mockSurveyResponseService.Object); + var result = (OkObjectResult)await surveyResponseProvider.GetSurveyResponsesBySurveyAndLocationAsync(1, 1, 1); Assert.Equal(200, result.StatusCode); } @@ -78,7 +77,7 @@ namespace DamageAssesment.SurveyResponses.Test { var mockResponse = await MockData.getResponse(); mockSurveyResponseService.Setup(service => service.GetSurveyResponsesBySurveyAndLocationAsync(1, 1, 1)).ReturnsAsync(mockResponse); - var surveyResponseProvider = new SurveyResponsesController(mockSurveyResponseService.Object); + var surveyResponseProvider = new ResponsesController(mockSurveyResponseService.Object); var result = (NoContentResult)await surveyResponseProvider.GetSurveyResponsesBySurveyAndLocationAsync(1, 1, 1); Assert.Equal(204, result.StatusCode); } @@ -88,9 +87,9 @@ namespace DamageAssesment.SurveyResponses.Test { SurveyResponse mockRequestObject = await MockData.getSurveyResponseObject(); var mockResponse = await MockData.getOkResponse(); - mockSurveyResponseService.Setup(service => service.GetResponsesByAnswerAsync(1, 1, "Yes",1)).ReturnsAsync(mockResponse); - var surveyResponseProvider = new SurveyResponsesController(mockSurveyResponseService.Object); - var result = (OkObjectResult)await surveyResponseProvider.GetSurveyResponsesByAnswerAsyncAsync(1, 1, "Yes",1); + mockSurveyResponseService.Setup(service => service.GetResponsesByAnswerAsync(1, 1, "Yes", 1)).ReturnsAsync(mockResponse); + var surveyResponseProvider = new ResponsesController(mockSurveyResponseService.Object); + var result = (OkObjectResult)await surveyResponseProvider.GetSurveyResponsesByAnswerAsyncAsync(1, 1, "Yes", 1); Assert.Equal(200, result.StatusCode); } @@ -99,8 +98,8 @@ namespace DamageAssesment.SurveyResponses.Test { var mockResponse = await MockData.getResponse(); mockSurveyResponseService.Setup(service => service.GetResponsesByAnswerAsync(1, 1, "Yes", 1)).ReturnsAsync(mockResponse); - var surveyResponseProvider = new SurveyResponsesController(mockSurveyResponseService.Object); - var result = (NoContentResult)await surveyResponseProvider.GetSurveyResponsesByAnswerAsyncAsync(1, 1, "Yes",1); + var surveyResponseProvider = new ResponsesController(mockSurveyResponseService.Object); + var result = (NoContentResult)await surveyResponseProvider.GetSurveyResponsesByAnswerAsyncAsync(1, 1, "Yes", 1); Assert.Equal(204, result.StatusCode); } @@ -110,8 +109,8 @@ namespace DamageAssesment.SurveyResponses.Test { SurveyResponse mockRequestObject = await MockData.getSurveyResponseObject(); var mockResponse = await MockData.getOkResponse(); - mockSurveyResponseService.Setup(service => service.GetAnswersByRegionAsync(1,1)).ReturnsAsync(mockResponse); - var surveyResponseProvider = new SurveyResponsesController(mockSurveyResponseService.Object); + mockSurveyResponseService.Setup(service => service.GetAnswersByRegionAsync(1, 1)).ReturnsAsync(mockResponse); + var surveyResponseProvider = new ResponsesController(mockSurveyResponseService.Object); var result = (OkObjectResult)await surveyResponseProvider.GetAnswersByRegionAsync(1, 1); Assert.Equal(200, result.StatusCode); } @@ -121,7 +120,7 @@ namespace DamageAssesment.SurveyResponses.Test { var mockResponse = await MockData.getResponse(); mockSurveyResponseService.Setup(service => service.GetAnswersByRegionAsync(1, 1)).ReturnsAsync(mockResponse); - var surveyResponseProvider = new SurveyResponsesController(mockSurveyResponseService.Object); + var surveyResponseProvider = new ResponsesController(mockSurveyResponseService.Object); var result = (NoContentResult)await surveyResponseProvider.GetAnswersByRegionAsync(1, 1); Assert.Equal(204, result.StatusCode); } @@ -132,7 +131,7 @@ namespace DamageAssesment.SurveyResponses.Test SurveyResponse mockRequestObject = await MockData.getSurveyResponseObject(); var mockResponse = await MockData.getOkResponse(); mockSurveyResponseService.Setup(service => service.GetSurveyResponsesByMaintenanceCenterAsync(1, 1)).ReturnsAsync(mockResponse); - var surveyResponseProvider = new SurveyResponsesController(mockSurveyResponseService.Object); + var surveyResponseProvider = new ResponsesController(mockSurveyResponseService.Object); var result = (OkObjectResult)await surveyResponseProvider.GetAnswersByMaintenaceCentersync(1, 1); Assert.Equal(200, result.StatusCode); } @@ -142,7 +141,7 @@ namespace DamageAssesment.SurveyResponses.Test { var mockResponse = await MockData.getResponse(); mockSurveyResponseService.Setup(service => service.GetSurveyResponsesByMaintenanceCenterAsync(1, 1)).ReturnsAsync(mockResponse); - var surveyResponseProvider = new SurveyResponsesController(mockSurveyResponseService.Object); + var surveyResponseProvider = new ResponsesController(mockSurveyResponseService.Object); var result = (NoContentResult)await surveyResponseProvider.GetAnswersByMaintenaceCentersync(1, 1); Assert.Equal(204, result.StatusCode); } @@ -153,7 +152,7 @@ namespace DamageAssesment.SurveyResponses.Test 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 surveyResponseProvider = new ResponsesController(mockSurveyResponseService.Object); var result = (OkObjectResult)await surveyResponseProvider.GetSurveyResponseByIdAsync(1); Assert.Equal(200, result.StatusCode); } @@ -163,7 +162,7 @@ namespace DamageAssesment.SurveyResponses.Test { var mockResponse = await MockData.getResponse(); mockSurveyResponseService.Setup(service => service.GetSurveyResponseByIdAsync(1)).ReturnsAsync(mockResponse); - var surveyResponseProvider = new SurveyResponsesController(mockSurveyResponseService.Object); + var surveyResponseProvider = new ResponsesController(mockSurveyResponseService.Object); var result = (NoContentResult)await surveyResponseProvider.GetSurveyResponseByIdAsync(1); Assert.Equal(204, result.StatusCode); } @@ -175,7 +174,7 @@ namespace DamageAssesment.SurveyResponses.Test 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 surveyResponseController = new ResponsesController(mockSurveyResponseService.Object); var result = (OkObjectResult)await surveyResponseController.PostSurveysAsync(mockRequestObject); Assert.Equal(200, result.StatusCode); } @@ -186,7 +185,7 @@ namespace DamageAssesment.SurveyResponses.Test 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 surveyResponseController = new ResponsesController(mockSurveyResponseService.Object); var result = (BadRequestObjectResult)await surveyResponseController.PostSurveysAsync(mockRequestObject); Assert.Equal(400, result.StatusCode); } @@ -197,7 +196,7 @@ namespace DamageAssesment.SurveyResponses.Test 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 surveyResponseController = new ResponsesController(mockSurveyResponseService.Object); var result = (OkObjectResult)await surveyResponseController.PutSurveyResponseAsync(1, mockRequestObject); Assert.Equal(200, result.StatusCode); } @@ -208,7 +207,7 @@ namespace DamageAssesment.SurveyResponses.Test 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 surveyResponseController = new ResponsesController(mockSurveyResponseService.Object); var result = (BadRequestObjectResult)await surveyResponseController.PutSurveyResponseAsync(1, mockRequestObject); Assert.Equal(400, result.StatusCode); } @@ -219,7 +218,7 @@ namespace DamageAssesment.SurveyResponses.Test 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 surveyResponseController = new ResponsesController(mockSurveyResponseService.Object); var result = (OkObjectResult)await surveyResponseController.DeleteSurveyResponseAsync(1); Assert.Equal(200, result.StatusCode); } @@ -229,7 +228,7 @@ namespace DamageAssesment.SurveyResponses.Test { var mockResponse = await MockData.getResponse(); mockSurveyResponseService.Setup(service => service.DeleteSurveyResponseAsync(1)).ReturnsAsync(mockResponse); ; - var surveyResponseController = new SurveyResponsesController(mockSurveyResponseService.Object); + var surveyResponseController = new ResponsesController(mockSurveyResponseService.Object); var result = (NotFoundResult)await surveyResponseController.DeleteSurveyResponseAsync(1); Assert.Equal(404, result.StatusCode); } diff --git a/DamageAssesmentApi/DamageAssesment.Api.Responses/Controllers/SurveyResponsesController.cs b/DamageAssesmentApi/DamageAssesment.Api.Responses/Controllers/ResponsesController.cs similarity index 90% rename from DamageAssesmentApi/DamageAssesment.Api.Responses/Controllers/SurveyResponsesController.cs rename to DamageAssesmentApi/DamageAssesment.Api.Responses/Controllers/ResponsesController.cs index 55b7f5d..4cdeab6 100644 --- a/DamageAssesmentApi/DamageAssesment.Api.Responses/Controllers/SurveyResponsesController.cs +++ b/DamageAssesmentApi/DamageAssesment.Api.Responses/Controllers/ResponsesController.cs @@ -1,15 +1,16 @@ using DamageAssesment.Api.Responses.Interfaces; using DamageAssesment.Api.Responses.Models; +using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; namespace DamageAssesment.Api.Responses.Controllers { [ApiController] - public class SurveyResponsesController : ControllerBase + public class ResponsesController : ControllerBase { private readonly ISurveysResponse surveyResponseProvider; - public SurveyResponsesController(ISurveysResponse surveyResponseProvider) + public ResponsesController(ISurveysResponse surveyResponseProvider) { this.surveyResponseProvider = surveyResponseProvider; } @@ -17,6 +18,7 @@ namespace DamageAssesment.Api.Responses.Controllers /// GET request for retrieving survey responses. /// + [Authorize(Roles = "admin,survey,user,report")] [Route("responses/{employeeid:int}")] [Route("responses")] [HttpGet] @@ -36,6 +38,7 @@ namespace DamageAssesment.Api.Responses.Controllers /// /// GET request for retrieving survey responses by survey ID. /// + [Authorize(Roles = "admin,survey,user,report")] [Route("responses/bysurvey/{surveyid:int}/{employeeid:int}")] [Route("responses/bysurvey/{surveyid:int}")] [HttpGet] @@ -54,12 +57,13 @@ namespace DamageAssesment.Api.Responses.Controllers /// The ID of the survey for which responses are to be retrieved. /// The ID of the location for which responses are to be retrieved. + [Authorize(Roles = "admin,survey,user,report")] [Route("responses/{surveyid:int}/{locationid:int}/{employeeid:int}")] [Route("responses/{surveyid:int}/{locationid:int}")] [HttpGet] - public async Task GetSurveyResponsesBySurveyAndLocationAsync(int surveyid, int locationid,int? employeeid) + public async Task GetSurveyResponsesBySurveyAndLocationAsync(int surveyid, int locationid, int? employeeid) { - var result = await this.surveyResponseProvider.GetSurveyResponsesBySurveyAndLocationAsync(surveyid, locationid,employeeid ?? 0); + var result = await this.surveyResponseProvider.GetSurveyResponsesBySurveyAndLocationAsync(surveyid, locationid, employeeid ?? 0); if (result.IsSuccess) { return Ok(result.SurveyResponses); @@ -73,6 +77,7 @@ namespace DamageAssesment.Api.Responses.Controllers /// The ID of the question for which responses are to be retrieved. /// The answer for which responses are to be retrieved. + [Authorize(Roles = "admin,survey,user,report")] [Route("responses/byanswer/{surveyid:int}/{questionid:int}/{answer:alpha}/{employeeid:int}")] [Route("responses/byanswer/{surveyid:int}/{questionid:int}/{answer:alpha}")] [HttpGet] @@ -91,6 +96,7 @@ namespace DamageAssesment.Api.Responses.Controllers /// /// The ID of the survey for which answers are to be retrieved. + [Authorize(Roles = "admin,survey,user,report")] [Route("responses/byregion/{surveyid:int}")] [Route("responses/byregion/{surveyid:int}/{employeeid}")] [HttpGet] @@ -107,6 +113,7 @@ namespace DamageAssesment.Api.Responses.Controllers /// GET request for retrieving survey responses by survey ID and maintenance center. /// /// The ID of the survey for which responses are to be retrieved. + [Authorize(Roles = "admin,survey,user,report")] [Route("responses/bymaintenancecenter/{surveyid:int}/{employeeid:int}")] [Route("responses/bymaintenancecenter/{surveyid:int}")] [HttpGet] @@ -124,6 +131,7 @@ namespace DamageAssesment.Api.Responses.Controllers /// /// The ID of the survey response to be retrieved. + [Authorize(Roles = "admin,survey,user,report")] [HttpGet("responses/{id}")] public async Task GetSurveyResponseByIdAsync(int id) { @@ -140,6 +148,7 @@ namespace DamageAssesment.Api.Responses.Controllers /// /// The survey response object to be created. + [Authorize(Roles = "admin,survey,user,report")] [HttpPost("responses")] public async Task PostSurveysAsync(Models.SurveyResponse surveyResponse) { @@ -156,6 +165,7 @@ namespace DamageAssesment.Api.Responses.Controllers /// The ID of the survey response to be updated. /// The updated survey response object. + [Authorize(Roles = "admin,survey,user,report")] [HttpPut("responses/{id}")] public async Task PutSurveyResponseAsync(int id, Models.SurveyResponse surveyResponse) { @@ -173,6 +183,7 @@ namespace DamageAssesment.Api.Responses.Controllers /// DELETE request for deleting an existing survey response. /// + [Authorize(Roles = "admin,survey,user,report")] [HttpDelete("responses/{id}")] public async Task DeleteSurveyResponseAsync(int id) { @@ -188,6 +199,7 @@ namespace DamageAssesment.Api.Responses.Controllers /// /// The answers to be submitted for the survey. + [Authorize(Roles = "admin,survey,user,report")] [HttpPost("responses/answers")] public async Task PostSurveyAnswersAsync(Request request) { @@ -199,6 +211,7 @@ namespace DamageAssesment.Api.Responses.Controllers return BadRequest(result.ErrorMessage); } + [Authorize(Roles = "admin,survey,user,report")] [Route("responses/surveys/active")] [Route("responses/surveys/active/{language:alpha}")] [Route("responses/surveys/active/{employeeid:int}")] @@ -214,6 +227,7 @@ namespace DamageAssesment.Api.Responses.Controllers return NoContent(); } + [Authorize(Roles = "admin,survey,user,report")] [Route("responses/surveys/historic")] [Route("responses/surveys/historic/{language:alpha}")] [Route("responses/surveys/historic/{employeeid:int}")] diff --git a/DamageAssesmentApi/DamageAssesment.Api.Responses/Interfaces/IAnswerServiceProvider.cs b/DamageAssesmentApi/DamageAssesment.Api.Responses/Interfaces/IAnswerServiceProvider.cs index 43ba9a1..7c23f55 100644 --- a/DamageAssesmentApi/DamageAssesment.Api.Responses/Interfaces/IAnswerServiceProvider.cs +++ b/DamageAssesmentApi/DamageAssesment.Api.Responses/Interfaces/IAnswerServiceProvider.cs @@ -4,9 +4,9 @@ namespace DamageAssesment.Api.Responses.Interfaces { public interface IAnswerServiceProvider { - Task> getAnswersAsync(); - Task> GetAnswersByResponseIdAsync(int responseId); + Task> getAnswersAsync(string token); + Task> GetAnswersByResponseIdAsync(int responseId, string token); - Task PostAnswersAsync(Models.Answer answer); + Task PostAnswersAsync(Models.Answer answer, string token); } } diff --git a/DamageAssesmentApi/DamageAssesment.Api.Responses/Interfaces/IAttachmentServiceProvider.cs b/DamageAssesmentApi/DamageAssesment.Api.Responses/Interfaces/IAttachmentServiceProvider.cs index 7350071..15f76a5 100644 --- a/DamageAssesmentApi/DamageAssesment.Api.Responses/Interfaces/IAttachmentServiceProvider.cs +++ b/DamageAssesmentApi/DamageAssesment.Api.Responses/Interfaces/IAttachmentServiceProvider.cs @@ -4,7 +4,7 @@ namespace DamageAssesment.Api.Responses.Interfaces { public interface IAttachmentServiceProvider { - Task> getAttachmentsAsync(); - Task> PostAttachmentsAsync(Models.AttachmentInfo attachmentInfo); + Task> getAttachmentsAsync(string token); + Task> PostAttachmentsAsync(Models.AttachmentInfo attachmentInfo, string token); } } diff --git a/DamageAssesmentApi/DamageAssesment.Api.Responses/Interfaces/IEmployeeServiceProvider.cs b/DamageAssesmentApi/DamageAssesment.Api.Responses/Interfaces/IEmployeeServiceProvider.cs index ef9eb00..797cea7 100644 --- a/DamageAssesmentApi/DamageAssesment.Api.Responses/Interfaces/IEmployeeServiceProvider.cs +++ b/DamageAssesmentApi/DamageAssesment.Api.Responses/Interfaces/IEmployeeServiceProvider.cs @@ -1,10 +1,10 @@ -using DamageAssesment.Api.Responses.Models; +using DamageAssesment.Api.Responses.Models; namespace DamageAssesment.Api.Responses.Interfaces { public interface IEmployeeServiceProvider { - Task> getEmployeesAsync(); - Task getEmployeeAsync(int employeeId); + Task> getEmployeesAsync(string token); + Task getEmployeeAsync(int employeeId, string token); } -} +} \ No newline at end of file diff --git a/DamageAssesmentApi/DamageAssesment.Api.Responses/Interfaces/IHttpUtil.cs b/DamageAssesmentApi/DamageAssesment.Api.Responses/Interfaces/IHttpUtil.cs index a8578e0..ae5620f 100644 --- a/DamageAssesmentApi/DamageAssesment.Api.Responses/Interfaces/IHttpUtil.cs +++ b/DamageAssesmentApi/DamageAssesment.Api.Responses/Interfaces/IHttpUtil.cs @@ -1,9 +1,9 @@ -using DamageAssesment.Api.Responses.Models; +using DamageAssesment.Api.Responses.Models; namespace DamageAssesment.Api.Responses.Interfaces { public interface IHttpUtil { - Task SendAsync(HttpMethod method, string url, string JsonInput); + Task SendAsync(HttpMethod method, string url, string JsonInput, string token); } } diff --git a/DamageAssesmentApi/DamageAssesment.Api.Responses/Interfaces/ILocationServiceProvider.cs b/DamageAssesmentApi/DamageAssesment.Api.Responses/Interfaces/ILocationServiceProvider.cs index 75945cd..75ab80e 100644 --- a/DamageAssesmentApi/DamageAssesment.Api.Responses/Interfaces/ILocationServiceProvider.cs +++ b/DamageAssesmentApi/DamageAssesment.Api.Responses/Interfaces/ILocationServiceProvider.cs @@ -4,6 +4,6 @@ namespace DamageAssesment.Api.Responses.Interfaces { public interface ILocationServiceProvider { - Task> getLocationsAsync(); + Task> getLocationsAsync(string token); } } diff --git a/DamageAssesmentApi/DamageAssesment.Api.Responses/Interfaces/IQuestionServiceProvider.cs b/DamageAssesmentApi/DamageAssesment.Api.Responses/Interfaces/IQuestionServiceProvider.cs index 5c54e57..b37a171 100644 --- a/DamageAssesmentApi/DamageAssesment.Api.Responses/Interfaces/IQuestionServiceProvider.cs +++ b/DamageAssesmentApi/DamageAssesment.Api.Responses/Interfaces/IQuestionServiceProvider.cs @@ -4,8 +4,8 @@ namespace DamageAssesment.Api.Responses.Interfaces { public interface IQuestionServiceProvider { - Task> getQuestionsAsync(); - Task> getSurveyQuestionsAsync(int surveyId); - Task getQuestionsAsync(int questionId); + Task> getQuestionsAsync(string token); + Task> getSurveyQuestionsAsync(int surveyId, string token); + Task getQuestionsAsync(int questionId, string token); } } diff --git a/DamageAssesmentApi/DamageAssesment.Api.Responses/Interfaces/IRegionServiceProvider.cs b/DamageAssesmentApi/DamageAssesment.Api.Responses/Interfaces/IRegionServiceProvider.cs index be3b1c3..a97193e 100644 --- a/DamageAssesmentApi/DamageAssesment.Api.Responses/Interfaces/IRegionServiceProvider.cs +++ b/DamageAssesmentApi/DamageAssesment.Api.Responses/Interfaces/IRegionServiceProvider.cs @@ -4,6 +4,6 @@ namespace DamageAssesment.Api.Responses.Interfaces { public interface IRegionServiceProvider { - Task> getRegionsAsync(); + Task> getRegionsAsync(string token); } } diff --git a/DamageAssesmentApi/DamageAssesment.Api.Responses/Interfaces/ISurveyServiceProvider.cs b/DamageAssesmentApi/DamageAssesment.Api.Responses/Interfaces/ISurveyServiceProvider.cs index 64252c9..8c66bda 100644 --- a/DamageAssesmentApi/DamageAssesment.Api.Responses/Interfaces/ISurveyServiceProvider.cs +++ b/DamageAssesmentApi/DamageAssesment.Api.Responses/Interfaces/ISurveyServiceProvider.cs @@ -4,7 +4,7 @@ namespace DamageAssesment.Api.Responses.Interfaces { public interface ISurveyServiceProvider { - Task> getSurveysAsync(string language); - Task getSurveyAsync(int surveyId); + Task> getSurveysAsync(string language,string token); + Task getSurveyAsync(int surveyId,string token); } } diff --git a/DamageAssesmentApi/DamageAssesment.Api.Responses/Models/Employee.cs b/DamageAssesmentApi/DamageAssesment.Api.Responses/Models/Employee.cs index 72ceffc..3a84d81 100644 --- a/DamageAssesmentApi/DamageAssesment.Api.Responses/Models/Employee.cs +++ b/DamageAssesmentApi/DamageAssesment.Api.Responses/Models/Employee.cs @@ -11,6 +11,6 @@ namespace DamageAssesment.Api.Responses.Models public string OfficePhoneNumber { get; set; } public string Email { get; set; } public bool IsActive { get; set; } - public string? PreferredLanguage { get; set; } + public string PreferredLanguage { get; set; } } } diff --git a/DamageAssesmentApi/DamageAssesment.Api.Responses/Program.cs b/DamageAssesmentApi/DamageAssesment.Api.Responses/Program.cs index 1641e75..379caab 100644 --- a/DamageAssesmentApi/DamageAssesment.Api.Responses/Program.cs +++ b/DamageAssesmentApi/DamageAssesment.Api.Responses/Program.cs @@ -5,6 +5,10 @@ using DamageAssesment.Api.Responses.Providers; using Microsoft.EntityFrameworkCore; using Polly; using System.Reflection; +using Microsoft.OpenApi.Models; +using Microsoft.AspNetCore.Authentication.JwtBearer; +using Microsoft.IdentityModel.Tokens; +using System.Text; var builder = WebApplication.CreateBuilder(args); const int maxApiCallRetries = 3; @@ -14,6 +18,24 @@ const int intervalForCircuitBraker = 5; //5 seconds // 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 + }; +}); builder.Services.AddControllers(); // Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle @@ -26,6 +48,7 @@ builder.Services.AddScoped(); builder.Services.AddScoped(); builder.Services.AddScoped(); builder.Services.AddScoped(); +builder.Services.AddHttpContextAccessor(); builder.Services.AddHttpClient(). AddTransientHttpErrorPolicy(policy => policy.WaitAndRetryAsync(maxApiCallRetries, _ => TimeSpan.FromSeconds(intervalToRetry))). @@ -35,12 +58,40 @@ builder.Services.AddHttpClient(). builder.Services.AddAutoMapper(AppDomain.CurrentDomain.GetAssemblies()); builder.Services.AddEndpointsApiExplorer(); //builder.Services.AddSwaggerGen(); -builder.Services.AddSwaggerGen(c => + +builder.Services.AddSwaggerGen(options => { // Include XML comments from your assembly var xmlFile = $"{Assembly.GetExecutingAssembly().GetName().Name}.xml"; var xmlPath = Path.Combine(AppContext.BaseDirectory, xmlFile); - c.IncludeXmlComments(xmlPath); + options.IncludeXmlComments(xmlPath); + + OpenApiSecurityScheme securityDefinition = new OpenApiSecurityScheme() + { + Name = "Bearer", + BearerFormat = "JWT", + Scheme = "bearer", + Description = "Specify the authorization token.", + In = ParameterLocation.Header, + Type = SecuritySchemeType.Http, + }; + + options.AddSecurityDefinition("jwt_auth", securityDefinition); + + // Make sure swagger UI requires a Bearer token specified + OpenApiSecurityScheme securityScheme = new OpenApiSecurityScheme() + { + Reference = new OpenApiReference() + { + Id = "jwt_auth", + Type = ReferenceType.SecurityScheme + } + }; + OpenApiSecurityRequirement securityRequirements = new OpenApiSecurityRequirement() + { + {securityScheme, new string[] { }}, + }; + options.AddSecurityRequirement(securityRequirements); }); builder.Services.AddDbContext(option => { @@ -55,6 +106,7 @@ if (app.Environment.IsDevelopment()) app.UseSwaggerUI(); } +app.UseAuthentication(); app.UseAuthorization(); app.MapControllers(); diff --git a/DamageAssesmentApi/DamageAssesment.Api.Responses/Properties/launchSettings.json b/DamageAssesmentApi/DamageAssesment.Api.Responses/Properties/launchSettings.json index 7bd92b0..f3cba3b 100644 --- a/DamageAssesmentApi/DamageAssesment.Api.Responses/Properties/launchSettings.json +++ b/DamageAssesmentApi/DamageAssesment.Api.Responses/Properties/launchSettings.json @@ -1,6 +1,6 @@ { "profiles": { - "DamageAssesment.Api.SurveyResponses": { + "DamageAssesment.Api.Responses": { "commandName": "Project", "launchBrowser": true, "launchUrl": "swagger", diff --git a/DamageAssesmentApi/DamageAssesment.Api.Responses/Providers/SurveyResponsesProvider.cs b/DamageAssesmentApi/DamageAssesment.Api.Responses/Providers/SurveyResponsesProvider.cs index 0c6c817..00f030e 100644 --- a/DamageAssesmentApi/DamageAssesment.Api.Responses/Providers/SurveyResponsesProvider.cs +++ b/DamageAssesmentApi/DamageAssesment.Api.Responses/Providers/SurveyResponsesProvider.cs @@ -18,8 +18,10 @@ namespace DamageAssesment.Api.Responses.Providers private readonly IQuestionServiceProvider questionServiceProvider; private readonly ISurveyServiceProvider surveyServiceProvider; private readonly IMapper mapper; + private readonly IHttpContextAccessor httpContextAccessor; + private string token; - public SurveyResponsesProvider(SurveyResponseDbContext surveyResponseDbContext, ILogger logger, IAnswerServiceProvider answerServiceProvider, IRegionServiceProvider regionServiceProvider, ILocationServiceProvider locationServiceProvider, IEmployeeServiceProvider employeeServiceProvider, IAttachmentServiceProvider attachmentServiceProvider, IQuestionServiceProvider questionServiceProvider, ISurveyServiceProvider surveyServiceProvider, IMapper mapper) + public SurveyResponsesProvider(SurveyResponseDbContext surveyResponseDbContext, ILogger logger, IAnswerServiceProvider answerServiceProvider, IRegionServiceProvider regionServiceProvider, ILocationServiceProvider locationServiceProvider, IEmployeeServiceProvider employeeServiceProvider, IAttachmentServiceProvider attachmentServiceProvider, IQuestionServiceProvider questionServiceProvider, ISurveyServiceProvider surveyServiceProvider, IMapper mapper, IHttpContextAccessor httpContextAccessor) { this.surveyResponseDbContext = surveyResponseDbContext; this.logger = logger; @@ -30,8 +32,20 @@ namespace DamageAssesment.Api.Responses.Providers this.attachmentServiceProvider = attachmentServiceProvider; this.questionServiceProvider = questionServiceProvider; this.surveyServiceProvider = surveyServiceProvider; + this.httpContextAccessor = httpContextAccessor; this.mapper = mapper; SeedData(); + + token = httpContextAccessor.HttpContext.Request.Headers.Authorization; + if (token != null) + { + token = token.Replace("Bearer ", string.Empty); + } + else + { + token = ""; + } + // seedData(); } public void SeedData() @@ -111,14 +125,13 @@ namespace DamageAssesment.Api.Responses.Providers return (false, null, ex.Message); } } - public async Task<(bool IsSuccess, dynamic Surveys, string ErrorMessage)> GetActiveSurveysAsync(int? employeeid, string language) { try { logger?.LogInformation("Querying to get SurveyResponse object from DB"); //get all the survey that already taken by the employee - var surveys = await surveyServiceProvider.getSurveysAsync(language); + var surveys = await surveyServiceProvider.getSurveysAsync(language, token); surveys = surveys.Where(s => s.IsEnabled == true && s.StartDate <= DateTime.Now && s.EndDate >= DateTime.Now).ToList(); if (employeeid == null || employeeid == 0) return (true, surveys, null); @@ -139,7 +152,7 @@ namespace DamageAssesment.Api.Responses.Providers { logger?.LogInformation("Querying to get SurveyResponse object from DB"); - var surveys = await surveyServiceProvider.getSurveysAsync(language); + var surveys = await surveyServiceProvider.getSurveysAsync(language,token); // returning only historic data: end date is less than current date. surveys = surveys.Where(s => s.EndDate < DateTime.Now).ToList(); if (employeeid == null || employeeid == 0) @@ -164,7 +177,7 @@ namespace DamageAssesment.Api.Responses.Providers try { logger?.LogInformation("Querying to get Survey object from microservice"); - var survey = await surveyServiceProvider.getSurveyAsync(surveyId); + var survey = await surveyServiceProvider.getSurveyAsync(surveyId,token); if (survey != null) { @@ -195,7 +208,7 @@ namespace DamageAssesment.Api.Responses.Providers try { logger?.LogInformation("Querying to get Survey object from microservice"); - var survey = await surveyServiceProvider.getSurveyAsync(surveyId); + var survey = await surveyServiceProvider.getSurveyAsync(surveyId, token); if (survey != null) { @@ -226,7 +239,7 @@ namespace DamageAssesment.Api.Responses.Providers try { logger?.LogInformation("Querying to get Survey object from microservice"); - var survey = await surveyServiceProvider.getSurveyAsync(surveyId); + var survey = await surveyServiceProvider.getSurveyAsync(surveyId, token); if (survey != null) { @@ -257,8 +270,8 @@ namespace DamageAssesment.Api.Responses.Providers try { logger?.LogInformation("Querying to get Survey object from microservice"); - var survey = await surveyServiceProvider.getSurveyAsync(surveyId); - var question = await questionServiceProvider.getQuestionsAsync(questionId); + var survey = await surveyServiceProvider.getSurveyAsync(surveyId, token); + var question = await questionServiceProvider.getQuestionsAsync(questionId,token); bool IsCorrectAnswer = answer.ToLower().Equals("yes") || answer.ToLower().Equals("no") ? true : false; @@ -399,7 +412,7 @@ namespace DamageAssesment.Api.Responses.Providers { try { - var answersList = await answerServiceProvider.getAnswersAsync(); + var answersList = await answerServiceProvider.getAnswersAsync(token); if (answersList == null || !answersList.Any()) return null; @@ -422,8 +435,8 @@ namespace DamageAssesment.Api.Responses.Providers if (surveyAnswers == null || !surveyAnswers.Any()) return null; - var regions = await regionServiceProvider.getRegionsAsync(); - var locations = await locationServiceProvider.getLocationsAsync(); + var regions = await regionServiceProvider.getRegionsAsync(token); + var locations = await locationServiceProvider.getLocationsAsync(token); if (regions == null || !regions.Any() || locations == null || !locations.Any()) return null; @@ -433,18 +446,18 @@ namespace DamageAssesment.Api.Responses.Providers var result = from answer in surveyAnswers from location in locations where answer.LocationId.Equals(location.Id) - select new + select new { - answer.Id, - answer.QuestionId, - answer.AnswerText, - answer.Comment, - location.RegionId, - LocationId = location.Id, - answer.SurveyResponseId + answer.Id, + answer.QuestionId, + answer.AnswerText, + answer.Comment, + location.RegionId, + LocationId = location.Id, + answer.SurveyResponseId }; - + //group records by answer and region var q = from e in result @@ -452,13 +465,13 @@ namespace DamageAssesment.Api.Responses.Providers select new { g.Key.RegionId, - Answers = new + Answers = new { g.Key.AnswerText, Counter = g.Count() } }; - + //build the result List resultList = new List(); @@ -466,9 +479,9 @@ namespace DamageAssesment.Api.Responses.Providers { var answers = from u in q.ToList() where u.RegionId.Equals(region.Id) - select u.Answers; - - resultList.Add(new { RegionId = region.Id, region.Name, region.Abbreviation, Answers = answers }); + select u.Answers; + + resultList.Add(new { RegionId = region.Id, region.Name, region.Abbreviation, Answers = answers}); } //return the object result return new { Regions = resultList }; @@ -485,11 +498,11 @@ namespace DamageAssesment.Api.Responses.Providers { try { - var employee = await employeeServiceProvider.getEmployeeAsync(surveyResponse.EmployeeId); - var answers = await answerServiceProvider.GetAnswersByResponseIdAsync(surveyResponse.Id); - var allQuestions = await questionServiceProvider.getQuestionsAsync(); + var employee = await employeeServiceProvider.getEmployeeAsync(surveyResponse.EmployeeId, token); + var answers = await answerServiceProvider.GetAnswersByResponseIdAsync(surveyResponse.Id, token); + var allQuestions = await questionServiceProvider.getQuestionsAsync(token); var questions = allQuestions.Where(s => s.SurveyId == surveyResponse.SurveyId); - var attachments = await attachmentServiceProvider.getAttachmentsAsync(); + var attachments = await attachmentServiceProvider.getAttachmentsAsync(token); var result = new { @@ -528,91 +541,41 @@ namespace DamageAssesment.Api.Responses.Providers { try { - List surveyResonses = null; - Employee employee = null; - List employees = null; - if (employeeid == 0) - { - surveyResonses = await surveyResponseDbContext.SurveyResponses.Where(x => x.SurveyId == surveyId).ToListAsync(); - employees = await employeeServiceProvider.getEmployeesAsync(); - } - else - { - surveyResonses = await surveyResponseDbContext.SurveyResponses.Where(x => x.SurveyId == surveyId && x.EmployeeId == employeeid).ToListAsync(); - employee = await employeeServiceProvider.getEmployeeAsync(employeeid); - } - - var answers = await answerServiceProvider.getAnswersAsync(); - var questions = await questionServiceProvider.getQuestionsAsync(); + var surveyResonses = await surveyResponseDbContext.SurveyResponses.Where(x => x.SurveyId == surveyId).ToListAsync(); + var employees = await employeeServiceProvider.getEmployeesAsync(token); + var answers = await answerServiceProvider.getAnswersAsync(token); + var questions = await questionServiceProvider.getQuestionsAsync(token); var surveyQuestions = from q in questions where q.SurveyId == surveyId select q; //var surveyQuestions = await questionServiceProvider.getSurveyQuestionsAsync(surveyId); - var attachments = await attachmentServiceProvider.getAttachmentsAsync(); + var attachments = await attachmentServiceProvider.getAttachmentsAsync(token); + var result = from r in surveyResonses + select new + { + r.Id, + r.SurveyId, + r.LocationId, + r.EmployeeId, + r.ClientDevice, + r.KeyAnswerResult, + r.Longitute, + r.Latitude, + 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.CategoryId, q.Text }).SingleOrDefault(), + Attachments = from att in attachments where att.AnswerId == ans.Id select new { att.Id, att.URI } - if (employeeid == 0) - { - var result = from r in surveyResonses - select new - { - r.Id, - r.SurveyId, - r.LocationId, - r.EmployeeId, - r.ClientDevice, - r.KeyAnswerResult, - r.Longitute, - r.Latitude, - 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.CategoryId, q.Text }).SingleOrDefault(), - Attachments = from att in attachments where att.AnswerId == ans.Id select new { att.Id, att.URI } - - } - }; - return result; - } - else - { - object _employee = new { }; - if (employee != null) - { - _employee = new { employee.Id, employee.Name, employee.BirthDate, employee.Email, employee.OfficePhoneNumber }; - } - var result = from r in surveyResonses - select new - { - r.Id, - r.SurveyId, - r.LocationId, - r.EmployeeId, - r.ClientDevice, - r.KeyAnswerResult, - r.Longitute, - r.Latitude, - Employee = _employee, - 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.CategoryId, q.Text }).SingleOrDefault(), - Attachments = from att in attachments where att.AnswerId == ans.Id select new { att.Id, att.URI } - } - }; - - return result; - } + } + }; + return result; } catch (Exception ex) { @@ -634,12 +597,12 @@ namespace DamageAssesment.Api.Responses.Providers if (employeeid == 0) { surveyResonses = await surveyResponseDbContext.SurveyResponses.ToListAsync(); - employees = await employeeServiceProvider.getEmployeesAsync(); + employees = await employeeServiceProvider.getEmployeesAsync(token); } else { surveyResonses = await surveyResponseDbContext.SurveyResponses.Where(x => x.EmployeeId == employeeid).ToListAsync(); - employee = await employeeServiceProvider.getEmployeeAsync(employeeid); + employee = await employeeServiceProvider.getEmployeeAsync(employeeid, token); if (employee != null) { @@ -648,9 +611,9 @@ namespace DamageAssesment.Api.Responses.Providers } - var answers = await answerServiceProvider.getAnswersAsync(); - var questions = await questionServiceProvider.getQuestionsAsync(); - var attachments = await attachmentServiceProvider.getAttachmentsAsync(); + var answers = await answerServiceProvider.getAnswersAsync(token); + var questions = await questionServiceProvider.getQuestionsAsync(token); + var attachments = await attachmentServiceProvider.getAttachmentsAsync(token); var result = from r in surveyResonses select new @@ -677,8 +640,6 @@ namespace DamageAssesment.Api.Responses.Providers } }; return result; - - } catch (Exception ex) { @@ -702,8 +663,8 @@ namespace DamageAssesment.Api.Responses.Providers { surveyResponses = await surveyResponseDbContext.SurveyResponses.Where(x => x.SurveyId == surveyId && x.EmployeeId == employeeid).ToListAsync(); } - var answers = await answerServiceProvider.getAnswersAsync(); - var locations = await locationServiceProvider.getLocationsAsync(); + var answers = await answerServiceProvider.getAnswersAsync(token); + var locations = await locationServiceProvider.getLocationsAsync(token); var maintenanceCenters = locations.DistinctBy(m => m.MaintenanceCenter); //get all the answers for the particular survey @@ -732,7 +693,7 @@ namespace DamageAssesment.Api.Responses.Providers select new { g.Key.MaintenanceCenter, - Answers = new + Answers = new { g.Key.AnswerText, Counter = g.Count() @@ -769,12 +730,12 @@ namespace DamageAssesment.Api.Responses.Providers if (employeeid == 0) { surveyResonses = await surveyResponseDbContext.SurveyResponses.Where(x => x.SurveyId == surveyId && x.LocationId == locationId).ToListAsync(); - employees = await employeeServiceProvider.getEmployeesAsync(); + employees = await employeeServiceProvider.getEmployeesAsync(token); } else { surveyResonses = await surveyResponseDbContext.SurveyResponses.Where(x => x.SurveyId == surveyId && x.EmployeeId == employeeid && x.LocationId == locationId).ToListAsync(); - employee = await employeeServiceProvider.getEmployeeAsync(employeeid); + employee = await employeeServiceProvider.getEmployeeAsync(employeeid, token); if (employee != null) { @@ -782,10 +743,10 @@ namespace DamageAssesment.Api.Responses.Providers } } - var answers = await answerServiceProvider.getAnswersAsync(); - var questions = await questionServiceProvider.getQuestionsAsync(); + var answers = await answerServiceProvider.getAnswersAsync(token); + var questions = await questionServiceProvider.getQuestionsAsync(token); var surveyQuestions = from q in questions where q.SurveyId == surveyId select q; - var attachments = await attachmentServiceProvider.getAttachmentsAsync(); + var attachments = await attachmentServiceProvider.getAttachmentsAsync(token); var result = from r in surveyResonses select new @@ -798,7 +759,7 @@ namespace DamageAssesment.Api.Responses.Providers r.KeyAnswerResult, r.Longitute, r.Latitude, - Employee = employeeid != 0 ? _employee : (from e in employees where r.EmployeeId == e.Id select new { e.Id, e.Name, e.BirthDate, e.Email, e.OfficePhoneNumber }).SingleOrDefault(), + 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 @@ -813,7 +774,6 @@ namespace DamageAssesment.Api.Responses.Providers } }; return result; - } catch (Exception ex) { @@ -836,12 +796,12 @@ namespace DamageAssesment.Api.Responses.Providers if (employeeid == 0) { surveyResponses = await surveyResponseDbContext.SurveyResponses.Where(x => x.SurveyId == survey.Id).ToListAsync(); - employees = await employeeServiceProvider.getEmployeesAsync(); + employees = await employeeServiceProvider.getEmployeesAsync(token); } else { surveyResponses = await surveyResponseDbContext.SurveyResponses.Where(x => x.SurveyId == survey.Id && x.EmployeeId == employeeid).ToListAsync(); - employee = await employeeServiceProvider.getEmployeeAsync(employeeid); + employee = await employeeServiceProvider.getEmployeeAsync(employeeid, token); if (employee != null) { @@ -851,8 +811,8 @@ namespace DamageAssesment.Api.Responses.Providers //var surveyResponses = await surveyResponseDbContext.Responses.Where(x => x.SurveyId == survey.Id).ToListAsync(); // var employees = await employeeServiceProvider.getEmployeesAsync(); - var answers = await answerServiceProvider.getAnswersAsync(); - var attachments = await attachmentServiceProvider.getAttachmentsAsync(); + var answers = await answerServiceProvider.getAnswersAsync(token); + var attachments = await attachmentServiceProvider.getAttachmentsAsync(token); var result = from r in surveyResponses select new @@ -865,7 +825,7 @@ namespace DamageAssesment.Api.Responses.Providers r.KeyAnswerResult, r.Longitute, r.Latitude, - Employee = employeeid != 0 ? _employee : (from e in employees where r.EmployeeId == e.Id select new { e.Id, e.Name, e.BirthDate, e.Email, e.OfficePhoneNumber }).SingleOrDefault(), + 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 @@ -895,12 +855,12 @@ namespace DamageAssesment.Api.Responses.Providers { if (answerRequest != null) { - var answer = await answerServiceProvider.PostAnswersAsync(new Models.Answer { QuestionId = answerRequest.QuestionId, AnswerText = answerRequest.AnswerText, Comment = answerRequest.Comment, SurveyResponseId = surveyResponseId }); + var answer = await answerServiceProvider.PostAnswersAsync(new Models.Answer { QuestionId = answerRequest.QuestionId, AnswerText = answerRequest.AnswerText, Comment = answerRequest.Comment, SurveyResponseId = surveyResponseId }, token); if (answer != null) { List listAnswerInfo = new List(); listAnswerInfo.Add(new AnswerInfo { AnswerId = answer.Id, postedFiles = answerRequest.PostedFiles }); - var attachments = attachmentServiceProvider.PostAttachmentsAsync(new AttachmentInfo { ResponseId = surveyResponseId, Answers = listAnswerInfo }); + var attachments = attachmentServiceProvider.PostAttachmentsAsync(new AttachmentInfo { ResponseId = surveyResponseId, Answers = listAnswerInfo }, token); string message = $"Answer for question {answerRequest.QuestionId} saved to the database"; logger?.LogInformation(message); @@ -921,14 +881,13 @@ namespace DamageAssesment.Api.Responses.Providers } } - public async Task<(bool IsSuccess, Models.SurveyResponse SurveyResponse, string ErrorMessage)> PostSurveyAnswersAsync(Models.Request request) { try { if (request != null) { - var response = await PostSurveyResponseAsync(new Models.SurveyResponse { SurveyId = request.SurveyId, EmployeeId = request.EmployeeId, LocationId = request.LocationId, ClientDevice = request.ClientDevice, KeyAnswerResult = request.KeyAnswerResult, Latitude = Convert.ToDouble(request.Latitude), Longitute = Convert.ToDouble(request.Longitute), CreatedDate = DateTime.Now }); + var response = await PostSurveyResponseAsync(new Models.SurveyResponse { SurveyId = request.SurveyId, EmployeeId = request.EmployeeId, LocationId = request.LocationId, ClientDevice = request.ClientDevice, KeyAnswerResult = request.KeyAnswerResult, Latitude = Convert.ToDouble(request.Latitude), Longitute = Convert.ToDouble(request.Longitute), CreatedDate=DateTime.Now }); if (response.IsSuccess) { var surveyResponse = response.SurveyResponse; diff --git a/DamageAssesmentApi/DamageAssesment.Api.Responses/Services/AnswerServiceProvider.cs b/DamageAssesmentApi/DamageAssesment.Api.Responses/Services/AnswerServiceProvider.cs index 5b8eeeb..b550ff1 100644 --- a/DamageAssesmentApi/DamageAssesment.Api.Responses/Services/AnswerServiceProvider.cs +++ b/DamageAssesmentApi/DamageAssesment.Api.Responses/Services/AnswerServiceProvider.cs @@ -1,5 +1,6 @@ using DamageAssesment.Api.Responses.Interfaces; using DamageAssesment.Api.Responses.Models; +using Microsoft.Extensions.Primitives; using Newtonsoft.Json; @@ -10,11 +11,11 @@ namespace DamageAssesment.Api.Responses.Services public AnswerServiceProvider(IConfiguration configuration, IHttpUtil httpUtil, ILogger logger) : base(configuration, httpUtil, logger, configuration.GetValue("RessourceSettings:Answer"), configuration.GetValue("EndPointSettings:AnswerUrlBase")) { } - public async Task> getAnswersAsync() + public async Task> getAnswersAsync(string token) { try { - var responseJsonString = await httpUtil.SendAsync(HttpMethod.Get, url, null); + var responseJsonString = await httpUtil.SendAsync(HttpMethod.Get, url, null, token); var answers = JsonConvert.DeserializeObject>(responseJsonString); if (answers == null || !answers.Any()) @@ -28,12 +29,12 @@ namespace DamageAssesment.Api.Responses.Services } } - public async Task> GetAnswersByResponseIdAsync(int responseId) + public async Task> GetAnswersByResponseIdAsync(int responseId, string token) { try { url = urlBase + string.Format(configuration.GetValue("RessourceSettings:AnswerByResponse"), responseId); - var responseJsonString = await httpUtil.SendAsync(HttpMethod.Get, url, null); + var responseJsonString = await httpUtil.SendAsync(HttpMethod.Get, url, null,token); var answers = JsonConvert.DeserializeObject>(responseJsonString); if (answers == null || !answers.Any()) @@ -47,12 +48,12 @@ namespace DamageAssesment.Api.Responses.Services } } - public async Task PostAnswersAsync(Answer answer) + public async Task PostAnswersAsync(Answer answer, string token ) { try { var requestJsonString = JsonConvert.SerializeObject(answer); - var responseJsonString = await httpUtil.SendAsync(HttpMethod.Post, url, requestJsonString); + var responseJsonString = await httpUtil.SendAsync(HttpMethod.Post, url, requestJsonString, token); var answers = JsonConvert.DeserializeObject(responseJsonString); if (answers == null) diff --git a/DamageAssesmentApi/DamageAssesment.Api.Responses/Services/AttachmentServiceProvider.cs b/DamageAssesmentApi/DamageAssesment.Api.Responses/Services/AttachmentServiceProvider.cs index bfbce94..9ace258 100644 --- a/DamageAssesmentApi/DamageAssesment.Api.Responses/Services/AttachmentServiceProvider.cs +++ b/DamageAssesmentApi/DamageAssesment.Api.Responses/Services/AttachmentServiceProvider.cs @@ -10,11 +10,11 @@ namespace DamageAssesment.Api.Responses.Services { } - public async Task> getAttachmentsAsync() + public async Task> getAttachmentsAsync(string token) { try { - var responseJsonString = await httpUtil.SendAsync(HttpMethod.Get, url, null); + var responseJsonString = await httpUtil.SendAsync(HttpMethod.Get, url, null,token); var attachments = JsonConvert.DeserializeObject>(responseJsonString); if (attachments == null || !attachments.Any()) @@ -28,12 +28,12 @@ namespace DamageAssesment.Api.Responses.Services } } - public async Task> PostAttachmentsAsync(AttachmentInfo attachmentInfo) + public async Task> PostAttachmentsAsync(AttachmentInfo attachmentInfo, string token) { try { var requestJsonString = JsonConvert.SerializeObject(attachmentInfo); - var responseJsonString = await httpUtil.SendAsync(HttpMethod.Post, url, requestJsonString); + var responseJsonString = await httpUtil.SendAsync(HttpMethod.Post, url, requestJsonString, token); var attachments = JsonConvert.DeserializeObject>(responseJsonString); if (attachments == null) diff --git a/DamageAssesmentApi/DamageAssesment.Api.Responses/Services/EmployeeServiceProvider.cs b/DamageAssesmentApi/DamageAssesment.Api.Responses/Services/EmployeeServiceProvider.cs index 22f63de..bcde62a 100644 --- a/DamageAssesmentApi/DamageAssesment.Api.Responses/Services/EmployeeServiceProvider.cs +++ b/DamageAssesmentApi/DamageAssesment.Api.Responses/Services/EmployeeServiceProvider.cs @@ -1,4 +1,4 @@ -using DamageAssesment.Api.Responses.Interfaces; +using DamageAssesment.Api.Responses.Interfaces; using DamageAssesment.Api.Responses.Models; using Microsoft.AspNetCore.Mvc.Routing; using Newtonsoft.Json; @@ -11,11 +11,11 @@ namespace DamageAssesment.Api.Responses.Services { } - public async Task> getEmployeesAsync() + public async Task> getEmployeesAsync(string token) { try { - var responseJsonString = await httpUtil.SendAsync(HttpMethod.Get, url, null); + var responseJsonString = await httpUtil.SendAsync(HttpMethod.Get, url, null,token); var employees = JsonConvert.DeserializeObject>(responseJsonString); if (employees == null || !employees.Any()) @@ -29,12 +29,12 @@ namespace DamageAssesment.Api.Responses.Services } } - public async Task getEmployeeAsync(int employeeId) + public async Task getEmployeeAsync(int employeeId, string token) { try { url = urlBase + string.Format(configuration.GetValue("RessourceSettings:EmployeeById"), employeeId); - var responseJsonString = await httpUtil.SendAsync(HttpMethod.Get, url, null); + var responseJsonString = await httpUtil.SendAsync(HttpMethod.Get, url, null, token); var employee = JsonConvert.DeserializeObject(responseJsonString); if (employee == null) diff --git a/DamageAssesmentApi/DamageAssesment.Api.Responses/Services/HttpUtil.cs b/DamageAssesmentApi/DamageAssesment.Api.Responses/Services/HttpUtil.cs index 053ffad..830c6c1 100644 --- a/DamageAssesmentApi/DamageAssesment.Api.Responses/Services/HttpUtil.cs +++ b/DamageAssesmentApi/DamageAssesment.Api.Responses/Services/HttpUtil.cs @@ -1,4 +1,5 @@ -using DamageAssesment.Api.Responses.Interfaces; +using DamageAssesment.Api.Responses.Interfaces; +using DamageAssesment.Api.Responses.Models; using System.Net.Http.Headers; using System.Text; @@ -14,20 +15,18 @@ namespace DamageAssesment.Api.Responses.Services this.httpClient = httpClient; this.logger = logger; } - public async Task SendAsync(HttpMethod method, string url, string JsonInput) + public async Task SendAsync(HttpMethod method, string url, string JsonInput, string token) { try { var request = new HttpRequestMessage(method, url); request.Headers.Accept.Clear(); request.Headers.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json")); - - //request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", token); + request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", token); if (method == HttpMethod.Post) { request.Content = new StringContent(JsonInput, Encoding.UTF8, "application/json"); } - var response = await httpClient.SendAsync(request, CancellationToken.None); response.EnsureSuccessStatusCode(); var responseString = await response.Content.ReadAsStringAsync(); diff --git a/DamageAssesmentApi/DamageAssesment.Api.Responses/Services/LocationServiceProvider.cs b/DamageAssesmentApi/DamageAssesment.Api.Responses/Services/LocationServiceProvider.cs index e6b36f6..2d38ca3 100644 --- a/DamageAssesmentApi/DamageAssesment.Api.Responses/Services/LocationServiceProvider.cs +++ b/DamageAssesmentApi/DamageAssesment.Api.Responses/Services/LocationServiceProvider.cs @@ -10,11 +10,11 @@ namespace DamageAssesment.Api.Responses.Services { } - public async Task> getLocationsAsync() + public async Task> getLocationsAsync(string token) { try { - var responseJsonString = await httpUtil.SendAsync(HttpMethod.Get, url, null); + var responseJsonString = await httpUtil.SendAsync(HttpMethod.Get, url, null, token); var locations = JsonConvert.DeserializeObject>(responseJsonString); if (locations == null || !locations.Any()) diff --git a/DamageAssesmentApi/DamageAssesment.Api.Responses/Services/QuestionServiceProvider.cs b/DamageAssesmentApi/DamageAssesment.Api.Responses/Services/QuestionServiceProvider.cs index 95086b8..4f2e75f 100644 --- a/DamageAssesmentApi/DamageAssesment.Api.Responses/Services/QuestionServiceProvider.cs +++ b/DamageAssesmentApi/DamageAssesment.Api.Responses/Services/QuestionServiceProvider.cs @@ -10,11 +10,11 @@ namespace DamageAssesment.Api.Responses.Services { } - public async Task> getQuestionsAsync() + public async Task> getQuestionsAsync(string token) { try { - var responseJsonString = await httpUtil.SendAsync(HttpMethod.Get, url, null); + var responseJsonString = await httpUtil.SendAsync(HttpMethod.Get, url, null,token); var questions = JsonConvert.DeserializeObject>(responseJsonString); if (questions == null || !questions.Any()) @@ -28,12 +28,12 @@ namespace DamageAssesment.Api.Responses.Services } } - public async Task> getSurveyQuestionsAsync(int surveyId) + public async Task> getSurveyQuestionsAsync(int surveyId, string token) { try { url = urlBase + string.Format(configuration.GetValue("RessourceSettings:SurveyQuestion"), surveyId); - var responseJsonString = await httpUtil.SendAsync(HttpMethod.Get, url, null); + var responseJsonString = await httpUtil.SendAsync(HttpMethod.Get, url, null, token); var questions = JsonConvert.DeserializeObject>(responseJsonString); if (questions == null || !questions.Any()) @@ -48,12 +48,12 @@ namespace DamageAssesment.Api.Responses.Services } - public async Task getQuestionsAsync(int questionId) + public async Task getQuestionsAsync(int questionId, string token) { try { url = urlBase + string.Format(configuration.GetValue("RessourceSettings:QuestionById"), questionId); - var responseJsonString = await httpUtil.SendAsync(HttpMethod.Get, url, null); + var responseJsonString = await httpUtil.SendAsync(HttpMethod.Get, url, null, token); var question = JsonConvert.DeserializeObject(responseJsonString); if (question == null) diff --git a/DamageAssesmentApi/DamageAssesment.Api.Responses/Services/RegionServiceProvider.cs b/DamageAssesmentApi/DamageAssesment.Api.Responses/Services/RegionServiceProvider.cs index 49d3e28..13de3d6 100644 --- a/DamageAssesmentApi/DamageAssesment.Api.Responses/Services/RegionServiceProvider.cs +++ b/DamageAssesmentApi/DamageAssesment.Api.Responses/Services/RegionServiceProvider.cs @@ -9,11 +9,11 @@ namespace DamageAssesment.Api.Responses.Services public RegionServiceProvider(IConfiguration configuration, IHttpUtil httpUtil, ILogger logger) : base(configuration, httpUtil, logger, configuration.GetValue("RessourceSettings:Region"), configuration.GetValue("EndPointSettings:LocationUrlBase")) { } - public async Task> getRegionsAsync() + public async Task> getRegionsAsync(string token) { try { - var responseJsonString = await httpUtil.SendAsync(HttpMethod.Get, url, null); + var responseJsonString = await httpUtil.SendAsync(HttpMethod.Get, url, null, token); var regions = JsonConvert.DeserializeObject>(responseJsonString); if (regions == null || !regions.Any()) diff --git a/DamageAssesmentApi/DamageAssesment.Api.Responses/Services/SurveyServiceProvider.cs b/DamageAssesmentApi/DamageAssesment.Api.Responses/Services/SurveyServiceProvider.cs index a77e1a7..1a30be0 100644 --- a/DamageAssesmentApi/DamageAssesment.Api.Responses/Services/SurveyServiceProvider.cs +++ b/DamageAssesmentApi/DamageAssesment.Api.Responses/Services/SurveyServiceProvider.cs @@ -4,19 +4,19 @@ using Newtonsoft.Json; namespace DamageAssesment.Api.Responses.Services { - public class SurveyServiceProvider : ServiceProviderBase, ISurveyServiceProvider + public class SurveyServiceProvider :ServiceProviderBase, ISurveyServiceProvider { public SurveyServiceProvider(IConfiguration configuration, IHttpUtil httpUtil, ILogger logger) : base(configuration, httpUtil, logger, configuration.GetValue("RessourceSettings:Survey"), configuration.GetValue("EndPointSettings:SurveyUrlBase")) { } - public async Task> getSurveysAsync(string language) + public async Task> getSurveysAsync(string language, string token) { try { if (!string.IsNullOrEmpty(language)) url = url + "/" + language; - var responseJsonString = await httpUtil.SendAsync(HttpMethod.Get, url, null); + var responseJsonString = await httpUtil.SendAsync(HttpMethod.Get, url, null, token); var surveys = JsonConvert.DeserializeObject>(responseJsonString); if (surveys == null || !surveys.Any()) @@ -30,15 +30,15 @@ namespace DamageAssesment.Api.Responses.Services } } - public async Task getSurveyAsync(int surveyId) + public async Task getSurveyAsync(int surveyId, string token) { try { url = urlBase + string.Format(configuration.GetValue("RessourceSettings:SurveyById"), surveyId); - var responseJsonString = await httpUtil.SendAsync(HttpMethod.Get, url, null); + var responseJsonString = await httpUtil.SendAsync(HttpMethod.Get, url, null, token); var survey = JsonConvert.DeserializeObject(responseJsonString); - if (survey == null) + if (survey == null ) return null; else return survey; } diff --git a/DamageAssesmentApi/DamageAssesment.Api.Responses/appsettings.json b/DamageAssesmentApi/DamageAssesment.Api.Responses/appsettings.json index 8829c0b..e7152b6 100644 --- a/DamageAssesmentApi/DamageAssesment.Api.Responses/appsettings.json +++ b/DamageAssesmentApi/DamageAssesment.Api.Responses/appsettings.json @@ -6,7 +6,14 @@ } }, "AllowedHosts": "*", + "JwtSettings": { + "securitykey": "bWlhbWkgZGFkZSBzY2hvb2xzIHNlY3JldCBrZXk=" + }, + "ConnectionStrings": { + "ResponsesConnection": "Server=DESKTOP-OF5DPLQ\\SQLEXPRESS;Database=da_survey_dev;Trusted_Connection=True;TrustServerCertificate=True;" + //"ResponsesConnection": "Server=tcp:da-dev.database.windows.net,1433;Initial Catalog=da-dev-db;Encrypt=True;User ID=admin-dev;Password=b3tgRABw8LGE75k;TrustServerCertificate=False;Connection Timeout=30;" + }, //"EndPointSettings": { // "AnswerUrlBase": "http://localhost:5200", // "LocationUrlBase": "http://localhost:5213", @@ -16,7 +23,6 @@ // "AttachmentUrlBase": "http://localhost:5243", // "SurveyUrlBase": "http://localhost:5009" //}, - //Endpoints for docker-container "EndPointSettings": { "AnswerUrlBase": "http://damageassesment.api.answers:80", "LocationUrlBase": "http://damageassesment.api.locations:80", @@ -39,10 +45,5 @@ "AnswerByResponse": "/answers/byresponse/{0}", "Location": "/locations", "Region": "/regions" - }, - "ConnectionStrings": { - //"SurveyResponseConnection": "Server=DESKTOP-OF5DPLQ\\SQLEXPRESS;Database=da_survey_dev;Trusted_Connection=True;TrustServerCertificate=True;" - // "ResponsesConnection": "Server=localhost,1433;Database=da_survey_dev;User Id=sa;Password=Password123;TrustServerCertificate=True;", - "ResponsesConnection": "Server=207.180.248.35;Database=da_survey_dev;User Id=sa;Password=YourStrongPassw0rd;TrustServerCertificate=True;" } } diff --git a/DamageAssesmentApi/DamageAssesment.Api.SurveyResponses/Migrations/20230817221348_InitialSurveyResponse.Designer.cs b/DamageAssesmentApi/DamageAssesment.Api.SurveyResponses/Migrations/20230817221348_InitialSurveyResponse.Designer.cs deleted file mode 100644 index edec629..0000000 --- a/DamageAssesmentApi/DamageAssesment.Api.SurveyResponses/Migrations/20230817221348_InitialSurveyResponse.Designer.cs +++ /dev/null @@ -1,55 +0,0 @@ -// -using DamageAssesment.Api.SurveyResponses.Db; -using Microsoft.EntityFrameworkCore; -using Microsoft.EntityFrameworkCore.Infrastructure; -using Microsoft.EntityFrameworkCore.Metadata; -using Microsoft.EntityFrameworkCore.Migrations; -using Microsoft.EntityFrameworkCore.Storage.ValueConversion; - -#nullable disable - -namespace DamageAssesment.Api.SurveyResponses.Migrations -{ - [DbContext(typeof(SurveyResponseDbContext))] - [Migration("20230817221348_InitialSurveyResponse")] - partial class InitialSurveyResponse - { - /// - protected override void BuildTargetModel(ModelBuilder modelBuilder) - { -#pragma warning disable 612, 618 - modelBuilder - .HasAnnotation("ProductVersion", "7.0.9") - .HasAnnotation("Relational:MaxIdentifierLength", 128); - - SqlServerModelBuilderExtensions.UseIdentityColumns(modelBuilder); - - modelBuilder.Entity("DamageAssesment.Api.SurveyResponses.Db.SurveyResponse", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("int"); - - SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); - - b.Property("EmployeeId") - .IsRequired() - .HasMaxLength(6) - .HasColumnType("nvarchar(6)"); - - b.Property("LocationId") - .IsRequired() - .HasMaxLength(4) - .HasColumnType("nvarchar(4)"); - - b.Property("SurveyId") - .HasColumnType("int"); - - b.HasKey("Id"); - - b.ToTable("SurveyResponses"); - }); -#pragma warning restore 612, 618 - } - } -} diff --git a/DamageAssesmentApi/DamageAssesment.Api.SurveyResponses/Migrations/20230817221348_InitialSurveyResponse.cs b/DamageAssesmentApi/DamageAssesment.Api.SurveyResponses/Migrations/20230817221348_InitialSurveyResponse.cs deleted file mode 100644 index e886ab1..0000000 --- a/DamageAssesmentApi/DamageAssesment.Api.SurveyResponses/Migrations/20230817221348_InitialSurveyResponse.cs +++ /dev/null @@ -1,36 +0,0 @@ -using Microsoft.EntityFrameworkCore.Migrations; - -#nullable disable - -namespace DamageAssesment.Api.SurveyResponses.Migrations -{ - /// - public partial class InitialSurveyResponse : Migration - { - /// - protected override void Up(MigrationBuilder migrationBuilder) - { - migrationBuilder.CreateTable( - name: "SurveyResponses", - columns: table => new - { - Id = table.Column(type: "int", nullable: false) - .Annotation("SqlServer:Identity", "1, 1"), - SurveyId = table.Column(type: "int", nullable: false), - LocationId = table.Column(type: "nvarchar(4)", maxLength: 4, nullable: false), - EmployeeId = table.Column(type: "nvarchar(6)", maxLength: 6, nullable: false) - }, - constraints: table => - { - table.PrimaryKey("PK_SurveyResponses", x => x.Id); - }); - } - - /// - protected override void Down(MigrationBuilder migrationBuilder) - { - migrationBuilder.DropTable( - name: "SurveyResponses"); - } - } -} diff --git a/DamageAssesmentApi/DamageAssesment.Api.SurveyResponses/Migrations/SurveyResponseDbContextModelSnapshot.cs b/DamageAssesmentApi/DamageAssesment.Api.SurveyResponses/Migrations/SurveyResponseDbContextModelSnapshot.cs deleted file mode 100644 index 1870d21..0000000 --- a/DamageAssesmentApi/DamageAssesment.Api.SurveyResponses/Migrations/SurveyResponseDbContextModelSnapshot.cs +++ /dev/null @@ -1,52 +0,0 @@ -// -using DamageAssesment.Api.SurveyResponses.Db; -using Microsoft.EntityFrameworkCore; -using Microsoft.EntityFrameworkCore.Infrastructure; -using Microsoft.EntityFrameworkCore.Metadata; -using Microsoft.EntityFrameworkCore.Storage.ValueConversion; - -#nullable disable - -namespace DamageAssesment.Api.SurveyResponses.Migrations -{ - [DbContext(typeof(SurveyResponseDbContext))] - partial class SurveyResponseDbContextModelSnapshot : ModelSnapshot - { - protected override void BuildModel(ModelBuilder modelBuilder) - { -#pragma warning disable 612, 618 - modelBuilder - .HasAnnotation("ProductVersion", "7.0.9") - .HasAnnotation("Relational:MaxIdentifierLength", 128); - - SqlServerModelBuilderExtensions.UseIdentityColumns(modelBuilder); - - modelBuilder.Entity("DamageAssesment.Api.SurveyResponses.Db.SurveyResponse", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("int"); - - SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); - - b.Property("EmployeeId") - .IsRequired() - .HasMaxLength(6) - .HasColumnType("nvarchar(6)"); - - b.Property("LocationId") - .IsRequired() - .HasMaxLength(4) - .HasColumnType("nvarchar(4)"); - - b.Property("SurveyId") - .HasColumnType("int"); - - b.HasKey("Id"); - - b.ToTable("SurveyResponses"); - }); -#pragma warning restore 612, 618 - } - } -} diff --git a/DamageAssesmentApi/DamageAssesment.Api.Surveys/Controllers/SurveysController.cs b/DamageAssesmentApi/DamageAssesment.Api.Surveys/Controllers/SurveysController.cs index b93120b..2a4415c 100644 --- a/DamageAssesmentApi/DamageAssesment.Api.Surveys/Controllers/SurveysController.cs +++ b/DamageAssesmentApi/DamageAssesment.Api.Surveys/Controllers/SurveysController.cs @@ -1,4 +1,5 @@ using DamageAssesment.Api.Surveys.Interfaces; +using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; namespace DamageAssesment.Api.Surveys.Controllers @@ -15,6 +16,7 @@ namespace DamageAssesment.Api.Surveys.Controllers /// /// GET request for retrieving surveys. /// + [Authorize(Roles ="admin,survey,user,report")] [Route("surveys")] [Route("surveys/{language:alpha}")] [HttpGet] @@ -31,6 +33,7 @@ namespace DamageAssesment.Api.Surveys.Controllers /// /// GET request for retrieving surveys by ID. /// + [Authorize(Roles = "admin,survey,user,report")] [Route("surveys/{id:int}")] [Route("surveys/{id:int}/{language:alpha}")] [HttpGet] @@ -46,6 +49,7 @@ namespace DamageAssesment.Api.Surveys.Controllers /// /// POST request for creating a new survey. /// + [Authorize(Roles = "admin,survey,user,report")] [HttpPost("surveys")] public async Task PostSurveysAsync(Models.Survey survey) { @@ -59,6 +63,8 @@ namespace DamageAssesment.Api.Surveys.Controllers /// /// PUT request for updating an existing survey (surveyId,Updated Survey data). /// + + [Authorize(Roles = "admin,survey")] [HttpPut("surveys/{id}")] public async Task PutSurveysAsync(int id, Models.Survey survey) { @@ -76,6 +82,7 @@ namespace DamageAssesment.Api.Surveys.Controllers /// /// DELETE request for deleting a survey by ID. /// + [Authorize(Roles = "admin,survey")] [HttpDelete("surveys/{id}")] public async Task DeleteSurveysAsync(int id) { diff --git a/DamageAssesmentApi/DamageAssesment.Api.Surveys/Program.cs b/DamageAssesmentApi/DamageAssesment.Api.Surveys/Program.cs index 178b5fd..6d79d25 100644 --- a/DamageAssesmentApi/DamageAssesment.Api.Surveys/Program.cs +++ b/DamageAssesmentApi/DamageAssesment.Api.Surveys/Program.cs @@ -6,6 +6,7 @@ using Microsoft.EntityFrameworkCore; using Microsoft.IdentityModel.Tokens; using System.Text; using System.Reflection; +using Microsoft.OpenApi.Models; var builder = WebApplication.CreateBuilder(args); @@ -34,14 +35,44 @@ builder.Services.AddControllers(); builder.Services.AddScoped(); builder.Services.AddAutoMapper(AppDomain.CurrentDomain.GetAssemblies()); builder.Services.AddEndpointsApiExplorer(); -//builder.Services.AddSwaggerGen(); -builder.Services.AddSwaggerGen(c => + +builder.Services.AddSwaggerGen(options => { // Include XML comments from your assembly var xmlFile = $"{Assembly.GetExecutingAssembly().GetName().Name}.xml"; var xmlPath = Path.Combine(AppContext.BaseDirectory, xmlFile); - c.IncludeXmlComments(xmlPath); + options.IncludeXmlComments(xmlPath); + + OpenApiSecurityScheme securityDefinition = new OpenApiSecurityScheme() + { + Name = "Bearer", + BearerFormat = "JWT", + Scheme = "bearer", + Description = "Specify the authorization token.", + In = ParameterLocation.Header, + Type = SecuritySchemeType.Http, + }; + + options.AddSecurityDefinition("jwt_auth", securityDefinition); + + // Make sure swagger UI requires a Bearer token specified + OpenApiSecurityScheme securityScheme = new OpenApiSecurityScheme() + { + Reference = new OpenApiReference() + { + Id = "jwt_auth", + Type = ReferenceType.SecurityScheme + } + }; + + OpenApiSecurityRequirement securityRequirements = new OpenApiSecurityRequirement() + { + {securityScheme, new string[] { }}, + }; + + options.AddSecurityRequirement(securityRequirements); }); + builder.Services.AddDbContext(option => { option.UseSqlServer("SurveyConnection"); diff --git a/DamageAssesmentApi/DamageAssesment.Api.Surveys/Providers/SurveysProvider.cs b/DamageAssesmentApi/DamageAssesment.Api.Surveys/Providers/SurveysProvider.cs index fe09798..5acb580 100644 --- a/DamageAssesmentApi/DamageAssesment.Api.Surveys/Providers/SurveysProvider.cs +++ b/DamageAssesmentApi/DamageAssesment.Api.Surveys/Providers/SurveysProvider.cs @@ -95,7 +95,6 @@ namespace DamageAssesment.Api.Surveys.Providers logger?.LogInformation("Get all Surveys from DB"); //checking is enabled in survey response var surveys = await surveyDbContext.Surveys.ToListAsync();//Where(s => s.IsEnabled == true) - if (surveys != null) { surveysList = from s in surveys diff --git a/DamageAssesmentApi/DamageAssesment.Api.Surveys/appsettings.json b/DamageAssesmentApi/DamageAssesment.Api.Surveys/appsettings.json index 99bf950..cba9277 100644 --- a/DamageAssesmentApi/DamageAssesment.Api.Surveys/appsettings.json +++ b/DamageAssesmentApi/DamageAssesment.Api.Surveys/appsettings.json @@ -10,8 +10,8 @@ }, "AllowedHosts": "*", "ConnectionStrings": { - //"SurveyConnection": "Server=DESKTOP-OF5DPLQ\\SQLEXPRESS;Database=da_survey_dev;Trusted_Connection=True;TrustServerCertificate=True;" - //"SurveyConnection": "Server=localhost,1433;Database=da_survey_dev;User Id=sa;Password=Password123;TrustServerCertificate=True;", - "SurveyConnection": "Server=207.180.248.35;Database=da_survey_dev;User Id=sa;Password=YourStrongPassw0rd;TrustServerCertificate=True;" + "SurveyConnection": "Server=DESKTOP-OF5DPLQ\\SQLEXPRESS;Database=da_survey_dev;Trusted_Connection=True;TrustServerCertificate=True;" + //"SurveyConnection": "Server=tcp:da-dev.database.windows.net,1433;Initial Catalog=da-dev-db;Encrypt=True;User ID=admin-dev;Password=b3tgRABw8LGE75k;TrustServerCertificate=False;Connection Timeout=30;" + } } diff --git a/DamageAssesmentApi/DamageAssesment.Api.UsersAccess.Test/DamageAssesment.Api.UsersAccess.Test.csproj b/DamageAssesmentApi/DamageAssesment.Api.UsersAccess.Test/DamageAssesment.Api.UsersAccess.Test.csproj new file mode 100644 index 0000000..e655693 --- /dev/null +++ b/DamageAssesmentApi/DamageAssesment.Api.UsersAccess.Test/DamageAssesment.Api.UsersAccess.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.UsersAccess.Test/MockData.cs b/DamageAssesmentApi/DamageAssesment.Api.UsersAccess.Test/MockData.cs new file mode 100644 index 0000000..b25ec9a --- /dev/null +++ b/DamageAssesmentApi/DamageAssesment.Api.UsersAccess.Test/MockData.cs @@ -0,0 +1,44 @@ +using DamageAssesment.Api.UsersAccess.Models; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Xunit.Sdk; + +namespace DamageAssesment.Api.UsersAccess.Test +{ + public class MockData + { + public static async Task<(bool, Models.TokenResponse, string)> getTokenResponse(bool status, string message) + { + return (status, new Models.TokenResponse { jwttoken = "1234", refreshtoken = "12345" }, message); + } + + public static async Task<(bool, List, string)> getUsers(bool status, string message) + { + List users = new List(); + users.Add(new User { Id = 1, EmployeeCode = "Emp1", EmployeeId = 1, RoleId = 1, IsActive = true, CreateDate = DateTime.Now }); + users.Add(new User { Id = 2, EmployeeCode = "Emp2", EmployeeId = 2, RoleId = 1, IsActive = true, CreateDate = DateTime.Now }); + users.Add(new User { Id = 3, EmployeeCode = "Emp3", EmployeeId = 3, RoleId = 1, IsActive = true, CreateDate = DateTime.Now }); + return (status, users, message); + } + + public static async Task<(bool, User, string)> getUser(bool status, string message) + { + User user = getUsers(status, message).Result.Item2.FirstOrDefault(); + return (status, user, message); + } + + public static async Task<(bool, List, string)> getRoles(bool status, string message) + { + List roles = new List(); + roles.Add(new Role { Id = 1, Name = "Role 1" }); + roles.Add(new Role { Id = 2, Name = "Role 2" }); + roles.Add(new Role { Id = 3, Name = "Role 3" }); + + return (status, roles, message); + } + + } +} diff --git a/DamageAssesmentApi/DamageAssesment.Api.UsersAccess.Test/UsersAccessTest.cs b/DamageAssesmentApi/DamageAssesment.Api.UsersAccess.Test/UsersAccessTest.cs new file mode 100644 index 0000000..46165f3 --- /dev/null +++ b/DamageAssesmentApi/DamageAssesment.Api.UsersAccess.Test/UsersAccessTest.cs @@ -0,0 +1,194 @@ +using DamageAssesment.Api.UsersAccess.Controllers; +using DamageAssesment.Api.UsersAccess.Interfaces; +using Microsoft.AspNetCore.Mvc; +using Moq; +using Xunit; + +namespace DamageAssesment.Api.UsersAccess.Test +{ + public class UsersAccessTest + { + private Mock mockService; + + public UsersAccessTest() + { + mockService = new Mock(); + } + [Fact(DisplayName = "Get Token - Ok case")] + public async Task GetTokenAsync_ShouldReturnStatusCode200() + { + var response = await MockData.getTokenResponse(true,null); + mockService.Setup(service => service.AuthenticateAsync("Emp1")).ReturnsAsync(response); + var controller = new UsersAccessController(mockService.Object); + var result = (OkObjectResult)await controller.AuthenticateAsync("Emp1"); + Assert.Equal(200, result.StatusCode); + } + + [Fact(DisplayName = "Get Token - Unauthorized case")] + public async Task GetTokenAsync_ShouldReturnStatusCode401() + { + var response = await MockData.getTokenResponse(false, null); + mockService.Setup(service => service.AuthenticateAsync("Emp1")).ReturnsAsync(response); + var controller = new UsersAccessController(mockService.Object); + var result = (UnauthorizedObjectResult)await controller.AuthenticateAsync("Emp1"); + Assert.Equal(401, result.StatusCode); + } + + + [Fact(DisplayName = "RefreshToken - Ok case")] + public async Task RefreshTokenAsync_ShouldReturnStatusCode200() + { + var response = await MockData.getTokenResponse(true, null); + mockService.Setup(service => service.RefreshTokenAsync(null)).ReturnsAsync(response); + var controller = new UsersAccessController(mockService.Object); + var result = (OkObjectResult)await controller.RefreshTokenAsync(null); + Assert.Equal(200, result.StatusCode); + } + + [Fact(DisplayName = "RefreshToken - Unauthorized case")] + public async Task RefreshTokenAsync_ShouldReturnStatusCode401() + { + var response = await MockData.getTokenResponse(false, null); + mockService.Setup(service => service.RefreshTokenAsync(null)).ReturnsAsync(response); + var controller = new UsersAccessController(mockService.Object); + var result = (UnauthorizedObjectResult)await controller.RefreshTokenAsync(null); + Assert.Equal(401, result.StatusCode); + } + + [Fact(DisplayName = "GetUsers - Ok case")] + public async Task GetUsersAsync_ShouldReturnStatusCode200() + { + var response = await MockData.getUsers(true, null); + mockService.Setup(service => service.GetUsersAsync()).ReturnsAsync(response); + var controller = new UsersAccessController(mockService.Object); + var result = (OkObjectResult)await controller.GetUsersAsync(); + Assert.Equal(200, result.StatusCode); + } + + [Fact(DisplayName = "GetUsers - NoContent case")] + public async Task GetUsersAsync_ShouldReturnStatusCode204() + { + var response = await MockData.getUsers(false, null); + mockService.Setup(service => service.GetUsersAsync()).ReturnsAsync(response); + var controller = new UsersAccessController(mockService.Object); + var result = (NoContentResult)await controller.GetUsersAsync(); + Assert.Equal(204, result.StatusCode); + } + + [Fact(DisplayName = "GetUser - Ok case")] + public async Task GetUserAsync_ShouldReturnStatusCode200() + { + var response = await MockData.getUser(true, null); + mockService.Setup(service => service.GetUsersAsync(1)).ReturnsAsync(response); + var controller = new UsersAccessController(mockService.Object); + var result = (OkObjectResult)await controller.GetUsersAsync(1); + Assert.Equal(200, result.StatusCode); + } + + [Fact(DisplayName = "GetUser - NotFound case")] + public async Task GetUserAsync_ShouldReturnStatusCode204() + { + var response = await MockData.getUser(false, null); + mockService.Setup(service => service.GetUsersAsync(1)).ReturnsAsync(response); + var controller = new UsersAccessController(mockService.Object); + var result = (NotFoundResult)await controller.GetUsersAsync(1); + Assert.Equal(404, result.StatusCode); + } + + [Fact(DisplayName = "GetRoles - Ok case")] + public async Task GetRolesAsync_ShouldReturnStatusCode200() + { + var response = await MockData.getRoles(true, null); + mockService.Setup(service => service.GetRolesAsync()).ReturnsAsync(response); + var controller = new UsersAccessController(mockService.Object); + var result = (OkObjectResult)await controller.GetRolesAsync(); + Assert.Equal(200, result.StatusCode); + } + + [Fact(DisplayName = "GetRoles - NoContent case")] + public async Task GetRolesAsync_ShouldReturnStatusCode204() + { + var response = await MockData.getRoles(false, null); + mockService.Setup(service => service.GetRolesAsync()).ReturnsAsync(response); + var controller = new UsersAccessController(mockService.Object); + var result = (NoContentResult)await controller.GetRolesAsync(); + Assert.Equal(204, result.StatusCode); + } + + [Fact(DisplayName = "PostUser - Ok case")] + public async Task PostUserAsync_ShouldReturnStatusCode200() + { + var response = await MockData.getUser(true, null); + var user = new Models.User { Id = 1, EmployeeCode = "Emp1", EmployeeId = 1, RoleId = 1, IsActive = true, CreateDate = DateTime.Now }; + mockService.Setup(service => service.PostUserAsync(user)).ReturnsAsync(response); + var controller = new UsersAccessController(mockService.Object); + var result = (OkObjectResult)await controller.PostUserAsync(user); + Assert.Equal(200, result.StatusCode); + } + + [Fact(DisplayName = "PostUser - Bad Request case")] + public async Task PostUserAsync_ShouldReturnStatusCode400() + { + var response = await MockData.getUser(false, null); + var user = new Models.User { Id = 1, EmployeeCode = "Emp1", EmployeeId = 1, RoleId = 1, IsActive = true, CreateDate = DateTime.Now }; + mockService.Setup(service => service.PostUserAsync(user)).ReturnsAsync(response); + var controller = new UsersAccessController(mockService.Object); + var result = (BadRequestObjectResult)await controller.PostUserAsync(user); + Assert.Equal(400, result.StatusCode); + } + + [Fact(DisplayName = "PutUser - Ok case")] + public async Task PutUserAsync_ShouldReturnStatusCode200() + { + var response = await MockData.getUser(true, null); + var user = new Models.User { Id = 1, EmployeeCode = "Emp1", EmployeeId = 1, RoleId = 1, IsActive = true, CreateDate = DateTime.Now }; + mockService.Setup(service => service.PutUserAsync(1,user)).ReturnsAsync(response); + var controller = new UsersAccessController(mockService.Object); + var result = (OkObjectResult)await controller.PutUserAsync(1,user); + Assert.Equal(200, result.StatusCode); + } + + [Fact(DisplayName = "PutUser - BadRequest case")] + public async Task PutUserAsync_ShouldReturnStatusCode400() + { + var response = await MockData.getUser(false, null); + var user = new Models.User { Id = 1, EmployeeCode = "Emp1", EmployeeId = 1, RoleId = 1, IsActive = true, CreateDate = DateTime.Now }; + mockService.Setup(service => service.PutUserAsync(1,user)).ReturnsAsync(response); + var controller = new UsersAccessController(mockService.Object); + var result = (BadRequestObjectResult)await controller.PutUserAsync(1,user); + Assert.Equal(400, result.StatusCode); + } + + [Fact(DisplayName = "PutUser - Not Found case")] + public async Task PutUserAsync_ShouldReturnStatusCode404() + { + var response = await MockData.getUser(false, "Not Found"); + var user = new Models.User { Id = 1, EmployeeCode = "Emp1", EmployeeId = 1, RoleId = 1, IsActive = true, CreateDate = DateTime.Now }; + mockService.Setup(service => service.PutUserAsync(1, user)).ReturnsAsync(response); + var controller = new UsersAccessController(mockService.Object); + var result = (NotFoundObjectResult)await controller.PutUserAsync(1,user); + Assert.Equal(404, result.StatusCode); + } + + + [Fact(DisplayName = "DeleteUser - Ok case")] + public async Task DeleteUserAsync_ShouldReturnStatusCode200() + { + var response = await MockData.getUser(true, null); + mockService.Setup(service => service.DeleteUserAsync(1)).ReturnsAsync(response); + var controller = new UsersAccessController(mockService.Object); + var result = (OkObjectResult)await controller.DeleteUserAsync(1); + Assert.Equal(200, result.StatusCode); + } + + [Fact(DisplayName = "DeleteUser - Not Found case")] + public async Task DeleteUserAsync_ShouldReturnStatusCode404() + { + var response = await MockData.getUser(false, "Not Found"); + mockService.Setup(service => service.DeleteUserAsync(1)).ReturnsAsync(response); + var controller = new UsersAccessController(mockService.Object); + var result = (NotFoundResult)await controller.DeleteUserAsync(1); + Assert.Equal(404, result.StatusCode); + } + } +} \ No newline at end of file diff --git a/DamageAssesmentApi/DamageAssesment.Api.UsersAccess/Controllers/UsersAccessController.cs b/DamageAssesmentApi/DamageAssesment.Api.UsersAccess/Controllers/UsersAccessController.cs new file mode 100644 index 0000000..e0aae67 --- /dev/null +++ b/DamageAssesmentApi/DamageAssesment.Api.UsersAccess/Controllers/UsersAccessController.cs @@ -0,0 +1,117 @@ +using DamageAssesment.Api.UsersAccess.Interfaces; +using DamageAssesment.Api.UsersAccess.Models; +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Mvc; + +namespace DamageAssesment.Api.UsersAccess.Controllers +{ + [ApiController] + public class UsersAccessController : ControllerBase + { + private IUsersAccessProvider userAccessProvider; + + public UsersAccessController(IUsersAccessProvider userAccessProvider) + { + this.userAccessProvider = userAccessProvider; + } + [Authorize(Policy = "Dadeschools")] + [HttpPost("token/{employecode}")] + public async Task AuthenticateAsync(string employecode) + { + var result = await userAccessProvider.AuthenticateAsync(employecode); + if (result.IsSuccess) + { + return Ok(result.TokenResponse); + } + return Unauthorized(result.ErrorMessage); + } + + [Authorize(Policy = "Dadeschools")] + [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); + } + + [Authorize(Policy = "DamageApp", Roles ="admin")] + [HttpGet("users")] + public async Task GetUsersAsync() + { + var result = await userAccessProvider.GetUsersAsync(); + if (result.IsSuccess) + { + return Ok(result.Users); + } + return NoContent(); + } + + [Authorize(Policy = "DamageApp", Roles = "admin")] + [HttpGet("users/{Id}")] + public async Task GetUsersAsync(int Id) + { + var result = await userAccessProvider.GetUsersAsync(Id); + if (result.IsSuccess) + { + return Ok(result.User); + } + return NotFound(); + } + + [Authorize(Policy = "DamageApp", Roles = "admin")] + [HttpGet("roles")] + public async Task GetRolesAsync() + { + var result = await userAccessProvider.GetRolesAsync(); + if (result.IsSuccess) + { + return Ok(result.Roles); + } + return NoContent(); + } + [Authorize(Policy = "DamageApp", Roles = "admin")] + [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); + } + + [Authorize(Policy = "DamageApp", Roles = "admin")] + [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); + } + + [Authorize(Policy = "DamageApp", Roles = "admin")] + [HttpDelete("users/{Id}")] + public async Task DeleteUserAsync(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..6c6eb21 --- /dev/null +++ b/DamageAssesmentApi/DamageAssesment.Api.UsersAccess/DamageAssesment.Api.UsersAccess.csproj @@ -0,0 +1,29 @@ + + + + net6.0 + enable + enable + + + + + + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + + + + + 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..bdfe576 --- /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 int 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..f99deb8 --- /dev/null +++ b/DamageAssesmentApi/DamageAssesment.Api.UsersAccess/Db/User.cs @@ -0,0 +1,31 @@ +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 int EmployeeId { get; set; } + + [Required] + [StringLength(50)] + public string EmployeeCode { 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..157dfb3 --- /dev/null +++ b/DamageAssesmentApi/DamageAssesment.Api.UsersAccess/Db/UsersAccessDbContext.cs @@ -0,0 +1,39 @@ +using Microsoft.EntityFrameworkCore; +using Microsoft.Extensions.Configuration; + +namespace DamageAssesment.Api.UsersAccess.Db +{ + public class UsersAccessDbContext : DbContext + { + public DbSet Users { get; set; } + public DbSet Roles { get; set; } + public DbSet Tokens { get; set; } + private IConfiguration _Configuration { get; set; } + public UsersAccessDbContext(DbContextOptions options, IConfiguration configuration) : base(options) + { + _Configuration = configuration; + } + protected override void OnConfiguring(DbContextOptionsBuilder options) + { + // connect to sql server with connection string from app settings + options.UseSqlServer(_Configuration.GetConnectionString("UsersAccessConnection")); + } + + protected override void OnModelCreating(ModelBuilder modelBuilder) + { + base.OnModelCreating(modelBuilder); + + modelBuilder.Entity() + .Property(item => item.Id) + .ValueGeneratedOnAdd(); + + modelBuilder.Entity() + .Property(item => item.Id) + .ValueGeneratedOnAdd(); + + modelBuilder.Entity() + .Property(item => item.Id) + .ValueGeneratedOnAdd(); + } + } +} diff --git a/DamageAssesmentApi/DamageAssesment.Api.UsersAccess/Interfaces/IEmployeeServiceProvider.cs b/DamageAssesmentApi/DamageAssesment.Api.UsersAccess/Interfaces/IEmployeeServiceProvider.cs new file mode 100644 index 0000000..255a954 --- /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(int 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..6115e7c --- /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(Models.User user); + Task TokenAuthenticate(Models.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..ea64376 --- /dev/null +++ b/DamageAssesmentApi/DamageAssesment.Api.UsersAccess/Interfaces/IUsersAccessProvider.cs @@ -0,0 +1,17 @@ +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(string employeCode); + public Task<(bool IsSuccess, Models.TokenResponse TokenResponse, string ErrorMessage)>RefreshTokenAsync(TokenResponse tokenResponse); + public void seedData(); + } +} diff --git a/DamageAssesmentApi/DamageAssesment.Api.UsersAccess/Interfaces/Interface.cs b/DamageAssesmentApi/DamageAssesment.Api.UsersAccess/Interfaces/Interface.cs new file mode 100644 index 0000000..3d0a8ed --- /dev/null +++ b/DamageAssesmentApi/DamageAssesment.Api.UsersAccess/Interfaces/Interface.cs @@ -0,0 +1,7 @@ +namespace DamageAssesment.Api.UsersAccess.Interfaces +{ + public interface IHttpUtil + { + Task SendAsync(HttpMethod method, string url, string JsonInput); + } +} diff --git a/DamageAssesmentApi/DamageAssesment.Api.UsersAccess/Models/Employee.cs b/DamageAssesmentApi/DamageAssesment.Api.UsersAccess/Models/Employee.cs new file mode 100644 index 0000000..b08d156 --- /dev/null +++ b/DamageAssesmentApi/DamageAssesment.Api.UsersAccess/Models/Employee.cs @@ -0,0 +1,14 @@ +namespace DamageAssesment.Api.UsersAccess.Models +{ + public class Employee + { + public int Id { get; set; } + public string EmployeeCode { get; set; } + public string Name { get; set; } + public DateTime BirthDate { get; set; } + public string OfficePhoneNumber { get; set; } + public string Email { get; set; } + public bool IsActive { get; set; } + public string PreferredLanguage { get; set; } + } +} 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..a275c60 --- /dev/null +++ b/DamageAssesmentApi/DamageAssesment.Api.UsersAccess/Models/Role.cs @@ -0,0 +1,8 @@ +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..87f1ae3 --- /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..e43bc20 --- /dev/null +++ b/DamageAssesmentApi/DamageAssesment.Api.UsersAccess/Models/User.cs @@ -0,0 +1,13 @@ +namespace DamageAssesment.Api.UsersAccess.Models +{ + public class User + { + public int Id { get; set; } + public int EmployeeId { get; set; } + public string EmployeeCode { 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..cf01fa3 --- /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..567e613 --- /dev/null +++ b/DamageAssesmentApi/DamageAssesment.Api.UsersAccess/Program.cs @@ -0,0 +1,146 @@ +using DamageAssesment.Api.UsersAccess.Db; +using DamageAssesment.Api.UsersAccess.Interfaces; +using DamageAssesment.Api.UsersAccess.Providers; +using DamageAssesment.Api.UsersAccess.Models; +using Microsoft.EntityFrameworkCore; +using Microsoft.IdentityModel.Tokens; +using System.Text; +using Polly; +using DamageAssesment.Api.UsersAccess.Services; +using Microsoft.OpenApi.Models; +using System.Reflection; +using Microsoft.AspNetCore.Authorization; + +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(). + AddJwtBearer("DamageApp", 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 + }; +}).AddJwtBearer("Dadeschools", options => +{ + options.Authority = builder.Configuration["Dadeschools:Authority"]; + options.TokenValidationParameters.ValidTypes = new[] { "at+jwt" }; + options.TokenValidationParameters.ValidateAudience = false; +}); + + +builder.Services.AddAuthorization(options => +{ + var DamageAppPolicy = new AuthorizationPolicyBuilder() + .RequireAuthenticatedUser() + .AddAuthenticationSchemes("DamageApp") + .Build(); + var DadeschoolsPolicy = new AuthorizationPolicyBuilder() + .RequireAuthenticatedUser() + .AddAuthenticationSchemes("Dadeschools") + .Build(); + var allPolicy = new AuthorizationPolicyBuilder() + .RequireAuthenticatedUser() + .AddAuthenticationSchemes("DamageApp", "Dadeschools") + .Build(); + options.AddPolicy("DamageApp", DamageAppPolicy); + options.AddPolicy("Dadeschools", DadeschoolsPolicy); + options.AddPolicy("AllPolicies", allPolicy); + options.DefaultPolicy = options.GetPolicy("DamageApp")!; +}); + +var _jwtsettings = builder.Configuration.GetSection("JwtSettings"); +builder.Services.Configure(_jwtsettings); + +builder.Services.AddControllers(); +// Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle +builder.Services.AddScoped(); +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.AddAutoMapper(AppDomain.CurrentDomain.GetAssemblies()); +builder.Services.AddEndpointsApiExplorer(); +//builder.Services.AddSwaggerGen(); + +builder.Services.AddSwaggerGen(options => +{ + + // Include XML comments from your assembly + var xmlFile = $"{Assembly.GetExecutingAssembly().GetName().Name}.xml"; + var xmlPath = Path.Combine(AppContext.BaseDirectory, xmlFile); + //options.IncludeXmlComments(xmlPath); + + OpenApiSecurityScheme securityDefinition = new OpenApiSecurityScheme() + { + Name = "Bearer", + BearerFormat = "JWT", + Scheme = "bearer", + Description = "Specify the authorization token.", + In = ParameterLocation.Header, + Type = SecuritySchemeType.Http, + }; + + options.AddSecurityDefinition("jwt_auth", securityDefinition); + + // Make sure swagger UI requires a Bearer token specified + OpenApiSecurityScheme securityScheme = new OpenApiSecurityScheme() + { + Reference = new OpenApiReference() + { + Id = "jwt_auth", + Type = ReferenceType.SecurityScheme + } + }; + + OpenApiSecurityRequirement securityRequirements = new OpenApiSecurityRequirement() + { + {securityScheme, new string[] { }}, + }; + + options.AddSecurityRequirement(securityRequirements); +}); + +builder.Services.AddDbContext(option => +{ + option.UseSqlServer("UsersAccessConnection"); +}); +var app = builder.Build(); + +// Configure the HTTP request pipeline. +if (app.Environment.IsDevelopment()) +{ + app.UseSwagger(); + app.UseSwaggerUI(); + + using (var serviceScope = app.Services.CreateScope()) + { + var services = serviceScope.ServiceProvider; + var usersAccessProvider = services.GetRequiredService(); + usersAccessProvider.seedData(); + } +} + +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/UserAccessProvider.cs b/DamageAssesmentApi/DamageAssesment.Api.UsersAccess/Providers/UserAccessProvider.cs new file mode 100644 index 0000000..a599053 --- /dev/null +++ b/DamageAssesmentApi/DamageAssesment.Api.UsersAccess/Providers/UserAccessProvider.cs @@ -0,0 +1,305 @@ +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(); + } + + public void seedData() + { + if (!userAccessDbContext.Users.Any()) + { + userAccessDbContext.Users.Add(new Db.User { EmployeeId = 1, EmployeeCode = "Emp1", RoleId = 1, IsActive = true, CreateDate = DateTime.Now }); + userAccessDbContext.Users.Add(new Db.User { EmployeeId = 2, EmployeeCode = "Emp2", RoleId = 2, IsActive = true, CreateDate = DateTime.Now }); + //userAccessDbContext.Users.Add(new Db.User { EmployeeId = 3, EmployeeCode = "Emp3", RoleId = 3, IsActive = true, CreateDate = DateTime.Now }); + userAccessDbContext.SaveChanges(); + } + + if (!userAccessDbContext.Roles.Any()) + { + userAccessDbContext.Roles.Add(new Db.Role { Name = "admin", Description ="Administrator role have full access" }); + userAccessDbContext.Roles.Add(new Db.Role { Name = "user", Description =" User role"}); + userAccessDbContext.Roles.Add(new Db.Role { Name = "survey", Description ="Survey role" }); + userAccessDbContext.Roles.Add(new Db.Role { Name = "report", Description ="Report role"}); + userAccessDbContext.Roles.Add(new Db.Role { Name = "document", Description ="Document role" }); + 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 _user = mapper.Map(user); + userAccessDbContext.Users.Add(_user); + user.Id = _user.Id; + await userAccessDbContext.SaveChangesAsync(); + return (true, user, "Successful"); + } + else + { + logger?.LogInformation($"null object cannot be added"); + return (false, null, $"null object 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.AsNoTracking().Where(s => s.Id == Id).SingleOrDefaultAsync(); + + if (_user != null) + { + int count = userAccessDbContext.Users.Where(u => u.Id != user.Id).Count(); + if (count == 0) + { + 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(string employecode) + { + + if (employecode != null) + { + //implementation for dadeschools authentication + // var employees = await employeeServiceProvider.getEmployeesAsync(); + // var employee = employees.Where(e=> e.EmployeeCode.ToLower() == employecode.ToLower()).SingleOrDefault(); + var user = userAccessDbContext.Users.Where(x => x.IsActive == true && x.EmployeeCode.ToLower() == employecode.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.EmployeeCode), + 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(mapper.Map(user)) }; + return (true, response, "Authentication success and token issued."); + } + else + { + return (false, null, "user inactive or 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 == 1 + && 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/Services/EmployeeServiceProvider.cs b/DamageAssesmentApi/DamageAssesment.Api.UsersAccess/Services/EmployeeServiceProvider.cs new file mode 100644 index 0000000..a0364a0 --- /dev/null +++ b/DamageAssesmentApi/DamageAssesment.Api.UsersAccess/Services/EmployeeServiceProvider.cs @@ -0,0 +1,50 @@ +using DamageAssesment.Api.UsersAccess.Interfaces; +using DamageAssesment.Api.UsersAccess.Models; +using Newtonsoft.Json; + +namespace DamageAssesment.Api.UsersAccess.Services +{ + public class EmployeeServiceProvider : ServiceProviderBase, IEmployeeServiceProvider + { + public EmployeeServiceProvider(IConfiguration configuration, IHttpUtil httpUtil, ILogger logger) : base(configuration, httpUtil, logger, configuration.GetValue("RessourceSettings:Employee"), configuration.GetValue("EndPointSettings:EmployeeUrlBase")) + { + } + + public async Task> getEmployeesAsync() + { + try + { + var responseJsonString = await httpUtil.SendAsync(HttpMethod.Get, url, null); + var employees = JsonConvert.DeserializeObject>(responseJsonString); + + if (employees == null || !employees.Any()) + return new List(); + else return employees; + } + catch (Exception ex) + { + logger?.LogError($"Exception Found : {ex.Message} - Ref: EmployeeServiceProvider.getEmployeesAsync()"); + return new List(); + } + } + + public async Task getEmployeeAsync(int employeeId) + { + try + { + url = urlBase + string.Format(configuration.GetValue("RessourceSettings:EmployeeById"), employeeId); + var responseJsonString = await httpUtil.SendAsync(HttpMethod.Get, url, null); + var employee = JsonConvert.DeserializeObject(responseJsonString); + + 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/Services/HttpUtil.cs b/DamageAssesmentApi/DamageAssesment.Api.UsersAccess/Services/HttpUtil.cs new file mode 100644 index 0000000..a8b5c9f --- /dev/null +++ b/DamageAssesmentApi/DamageAssesment.Api.UsersAccess/Services/HttpUtil.cs @@ -0,0 +1,42 @@ +using DamageAssesment.Api.UsersAccess.Interfaces; +using System.Net.Http.Headers; +using System.Text; + +namespace DamageAssesment.Api.UsersAccess.Services +{ + public class HttpUtil : IHttpUtil + { + private readonly HttpClient httpClient; + private readonly ILogger logger; + + public HttpUtil(HttpClient httpClient, ILogger logger) + { + this.httpClient = httpClient; + this.logger = logger; + } + public async Task SendAsync(HttpMethod method, string url, string JsonInput) + { + try + { + var request = new HttpRequestMessage(method, url); + request.Headers.Accept.Clear(); + request.Headers.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json")); + + //request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", token); + if (method == HttpMethod.Post) + { + request.Content = new StringContent(JsonInput, Encoding.UTF8, "application/json"); + } + var response = await httpClient.SendAsync(request, CancellationToken.None); + response.EnsureSuccessStatusCode(); + var responseString = await response.Content.ReadAsStringAsync(); + return responseString; + } + catch (Exception ex) + { + logger?.LogError($"Exception Message : {ex.Message} - Ref: HttpUtil.SendAsync()"); + return null; + } + } + } +} diff --git a/DamageAssesmentApi/DamageAssesment.Api.UsersAccess/Services/ServiceProviderBase.cs b/DamageAssesmentApi/DamageAssesment.Api.UsersAccess/Services/ServiceProviderBase.cs new file mode 100644 index 0000000..a90b839 --- /dev/null +++ b/DamageAssesmentApi/DamageAssesment.Api.UsersAccess/Services/ServiceProviderBase.cs @@ -0,0 +1,25 @@ +using DamageAssesment.Api.UsersAccess.Interfaces; + +namespace DamageAssesment.Api.UsersAccess.Services +{ + public class ServiceProviderBase + { + protected readonly IConfiguration configuration; + protected readonly IHttpUtil httpUtil; + protected readonly ILogger logger; + protected string ressource; + protected string urlBase; + protected string url; + + + public ServiceProviderBase(IConfiguration configuration, IHttpUtil httpUtil, ILogger logger, string ressource, string urlBase) + { + this.configuration = configuration; + this.httpUtil = httpUtil; + this.logger = logger; + this.ressource = ressource; + this.urlBase = urlBase; + url = urlBase + ressource; + } + } +} diff --git a/DamageAssesmentApi/DamageAssesment.Api.UsersAccess/Services/TokenServiceProvider.cs b/DamageAssesmentApi/DamageAssesment.Api.UsersAccess/Services/TokenServiceProvider.cs new file mode 100644 index 0000000..91645b9 --- /dev/null +++ b/DamageAssesmentApi/DamageAssesment.Api.UsersAccess/Services/TokenServiceProvider.cs @@ -0,0 +1,59 @@ +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; + +namespace DamageAssesment.Api.UsersAccess.Services +{ + 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(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 Db.Token() + { + UserId = user.Id, + RefreshToken = refreshtoken, + IsActive = true + }); + } + await usersAccessDbContext.SaveChangesAsync(); + + return refreshtoken; + } + } + + public async Task TokenAuthenticate(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/appsettings.Development.json b/DamageAssesmentApi/DamageAssesment.Api.UsersAccess/appsettings.Development.json new file mode 100644 index 0000000..0c208ae --- /dev/null +++ b/DamageAssesmentApi/DamageAssesment.Api.UsersAccess/appsettings.Development.json @@ -0,0 +1,8 @@ +{ + "Logging": { + "LogLevel": { + "Default": "Information", + "Microsoft.AspNetCore": "Warning" + } + } +} diff --git a/DamageAssesmentApi/DamageAssesment.Api.UsersAccess/appsettings.json b/DamageAssesmentApi/DamageAssesment.Api.UsersAccess/appsettings.json new file mode 100644 index 0000000..150b8f3 --- /dev/null +++ b/DamageAssesmentApi/DamageAssesment.Api.UsersAccess/appsettings.json @@ -0,0 +1,41 @@ +{ + "JwtSettings": { + "securitykey": "bWlhbWkgZGFkZSBzY2hvb2xzIHNlY3JldCBrZXk=" + }, + "Logging": { + "LogLevel": { + "Default": "Information", + "Microsoft.AspNetCore": "Warning" + } + }, + "EndPointSettings": { + "EmployeeUrlBase": "http://localhost:5135" + }, + "RessourceSettings": { + "Employee": "/Employees", + "EmployeeById": "/Employees/{0}" + }, + "AllowedHosts": "*", + "Dadeschools": { + "Authority": "https://dev-graph.dadeschools.net", + "TokenUrl": "https://dev-graph.dadeschools.net/connect/token", + "ClientId": "dmapi", + "ClientSecret": "bfce2c8d-2064-4a02-b19d-7f1d42b16eae", + "Name": "Dadeschools Identity Server" + }, + "Scopes": [ + { + "Name": "openid", + "Description": "Request an authentication token on your behalf" + }, + { + "Name": "profile", + "Description": "Read basic information about you such as your date of brith and full name" + } + ], + "ConnectionStrings": { + "UsersAccessConnection": "Server=DESKTOP-OF5DPLQ\\SQLEXPRESS;Database=da_survey_dev;Trusted_Connection=True;TrustServerCertificate=True;" + //"UsersAccessConnection": "Server=tcp:da-dev.database.windows.net,1433;Initial Catalog=da-dev-db;Encrypt=True;User ID=admin-dev;Password=b3tgRABw8LGE75k;TrustServerCertificate=False;Connection Timeout=30;" + + } +} diff --git a/DamageAssesmentApi/DamageAssesment.Responses.Test/DamageAssesment.Api.Responses.Test.csproj b/DamageAssesmentApi/DamageAssesment.Responses.Test/DamageAssesment.Api.Responses.Test.csproj new file mode 100644 index 0000000..5190942 --- /dev/null +++ b/DamageAssesmentApi/DamageAssesment.Responses.Test/DamageAssesment.Api.Responses.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.Responses.Test/MockData.cs b/DamageAssesmentApi/DamageAssesment.Responses.Test/MockData.cs new file mode 100644 index 0000000..c7a52de --- /dev/null +++ b/DamageAssesmentApi/DamageAssesment.Responses.Test/MockData.cs @@ -0,0 +1,30 @@ + +using DamageAssesment.Api.Responses.Models; +using System.Collections.Generic; +using System.Text; + +namespace DamageAssesment.Api.Responses.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 = 1, LocationId = 1, SurveyId = 1, Id = 1 }; + } + } +} diff --git a/DamageAssesmentApi/DamageAssesment.Responses.Test/ResponsesServiceTest.cs b/DamageAssesmentApi/DamageAssesment.Responses.Test/ResponsesServiceTest.cs new file mode 100644 index 0000000..e586917 --- /dev/null +++ b/DamageAssesmentApi/DamageAssesment.Responses.Test/ResponsesServiceTest.cs @@ -0,0 +1,251 @@ +using DamageAssesment.Api.Responses.Controllers; +using DamageAssesment.Api.Responses.Interfaces; +using DamageAssesment.Api.Responses.Models; +using DamageAssesment.Api.Responses.Test; +using Microsoft.AspNetCore.Mvc; +using Moq; +using Xunit; + + +namespace DamageAssesment.SurveyResponses.Test +{ + public class ResponsesServiceTest + { + private Mock mockSurveyResponseService; + private string token { get; set; } + public ResponsesServiceTest() + { + mockSurveyResponseService = new Mock(); + token = Guid.NewGuid().ToString(); + } + + [Fact(DisplayName = "Get Responses - 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 ResponsesController(mockSurveyResponseService.Object); + var result = (OkObjectResult)await surveyResponseProvider.GetSurveyResponsesAsync(); + Assert.Equal(200, result.StatusCode); + } + + [Fact(DisplayName = "Get Responses - BadRequest case")] + public async Task GetSurveyResponsesAsync_ShouldReturnStatusCode204() + { + var mockResponse = await MockData.getResponse(); + mockSurveyResponseService.Setup(service => service.GetSurveyResponsesAsync()).ReturnsAsync(mockResponse); + var surveyResponseProvider = new ResponsesController(mockSurveyResponseService.Object); + var result = (BadRequestObjectResult)await surveyResponseProvider.GetSurveyResponsesAsync(); + Assert.Equal(400, result.StatusCode); + } + + [Fact(DisplayName = "Get Responses by surveyId - Ok case")] + public async Task GetSurveyResponsesBySurveyAsync_ShouldReturnStatusCode200() + { + SurveyResponse mockRequestObject = await MockData.getSurveyResponseObject(); + var mockResponse = await MockData.getOkResponse(); +<<<<<<<< HEAD:DamageAssesmentApi/DamageAssesment.Api.Responses.Test/SurveyResponsesServiceTest.cs + mockSurveyResponseService.Setup(service => service.GetSurveyResponsesBySurveyAsync(1,1)).ReturnsAsync(mockResponse); + var surveyResponseProvider = new SurveyResponsesController(mockSurveyResponseService.Object); + var result = (OkObjectResult)await surveyResponseProvider.GetSurveyResponsesAsync(1,1); +======== + mockSurveyResponseService.Setup(service => service.GetSurveyResponsesBySurveyAsync(1)).ReturnsAsync(mockResponse); + var surveyResponseProvider = new ResponsesController(mockSurveyResponseService.Object); + var result = (OkObjectResult)await surveyResponseProvider.GetSurveyResponsesAsync(1); +>>>>>>>> Azure-Integration:DamageAssesmentApi/DamageAssesment.Responses.Test/ResponsesServiceTest.cs + Assert.Equal(200, result.StatusCode); + } + + [Fact(DisplayName = "Get Responses by surveyId - NoContent case")] + public async Task GetSurveyResponsesBySurveyAsync_ShouldReturnStatusCode204() + { + var mockResponse = await MockData.getResponse(); +<<<<<<<< HEAD:DamageAssesmentApi/DamageAssesment.Api.Responses.Test/SurveyResponsesServiceTest.cs + mockSurveyResponseService.Setup(service => service.GetSurveyResponsesBySurveyAsync(1,1)).ReturnsAsync(mockResponse); + var surveyResponseProvider = new SurveyResponsesController(mockSurveyResponseService.Object); + var result = (NoContentResult)await surveyResponseProvider.GetSurveyResponsesAsync(1,1); +======== + mockSurveyResponseService.Setup(service => service.GetSurveyResponsesBySurveyAsync(1)).ReturnsAsync(mockResponse); + var surveyResponseProvider = new ResponsesController(mockSurveyResponseService.Object); + var result = (NoContentResult)await surveyResponseProvider.GetSurveyResponsesAsync(1); +>>>>>>>> Azure-Integration:DamageAssesmentApi/DamageAssesment.Responses.Test/ResponsesServiceTest.cs + Assert.Equal(204, result.StatusCode); + } + + + + + [Fact(DisplayName = "Get Responses 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, 1)).ReturnsAsync(mockResponse); + var surveyResponseProvider = new ResponsesController(mockSurveyResponseService.Object); + var result = (OkObjectResult)await surveyResponseProvider.GetSurveyResponsesBySurveyAndLocationAsync(1, 1); + Assert.Equal(200, result.StatusCode); + } + + [Fact(DisplayName = "Get Responses by surveyId and locationId - NoContent case")] + public async Task GetSurveyResponsesBySurveyLocationAsync_ShouldReturnStatusCode204() + { + var mockResponse = await MockData.getResponse(); + mockSurveyResponseService.Setup(service => service.GetSurveyResponsesBySurveyAndLocationAsync(1, 1)).ReturnsAsync(mockResponse); + var surveyResponseProvider = new ResponsesController(mockSurveyResponseService.Object); + var result = (NoContentResult)await surveyResponseProvider.GetSurveyResponsesBySurveyAndLocationAsync(1, 1); + Assert.Equal(204, result.StatusCode); + } + + [Fact(DisplayName = "Get Responses 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 ResponsesController(mockSurveyResponseService.Object); + var result = (OkObjectResult)await surveyResponseProvider.GetSurveyResponsesByAnswerAsyncAsync(1, 1, "Yes"); + Assert.Equal(200, result.StatusCode); + } + + [Fact(DisplayName = "Get Responses 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 ResponsesController(mockSurveyResponseService.Object); + var result = (NoContentResult)await surveyResponseProvider.GetSurveyResponsesByAnswerAsyncAsync(1, 1, "Yes"); + Assert.Equal(204, result.StatusCode); + } + + + [Fact(DisplayName = "Get Responses 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 ResponsesController(mockSurveyResponseService.Object); + var result = (OkObjectResult)await surveyResponseProvider.GetAnswersByRegionAsync(1); + Assert.Equal(200, result.StatusCode); + } + + [Fact(DisplayName = "Get Responses 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 ResponsesController(mockSurveyResponseService.Object); + var result = (NoContentResult)await surveyResponseProvider.GetAnswersByRegionAsync(1); + Assert.Equal(204, result.StatusCode); + } + + [Fact(DisplayName = "Get Responses 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 ResponsesController(mockSurveyResponseService.Object); + var result = (OkObjectResult)await surveyResponseProvider.GetAnswersByMaintenaceCentersync(1); + Assert.Equal(200, result.StatusCode); + } + + [Fact(DisplayName = "Get Responses 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 ResponsesController(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 ResponsesController(mockSurveyResponseService.Object); + var result = (OkObjectResult)await surveyResponseProvider.GetSurveyResponseByIdAsync(1); + Assert.Equal(200, result.StatusCode); + } + + [Fact(DisplayName = "Get Responses 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 ResponsesController(mockSurveyResponseService.Object); + var result = (NoContentResult)await surveyResponseProvider.GetSurveyResponseByIdAsync(1); + Assert.Equal(204, result.StatusCode); + } + + + [Fact(DisplayName = "Post Responses - 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 ResponsesController(mockSurveyResponseService.Object); + var result = (OkObjectResult)await surveyResponseController.PostSurveysAsync(mockRequestObject); + Assert.Equal(200, result.StatusCode); + } + + [Fact(DisplayName = "Post Responses - 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 ResponsesController(mockSurveyResponseService.Object); + var result = (BadRequestObjectResult)await surveyResponseController.PostSurveysAsync(mockRequestObject); + Assert.Equal(400, result.StatusCode); + } + + [Fact(DisplayName = "Put Responses - 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 ResponsesController(mockSurveyResponseService.Object); + var result = (OkObjectResult)await surveyResponseController.PutSurveyResponseAsync(1, mockRequestObject); + Assert.Equal(200, result.StatusCode); + } + + [Fact(DisplayName = "Put Responses - 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 ResponsesController(mockSurveyResponseService.Object); + var result = (BadRequestObjectResult)await surveyResponseController.PutSurveyResponseAsync(1, mockRequestObject); + Assert.Equal(400, result.StatusCode); + } + + [Fact(DisplayName = "Delete Responses - 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 ResponsesController(mockSurveyResponseService.Object); + var result = (OkObjectResult)await surveyResponseController.DeleteSurveyResponseAsync(1); + Assert.Equal(200, result.StatusCode); + } + + [Fact(DisplayName = "Delete Responses - NotFound case")] + public async Task DeleteSurveyAsync_ShouldReturnStatusCode404() + { + var mockResponse = await MockData.getResponse(); + mockSurveyResponseService.Setup(service => service.DeleteSurveyResponseAsync(1)).ReturnsAsync(mockResponse); ; + var surveyResponseController = new ResponsesController(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 index 23f7731..a6c9a8f 100644 --- a/DamageAssesmentApi/DamageAssesment.sln +++ b/DamageAssesmentApi/DamageAssesment.sln @@ -36,6 +36,10 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DamageAssesment.Api.Employe EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DamageAssesment.Api.DocuLinks.Test", "DamageAssesment.Api.DocuLinks.Test\DamageAssesment.Api.DocuLinks.Test.csproj", "{A7F17ED7-71D2-4FD0-87E5-D83415078FC0}" EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DamageAssesment.Api.UsersAccess", "DamageAssesment.Api.UsersAccess\DamageAssesment.Api.UsersAccess.csproj", "{40240AD6-90D2-4128-BCDF-12C77D1B1B55}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DamageAssesment.Api.UsersAccess.Test", "DamageAssesment.Api.UsersAccess.Test\DamageAssesment.Api.UsersAccess.Test.csproj", "{ADAF9385-262C-4A37-A603-A53B77EA515D}" +EndProject Project("{E53339B2-1760-4266-BCC7-CA923CBCF16C}") = "docker-compose", "docker-compose.dcproj", "{0DD44934-6826-43C8-A438-320A05209967}" EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DamageAssesment.Api.DocuLinks", "DamageAssesment.Api.DocuLinks\DamageAssesment.Api.DocuLinks.csproj", "{B027FBB9-1357-4FD6-85B3-8ADCE11CAE05}" @@ -102,6 +106,14 @@ Global {A7F17ED7-71D2-4FD0-87E5-D83415078FC0}.Debug|Any CPU.Build.0 = Debug|Any CPU {A7F17ED7-71D2-4FD0-87E5-D83415078FC0}.Release|Any CPU.ActiveCfg = Release|Any CPU {A7F17ED7-71D2-4FD0-87E5-D83415078FC0}.Release|Any CPU.Build.0 = Release|Any CPU + {40240AD6-90D2-4128-BCDF-12C77D1B1B55}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {40240AD6-90D2-4128-BCDF-12C77D1B1B55}.Debug|Any CPU.Build.0 = Debug|Any CPU + {40240AD6-90D2-4128-BCDF-12C77D1B1B55}.Release|Any CPU.ActiveCfg = Release|Any CPU + {40240AD6-90D2-4128-BCDF-12C77D1B1B55}.Release|Any CPU.Build.0 = Release|Any CPU + {ADAF9385-262C-4A37-A603-A53B77EA515D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {ADAF9385-262C-4A37-A603-A53B77EA515D}.Debug|Any CPU.Build.0 = Debug|Any CPU + {ADAF9385-262C-4A37-A603-A53B77EA515D}.Release|Any CPU.ActiveCfg = Release|Any CPU + {ADAF9385-262C-4A37-A603-A53B77EA515D}.Release|Any CPU.Build.0 = Release|Any CPU {0DD44934-6826-43C8-A438-320A05209967}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {0DD44934-6826-43C8-A438-320A05209967}.Debug|Any CPU.Build.0 = Debug|Any CPU {0DD44934-6826-43C8-A438-320A05209967}.Release|Any CPU.ActiveCfg = Release|Any CPU