using System; using System.Collections.Generic; using System.IO; using System.Text.Json; using System.Threading; using System.Threading.Tasks; using GB5Shared.Attachment; using GB5Shared.DTO.ECM; using GB5Shared.DTO.Framework.Login; using GB5Shared.DTO.Framework.ResponseStandard; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc; using static GB5Shared.GB5Constant.Constant; namespace FrameworkSL.Controllers.Attachment { /// /// Template-based attachment upload/delete. /// Uses IAttachmentUploadService (TemplateResolutionEngine) rather than the /// legacy Alfresco-backed IFileUploadBLL. /// Route prefix: /Attachment/Template /// [ApiController] [Route("Attachment/Template")] public class TemplateAttachmentController : ControllerBase { private readonly IAttachmentUploadService _uploadService; public TemplateAttachmentController(IAttachmentUploadService uploadService) => _uploadService = uploadService; // ── Upload ──────────────────────────────────────────────────── /// /// Multipart/form-data upload using the template engine for path resolution. /// POST /Attachment/Template/Upload /// Form fields: DocumentSetDetailId, ObjectTypeId, ObjectId, BizTransactionTypeId, /// RowGuid, AttachmentType, Remarks, Tags, ContextDictionaryJson /// [HttpPost("Upload")] [DisableRequestSizeLimit] public async Task> Upload( IFormFile File, [FromForm] int DocumentSetDetailId, [FromForm] int ObjectTypeId, [FromForm] int ObjectId, [FromForm] int BizTransactionTypeId, [FromForm] Guid RowGuid, [FromForm] byte AttachmentType, [FromForm] string? Remarks, [FromForm] string? Tags, [FromForm] string? ContextDictionaryJson, [FromHeader(Name = "Login")] string LoginDTOJson, CancellationToken ct) { var login = Newtonsoft.Json.JsonConvert.DeserializeObject(LoginDTOJson)!; try { var contextDict = string.IsNullOrWhiteSpace(ContextDictionaryJson) ? new Dictionary() : JsonSerializer.Deserialize>(ContextDictionaryJson) ?? new Dictionary(); var request = new AttachmentUploadRequest { DocumentSetDetailId = DocumentSetDetailId, ObjectTypeId = ObjectTypeId, ObjectId = ObjectId, BizTransactionTypeId = BizTransactionTypeId, RowGuid = RowGuid, AttachmentType = AttachmentType, Remarks = Remarks, Tags = Tags ?? string.Empty, ContextDictionary = contextDict }; await using var stream = File.OpenReadStream(); var result = await _uploadService.UploadAsync( request, stream, File.FileName, File.ContentType, login, ct) .ConfigureAwait(false); return await GB5Shared.ResponseStandard.Response.CreateSuccessResponse( result, CacheKeyLevel.NOT_REQUIRED, login); } catch (Exception ex) { return await GB5Shared.ResponseStandard.Response.CreateExceptionError( ex, CacheKeyLevel.NOT_REQUIRED, login, ex.Message, 500); } } // ── Upload (Base64 / JSON body) ───────────────────────────────── /// /// JSON-body upload — same as Upload above, but the file travels as Base64 /// inside the request body instead of multipart/form-data. /// POST /Attachment/Template/UploadBase64 /// [HttpPost("UploadBase64")] public async Task> UploadBase64( [FromBody] AttachmentUploadBase64Request body, [FromHeader(Name = "Login")] string LoginDTOJson, CancellationToken ct) { var login = Newtonsoft.Json.JsonConvert.DeserializeObject(LoginDTOJson)!; try { var request = new AttachmentUploadRequest { DocumentSetDetailId = body.DocumentSetDetailId, ObjectTypeId = body.ObjectTypeId, ObjectId = body.ObjectId, BizTransactionTypeId = body.BizTransactionTypeId, RowGuid = body.RowGuid, AttachmentType = body.AttachmentType, Remarks = body.Remarks, Tags = body.Tags ?? string.Empty, ContextDictionary = body.ContextDictionary ?? new Dictionary() }; var fileBytes = Convert.FromBase64String(body.Base64Content); var contentType = string.IsNullOrWhiteSpace(body.ContentType) ? "application/octet-stream" : body.ContentType; using var stream = new MemoryStream(fileBytes); var result = await _uploadService.UploadAsync( request, stream, body.FileName, contentType, login, ct) .ConfigureAwait(false); return await GB5Shared.ResponseStandard.Response.CreateSuccessResponse( result, CacheKeyLevel.NOT_REQUIRED, login); } catch (Exception ex) { return await GB5Shared.ResponseStandard.Response.CreateExceptionError( ex, CacheKeyLevel.NOT_REQUIRED, login, ex.Message, 500); } } // ── Update (confirm deferred path) ────────────────────────────── /// /// Confirms a Phase-1 deferred attachment once the caller knows the real ObjectId /// and/or the field values its LOCATIONTEMPLATE/DOCUMENTNAMETEMPLATE tokens needed /// (e.g. {EMP}, {Year}, {Month} in "/employee/history/{EMP}"). Re-resolves the /// template, moves the file in storage to its final path, and updates TATTACHMENT. /// Idempotent — retrying with the same inputs is a safe no-op. /// POST /Attachment/Template/UpdateUploadBase64 /// [HttpPost("UpdateUploadBase64")] public async Task> UpdateUploadBase64( [FromBody] AttachmentResolvePathRequest body, [FromHeader(Name = "Login")] string LoginDTOJson, CancellationToken ct) { var login = Newtonsoft.Json.JsonConvert.DeserializeObject(LoginDTOJson)!; try { var result = await _uploadService.ResolveDeferredPathAsync(body, login, ct) .ConfigureAwait(false); return await GB5Shared.ResponseStandard.Response.CreateSuccessResponse( result, CacheKeyLevel.NOT_REQUIRED, login); } catch (Exception ex) { return await GB5Shared.ResponseStandard.Response.CreateExceptionError( ex, CacheKeyLevel.NOT_REQUIRED, login, ex.Message, 500); } } // ── Delete ──────────────────────────────────────────────────── /// /// Deletes a TATTACHMENT row and removes the physical file from storage. /// DELETE /Attachment/Template/Delete/{attachmentId} /// [HttpDelete("Delete/{AttachmentId:int}")] public async Task> Delete( int AttachmentId, [FromHeader(Name = "Login")] string LoginDTOJson, CancellationToken ct) { var login = Newtonsoft.Json.JsonConvert.DeserializeObject(LoginDTOJson)!; try { await _uploadService.DeleteAsync(AttachmentId, login, ct).ConfigureAwait(false); return await GB5Shared.ResponseStandard.Response.CreateSuccessResponse( "Attachment deleted.", CacheKeyLevel.NOT_REQUIRED, login); } catch (Exception ex) { return await GB5Shared.ResponseStandard.Response.CreateExceptionError( ex, CacheKeyLevel.NOT_REQUIRED, login, ex.Message, 500); } } } }