diff --git a/BMA.EHR.API.Command/BMA.EHR.API.Command.csproj b/BMA.EHR.API.Command/BMA.EHR.API.Command.csproj index 218c5f05..4510e069 100644 --- a/BMA.EHR.API.Command/BMA.EHR.API.Command.csproj +++ b/BMA.EHR.API.Command/BMA.EHR.API.Command.csproj @@ -7,9 +7,15 @@ + + + + + + diff --git a/BMA.EHR.API.Command/FileDownloadResponse.cs b/BMA.EHR.API.Command/FileDownloadResponse.cs new file mode 100644 index 00000000..653309fb --- /dev/null +++ b/BMA.EHR.API.Command/FileDownloadResponse.cs @@ -0,0 +1,11 @@ +namespace BMA.EHR.API.Command +{ + public class FileDownloadResponse + { + public string FileName { get; set; } = string.Empty; + + public string FileType { get; set; } = string.Empty; + + public byte[] FileContent { get; set; } + } +} diff --git a/BMA.EHR.API.Command/MinIOService.cs b/BMA.EHR.API.Command/MinIOService.cs deleted file mode 100644 index 34e8b61a..00000000 --- a/BMA.EHR.API.Command/MinIOService.cs +++ /dev/null @@ -1,208 +0,0 @@ -using BMA.EHR.Infrastructure.Persistence; -using Microsoft.EntityFrameworkCore; -using System.Net.Http.Headers; - -namespace BMA.EHR.API.Command -{ - public class MinIOService - { - // #region " Fields " - - // private readonly ApplicationDBContext _context; - // private readonly IConfiguration _configuration; - // private readonly IWebHostEnvironment _webHostEnvironment; - // private readonly AmazonS3Client _s3Client; - // private string _bucketName = string.Empty; - - // #endregion - - // #region " Constructors " - - // public MinIOService(ApplicationDBContext context, - // IConfiguration configuration, - // IWebHostEnvironment webHostEnvironment) - // { - // _context = context; - // _configuration = configuration; - // _webHostEnvironment = webHostEnvironment; - - // var config = new AmazonS3Config - // { - // ServiceURL = _configuration["MinIO:Endpoint"], - // ForcePathStyle = true - // }; - - // _s3Client = new AmazonS3Client(_configuration["MinIO:AccessKey"], _configuration["MinIO:SecretKey"], config); - // this._bucketName = _configuration["MinIO:BucketName"] ?? "bma-recruit"; - // } - - // #endregion - - // #region " Methods " - - // public async Task UploadFileAsync(IFormFile file, string newFileName = "") - // { - // var fileName = ""; - // var fileExt = Path.GetExtension(file.FileName); - // if (newFileName != "") - // fileName = $"{newFileName}"; - // else - // fileName = ContentDispositionHeaderValue.Parse(file.ContentDisposition).FileName.Trim('"'); - - - // var tmpDir = Path.Combine(_webHostEnvironment.ContentRootPath, "tmp"); - // if (!Directory.Exists(tmpDir)) - // Directory.CreateDirectory(tmpDir); - - // var tmpFile = Path.Combine(tmpDir, $"tmp_{DateTime.Now.ToString("ddMMyyyyHHmmss")}{fileExt}"); - - // try - // { - // using (var ms = new MemoryStream()) - // { - // var id = Guid.NewGuid(); - // file.CopyTo(ms); - // var fileBytes = ms.ToArray(); - // System.IO.MemoryStream filestream = new System.IO.MemoryStream(fileBytes); - - // var request = new PutObjectRequest - // { - // BucketName = _bucketName, - // Key = id.ToString("D"), - // InputStream = filestream, - // ContentType = file.ContentType, - // CannedACL = S3CannedACL.PublicRead - // }; - - // await _s3Client.PutObjectAsync(request); - - // // create document object - // var doc = new Document() - // { - // FileName = fileName, - // FileType = file.ContentType, - // FileSize = Convert.ToInt32(file.Length), - // ObjectRefId = id, - // CreatedDate = DateTime.Now - // }; - - // await _context.Documents.AddAsync(doc); - // await _context.SaveChangesAsync(); - - // return doc; - // } - // } - // catch - // { - // throw; - // } - // finally - // { - // File.Delete(tmpFile); - // } - // } - - // public async Task DownloadFileAsync(Guid fileId) - // { - // try - // { - // var doc = await _context.Documents.AsQueryable() - // .FirstOrDefaultAsync(x => x.Id == fileId); - - // if (doc == null) - // throw new Exception(GlobalMessages.FileNotFoundOnServer); - - // using (var memoryStream = new MemoryStream()) - // { - // GetObjectRequest request = new GetObjectRequest - // { - // BucketName = _bucketName, - // Key = doc.ObjectRefId.ToString("D") - // }; - - // using (GetObjectResponse response = await _s3Client.GetObjectAsync(request)) - // { - // using (Stream responseStream = response.ResponseStream) - // { - // responseStream.CopyTo(memoryStream); - // } - // } - - // var fileContent = memoryStream.ToArray(); - - // return new FileDownloadResponse - // { - // FileName = doc.FileName, - // FileType = doc.FileType, - // FileContent = fileContent - // }; - // }; - // } - // catch - // { - // throw; - // } - // } - - // public async Task DeleteFileAsync(Guid fileId) - // { - // try - // { - // var doc = await _context.Documents.AsQueryable() - // .FirstOrDefaultAsync(x => x.Id == fileId); - - // if (doc == null) - // throw new Exception(GlobalMessages.FileNotFoundOnServer); - // else - // { - // DeleteObjectRequest request = new DeleteObjectRequest - // { - // BucketName = _bucketName, - // Key = doc?.ObjectRefId.ToString("D") - // }; - - // // delete from minio - // await _s3Client.DeleteObjectAsync(request); - - - // _context.Documents.Remove(doc); - // await _context.SaveChangesAsync(); - // } - // } - // catch - // { - // throw; - // } - // } - - // public async Task ImagesPath(Guid fileId) - // { - // if (fileId == null) - // return ""; - - // var doc = await _context.Documents.AsQueryable() - // .FirstOrDefaultAsync(x => x.Id == fileId); - - // if (doc == null) - // throw new Exception(GlobalMessages.FileNotFoundOnServer); - // var config = new AmazonS3Config - // { - // ServiceURL = _configuration.GetValue("MinIO:Endpoint"), - // ForcePathStyle = true - // }; - - // DateTime expires = DateTime.UtcNow.AddHours(6); - // GetPreSignedUrlRequest request = new GetPreSignedUrlRequest - // { - // BucketName = _bucketName, - // Key = doc?.ObjectRefId.ToString("D"), - // Expires = expires, - // }; - // string path = _s3Client.GetPreSignedURL(request); - - // return path; - // } - - // #endregion - } -} \ No newline at end of file diff --git a/BMA.EHR.Application/BMA.EHR.Application.csproj b/BMA.EHR.Application/BMA.EHR.Application.csproj index b40d14e1..5bf43f93 100644 --- a/BMA.EHR.Application/BMA.EHR.Application.csproj +++ b/BMA.EHR.Application/BMA.EHR.Application.csproj @@ -7,6 +7,7 @@ + diff --git a/BMA.EHR.Application/Repositories/FileDownloadResponse.cs b/BMA.EHR.Application/Repositories/FileDownloadResponse.cs new file mode 100644 index 00000000..8f863717 --- /dev/null +++ b/BMA.EHR.Application/Repositories/FileDownloadResponse.cs @@ -0,0 +1,11 @@ +namespace BMA.EHR.Application.Repositories +{ + public class FileDownloadResponse + { + public string FileName { get; set; } = string.Empty; + + public string FileType { get; set; } = string.Empty; + + public byte[] FileContent { get; set; } + } +} diff --git a/BMA.EHR.Domain/Shared/GlobalMessages.cs b/BMA.EHR.Domain/Shared/GlobalMessages.cs index 0afc8707..b573aef4 100644 --- a/BMA.EHR.Domain/Shared/GlobalMessages.cs +++ b/BMA.EHR.Domain/Shared/GlobalMessages.cs @@ -14,6 +14,8 @@ public static readonly string ExceptionOccured = "เกิดข้อผิดพลาดขึ้นในระบบ กรุณาติดต่อผู้ดูแลระบบ!"; + public const string FileNotFoundOnServer = "ไม่พบไฟล์ในระบบ!!"; + #region " Meta Data " public static readonly string DataExist5 = "เนื่องจากมีการกำหนดวันหยุดในการทำงาน 5 วันอยู่"; diff --git a/BMA.EHR.Infrastructure/BMA.EHR.Infrastructure.csproj b/BMA.EHR.Infrastructure/BMA.EHR.Infrastructure.csproj index 3ad1be21..0f8a6718 100644 --- a/BMA.EHR.Infrastructure/BMA.EHR.Infrastructure.csproj +++ b/BMA.EHR.Infrastructure/BMA.EHR.Infrastructure.csproj @@ -7,6 +7,7 @@ + all runtime; build; native; contentfiles; analyzers; buildtransitive diff --git a/BMA.EHR.Infrastructure/InfrastructureServiceRegistration.cs b/BMA.EHR.Infrastructure/InfrastructureServiceRegistration.cs index cae8b382..77ebf1b6 100644 --- a/BMA.EHR.Infrastructure/InfrastructureServiceRegistration.cs +++ b/BMA.EHR.Infrastructure/InfrastructureServiceRegistration.cs @@ -1,4 +1,5 @@ using BMA.EHR.Application.Common.Interfaces; +using BMA.EHR.Application.Repositories; using BMA.EHR.Infrastructure.Persistence; using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.Configuration; @@ -10,8 +11,10 @@ namespace BMA.EHR.Infrastructure { public static IServiceCollection AddPersistence(this IServiceCollection services, IConfiguration configuration) - { - var connectionString = configuration.GetConnectionString("DefaultConnection"); + { + services.AddTransient(); + + var connectionString = configuration.GetConnectionString("DefaultConnection"); services.AddDbContext(options => options.UseMySql(connectionString, ServerVersion.AutoDetect(connectionString), diff --git a/BMA.EHR.Infrastructure/Storage/MinIOService.cs b/BMA.EHR.Infrastructure/Storage/MinIOService.cs new file mode 100644 index 00000000..ad527b61 --- /dev/null +++ b/BMA.EHR.Infrastructure/Storage/MinIOService.cs @@ -0,0 +1,214 @@ +using Amazon.S3; +using Amazon.S3.Model; +using BMA.EHR.Domain.Models.Documents; +using BMA.EHR.Domain.Shared; +using BMA.EHR.Infrastructure.Persistence; +using Microsoft.AspNetCore.Http; +using Microsoft.EntityFrameworkCore; +using Microsoft.Extensions.Configuration; +using System.Net.Http.Headers; +using Microsoft.AspNetCore.Hosting; + +namespace BMA.EHR.Application.Repositories +{ + public class MinIOService + { + #region " Fields " + + private readonly ApplicationDBContext _context; + private readonly IConfiguration _configuration; + private readonly AmazonS3Client _s3Client; + private string _bucketName = string.Empty; + + #endregion + + #region " Constructors " + + public MinIOService(ApplicationDBContext context, + IConfiguration configuration) + { + _context = context; + _configuration = configuration; + + var config = new AmazonS3Config + { + ServiceURL = _configuration["MinIO:Endpoint"], + ForcePathStyle = true + }; + + _s3Client = new AmazonS3Client(_configuration["MinIO:AccessKey"], _configuration["MinIO:SecretKey"], config); + this._bucketName = _configuration["MinIO:BucketName"] ?? "bma-recruit"; + } + + #endregion + + #region " Methods " + + public async Task UploadFileAsync(IFormFile file, string newFileName = "") + { + var fileName = ""; + var fileExt = Path.GetExtension(file.FileName); + if (newFileName != "") + fileName = $"{newFileName}"; + else + fileName = ContentDispositionHeaderValue.Parse(file.ContentDisposition).FileName.Trim('"'); + + + var tmpDir = Path.Combine("tmp"); + if (!Directory.Exists(tmpDir)) + Directory.CreateDirectory(tmpDir); + + var tmpFile = Path.Combine(tmpDir, $"tmp_{DateTime.Now.ToString("ddMMyyyyHHmmss")}{fileExt}"); + + try + { + using (var ms = new MemoryStream()) + { + var id = Guid.NewGuid(); + file.CopyTo(ms); + var fileBytes = ms.ToArray(); + System.IO.MemoryStream filestream = new System.IO.MemoryStream(fileBytes); + + var request = new PutObjectRequest + { + BucketName = _bucketName, + Key = id.ToString("D"), + InputStream = filestream, + ContentType = file.ContentType, + CannedACL = S3CannedACL.PublicRead + }; + + await _s3Client.PutObjectAsync(request); + + // create document object + var doc = new Document() + { + FileName = fileName, + FileType = file.ContentType, + FileSize = Convert.ToInt32(file.Length), + ObjectRefId = id, + CreatedDate = DateTime.Now + }; + + await _context.Documents.AddAsync(doc); + await _context.SaveChangesAsync(); + + return doc; + } + } + catch + { + throw; + } + finally + { + File.Delete(tmpFile); + } + } + + public async Task DownloadFileAsync(Guid fileId) + { + try + { + var doc = await _context.Documents.AsQueryable() + .FirstOrDefaultAsync(x => x.Id == fileId); + + if (doc == null) + throw new Exception(GlobalMessages.FileNotFoundOnServer); + + using (var memoryStream = new MemoryStream()) + { + GetObjectRequest request = new GetObjectRequest + { + BucketName = _bucketName, + Key = doc.ObjectRefId.ToString("D") + }; + + using (GetObjectResponse response = await _s3Client.GetObjectAsync(request)) + { + using (Stream responseStream = response.ResponseStream) + { + responseStream.CopyTo(memoryStream); + } + } + + var fileContent = memoryStream.ToArray(); + + return new FileDownloadResponse + { + FileName = doc.FileName, + FileType = doc.FileType, + FileContent = fileContent + }; + }; + } + catch + { + throw; + } + } + + public async Task DeleteFileAsync(Guid fileId) + { + try + { + var doc = await _context.Documents.AsQueryable() + .FirstOrDefaultAsync(x => x.Id == fileId); + + if (doc == null) + throw new Exception(GlobalMessages.FileNotFoundOnServer); + else + { + DeleteObjectRequest request = new DeleteObjectRequest + { + BucketName = _bucketName, + Key = doc?.ObjectRefId.ToString("D") + }; + + // delete from minio + await _s3Client.DeleteObjectAsync(request); + + + _context.Documents.Remove(doc); + await _context.SaveChangesAsync(); + } + } + catch + { + throw; + } + } + + public async Task ImagesPath(Guid? fileId) + { + if (fileId == null) + return ""; + + var doc = await _context.Documents.AsQueryable() + .FirstOrDefaultAsync(x => x.Id == fileId); + + if (doc == null) + throw new Exception(GlobalMessages.FileNotFoundOnServer); + var config = new AmazonS3Config + { + ServiceURL = _configuration["MinIO:Endpoint"], + ForcePathStyle = true + }; + + DateTime expires = DateTime.UtcNow.AddHours(6); + var _protocol = _configuration["Protocol"]; + GetPreSignedUrlRequest request = new GetPreSignedUrlRequest + { + BucketName = _bucketName, + Key = doc?.ObjectRefId.ToString("D"), + Expires = expires, + Protocol = _protocol =="HTTPS"?Protocol.HTTPS: Protocol.HTTP + }; + string path = _s3Client.GetPreSignedURL(request); + + return path; + } + + #endregion + } +} \ No newline at end of file diff --git a/BMA.EHR.MetaData.Service/appsettings.json b/BMA.EHR.MetaData.Service/appsettings.json index b2be50ae..878609ae 100644 --- a/BMA.EHR.MetaData.Service/appsettings.json +++ b/BMA.EHR.MetaData.Service/appsettings.json @@ -1,28 +1,29 @@ { - "Serilog": { - "MinimumLevel": { - "Default": "Information", - "Override": { - "Microsoft": "Information", - "System": "Warning" - } - } - }, - "ElasticConfiguration": { - "Uri": "http://localhost:9200" - }, - "AllowedHosts": "*", - "ConnectionStrings": { - //"DefaultConnection": "User Id=sys;Password=P@ssw0rd;DBA Privilege=SYSDBA;Data Source=localhost:1521/ORCLCDB", - "DefaultConnection": "server=192.168.1.9;user=root;password=adminVM123;port=3306;database=bma_ehr_demo;Convert Zero Datetime=True;Allow User Variables=true;Pooling=True;" - }, - "Jwt": { - "Key": "HP-FnQMUj9msHMSD3T9HtdEnphAKoCJLEl85CIqROFI", - "Issuer": "https://identity.frappet.com/realms/bma-ehr" - }, - "EPPlus": { - "ExcelPackage": { - "LicenseContext": "NonCommercial" - } + "Serilog": { + "MinimumLevel": { + "Default": "Information", + "Override": { + "Microsoft": "Information", + "System": "Warning" + } } + }, + "ElasticConfiguration": { + "Uri": "http://localhost:9200" + }, + "AllowedHosts": "*", + "ConnectionStrings": { + //"DefaultConnection": "User Id=sys;Password=P@ssw0rd;DBA Privilege=SYSDBA;Data Source=localhost:1521/ORCLCDB", + "DefaultConnection": "server=192.168.1.9;user=root;password=adminVM123;port=3306;database=bma_ehr_demo;Convert Zero Datetime=True;Allow User Variables=true;Pooling=True;" + }, + "Jwt": { + "Key": "HP-FnQMUj9msHMSD3T9HtdEnphAKoCJLEl85CIqROFI", + "Issuer": "https://identity.frappet.com/realms/bma-ehr" + }, + "EPPlus": { + "ExcelPackage": { + "LicenseContext": "NonCommercial" + } + }, + "Protocol": "HTTPS" } diff --git a/BMA.EHR.Placement.Service/BMA.EHR.Placement.Service.csproj b/BMA.EHR.Placement.Service/BMA.EHR.Placement.Service.csproj index 64bcfa67..28056f7e 100644 --- a/BMA.EHR.Placement.Service/BMA.EHR.Placement.Service.csproj +++ b/BMA.EHR.Placement.Service/BMA.EHR.Placement.Service.csproj @@ -36,6 +36,7 @@ + diff --git a/BMA.EHR.Placement.Service/Controllers/PlacementController.cs b/BMA.EHR.Placement.Service/Controllers/PlacementController.cs index 74a583c7..a875b9ad 100644 --- a/BMA.EHR.Placement.Service/Controllers/PlacementController.cs +++ b/BMA.EHR.Placement.Service/Controllers/PlacementController.cs @@ -1,17 +1,10 @@ -using BMA.EHR.Application.Common.Interfaces; -using BMA.EHR.Application.Repositories; +using BMA.EHR.Application.Repositories; using BMA.EHR.Domain.Common; -using BMA.EHR.Domain.Models.HR; -using BMA.EHR.Domain.Models.MetaData; -using BMA.EHR.Domain.Models.Placement; using BMA.EHR.Domain.Shared; using BMA.EHR.Infrastructure.Persistence; using BMA.EHR.Placement.Service.Requests; -using Microsoft.AspNetCore.Authorization; -using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc; using Microsoft.EntityFrameworkCore; -using Sentry; using Swashbuckle.AspNetCore.Annotations; using System.Security.Claims; @@ -20,20 +13,23 @@ namespace BMA.EHR.Placement.Service.Controllers [Route("api/[controller]/placement")] [ApiController] [Produces("application/json")] - [Authorize] + //[Authorize] [SwaggerTag("ระบบบรรจุ")] public class PlacementController : BaseController { private readonly PlacementRepository _repository; private readonly ApplicationDBContext _context; + private readonly MinIOService _documentService; private readonly IHttpContextAccessor _httpContextAccessor; public PlacementController(PlacementRepository repository, ApplicationDBContext context, + MinIOService documentService, IHttpContextAccessor httpContextAccessor) { _repository = repository; _context = context; + _documentService = documentService; _httpContextAccessor = httpContextAccessor; } @@ -206,17 +202,24 @@ namespace BMA.EHR.Placement.Service.Controllers return Success(placement); } - [HttpPost("pass/deferment")] - public async Task> UpdatePersonDeferment([FromBody] PersonDefermentRequest req) + [HttpPost("pass/deferment"), DisableRequestSizeLimit] + public async Task> UpdatePersonDeferment() { - var person = await _context.PlacementProfiles.FindAsync(req.PersonalId); + var person = await _context.PlacementProfiles.FindAsync(Request.Form.ContainsKey("personalId") ? Guid.Parse(Request.Form["personalId"]) : Guid.Parse("00000000-0000-0000-0000-000000000000")); if (person == null) return Error(GlobalMessages.DataNotFound, 404); person.IsRelief = true; - person.ReliefReason = req.Note; + person.ReliefReason = Request.Form.ContainsKey("note") ? Request.Form["note"] : ""; person.PlacementStatus = "UN-CONTAIN"; - //person.ReliefDoc = req.UploadFile;xxxxxxxxxxxxxx + if (Request.Form.Files != null && Request.Form.Files.Count != 0) + { + var file = Request.Form.Files[0]; + var fileExtension = Path.GetExtension(file.FileName); + + var doc = await _documentService.UploadFileAsync(file, file.FileName); + person.ReliefDoc = doc; + } person.LastUpdateFullName = FullName ?? "System Administrator"; person.LastUpdateUserId = UserId ?? ""; person.LastUpdatedAt = DateTime.Now; @@ -245,14 +248,13 @@ namespace BMA.EHR.Placement.Service.Controllers [HttpGet("pass/deferment/{personalId:length(36)}")] public async Task> GetPersonDeferment(Guid personalId) { - var person = await _context.PlacementProfiles.FindAsync(personalId); + var person = await _context.PlacementProfiles.Include(x => x.ReliefDoc).FirstOrDefaultAsync(x => x.Id == personalId); if (person == null) return Error(GlobalMessages.DataNotFound, 404); var data = new { ReliefReason = person.ReliefReason, - ReliefDoc = person.ReliefReason, - //ReliefDoc = person.ReliefDoc == null ? null : await _documentService.ImagesPath(person.ReliefDoc.Id),xxxxxxxxxxxxxx + ReliefDoc = person.ReliefDoc == null ? null : await _documentService.ImagesPath(person.ReliefDoc.Id), }; return Success(data); @@ -272,7 +274,7 @@ namespace BMA.EHR.Placement.Service.Controllers return Success(data); } - [HttpPost("pass/stat/{personalId:length(36)}")] + [HttpPost("pass")] public async Task> UpdatePositionByPerson(Guid personalId) { var person = await _context.PlacementProfiles.FindAsync(personalId); @@ -281,5 +283,6 @@ namespace BMA.EHR.Placement.Service.Controllers return Success(); } + } } diff --git a/BMA.EHR.Placement.Service/appsettings.json b/BMA.EHR.Placement.Service/appsettings.json index 0ac38caa..6d3526dc 100644 --- a/BMA.EHR.Placement.Service/appsettings.json +++ b/BMA.EHR.Placement.Service/appsettings.json @@ -30,5 +30,6 @@ "AccessKey": "frappet", "SecretKey": "P@ssw0rd", "BucketName": "bma-recruit" - } + }, + "Protocol": "HTTPS" }