Created
August 2, 2024 20:32
-
-
Save JaimeStill/d5f18dcf2053c10ec46981f8881c14c4 to your computer and use it in GitHub Desktop.
Fleshed out UploadService
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 characters
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 | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment