Created
August 2, 2024 20:32
Revisions
-
JaimeStill created this gist
Aug 2, 2024 .There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -0,0 +1,147 @@ using System.Text.RegularExpressions; using Core.Data; using Core.Models; using Core.Services.Settings; using Microsoft.AspNetCore.Http; using Microsoft.EntityFrameworkCore; using Platform.Messages; namespace Core.Services; public class UploadService(CoreContext db, UploadPathSettings paths) { readonly CoreContext db = db; readonly UploadPathSettings paths = paths; readonly string urlPattern = "[^a-zA-Z0-9-.]"; public async Task<PersonImage?> GetPersonImage(int personId) => await db.PersonImages .FirstOrDefaultAsync(x => x.PersonId == personId ); public async Task<ApiMessage<PersonImage>> UploadPersonImage(IFormFile file, int personId) { ValidationMessage validation = Validate(file, "image"); if (validation.IsValid) { await RemovePersonImage(personId); PersonImage image = await AddPersonImage(file, personId); return new(image, $"Person image {image.Name} successfully uploaded"); } else return new(validation); } public async Task<ApiMessage<PersonImage>> RemovePersonImage(int personId) { PersonImage? image = await GetPersonImage(personId); if (image is not null) { db.PersonImages.Remove(image); await db.SaveChangesAsync(); Delete(image); return new(image, $"Person image {image.Name} successfully removed"); } else return new("RemoveUserImage", new Exception("Person image not found")); } async Task<PersonImage> AddPersonImage(IFormFile file, int personId) { PersonImage image = await Write<PersonImage>(file, new()); image.PersonId = personId; await db.PersonImages.AddAsync(image); await db.SaveChangesAsync(); return image; } #region Internal string CreateSafeName(IFormFile file, string path) { int increment = 0; string fileName = UrlEncode(file.FileName); string newName = fileName; while (File.Exists(Path.Combine(path, newName))) { string extension = fileName.Split('.').Last(); newName = $"{fileName.Replace($".{extension}", "")}_{++increment}.{extension}"; } return newName; } static void Delete<T>(T upload) where T : Upload { if (File.Exists(upload.Path)) File.Delete(upload.Path); } static string GetUploadPath<T>(T upload) where T : Upload => upload switch { PersonImage _ => "person-images", _ => "uploads" }; void SetUpload<T>(IFormFile file, T upload, string path, string url) where T : Upload { if (!Directory.Exists(path)) Directory.CreateDirectory(path); string name = CreateSafeName(file, path); upload.File = name; upload.Name = file.Name; upload.Path = $"{path}{name}"; upload.Url = $"{url}{name}"; upload.FileType = file.ContentType; upload.Size = file.Length; } string UrlEncode(string url) => UrlEncode(url, urlPattern, "-"); static string UrlEncode(string url, string pattern, string replace = "") { string friendlyUrl = Regex.Replace(url, @"\s", string.Empty).ToLower(); friendlyUrl = Regex.Replace(friendlyUrl, pattern, replace); return friendlyUrl; } static ValidationMessage Validate(IFormFile file, string? filetype = null) { ValidationMessage message = new(); if (!(file.Length > 0)) message.AddMessage("File is empty"); if (!string.IsNullOrWhiteSpace(filetype)) { var invalid = !file.ContentType.Split('/')[0].Equals(filetype, StringComparison.CurrentCultureIgnoreCase); if (invalid) message.AddMessage($"File is not of type {filetype}"); } return message; } async Task<T> Write<T>(IFormFile file, T upload) where T : Upload { string uploadPath = GetUploadPath(upload); string path = Path.Combine(paths.Directory, uploadPath); string url = Path.Combine(paths.Url, uploadPath); SetUpload(file, upload, path, url); using FileStream stream = new(upload.Path, FileMode.Create); await file.CopyToAsync(stream); return upload; } #endregion }