Skip to content

Instantly share code, notes, and snippets.

@JaimeStill
Created August 2, 2024 20:32
Show Gist options
  • Save JaimeStill/d5f18dcf2053c10ec46981f8881c14c4 to your computer and use it in GitHub Desktop.
Save JaimeStill/d5f18dcf2053c10ec46981f8881c14c4 to your computer and use it in GitHub Desktop.
Fleshed out UploadService
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