Fix gestione allegati e creato metodo di esportazione log
This commit is contained in:
@@ -1,15 +1,13 @@
|
||||
using SteUp.Shared.Core.Dto;
|
||||
using SteUp.Shared.Core.Entities;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using SteUp.Maui.Core.Utility;
|
||||
using SteUp.Shared.Core.Dto;
|
||||
using SteUp.Shared.Core.Helpers;
|
||||
using SteUp.Shared.Core.Interface.System;
|
||||
|
||||
namespace SteUp.Maui.Core.Services;
|
||||
|
||||
public class AttachedService : IAttachedService
|
||||
public class AttachedService(ILogger<FileManager> logger) : IAttachedService
|
||||
{
|
||||
private static string AttachedRoot =>
|
||||
Path.Combine(FileSystem.CacheDirectory, "attached");
|
||||
|
||||
public async Task<AttachedDto?> SelectImageFromCamera()
|
||||
{
|
||||
var cameraPerm = await Permissions.RequestAsync<Permissions.Camera>();
|
||||
@@ -27,12 +25,13 @@ public class AttachedService : IAttachedService
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
logger.LogError(ex, ex.Message);
|
||||
Console.WriteLine($"Errore cattura foto: {ex.Message}");
|
||||
SentrySdk.CaptureException(ex);
|
||||
return null;
|
||||
}
|
||||
|
||||
return result is null ? null : await ConvertToDto(result, AttachedDto.TypeAttached.Image);
|
||||
return result is null ? null : await UtilityFile.ConvertToDto(result, AttachedDto.TypeAttached.Image);
|
||||
}
|
||||
|
||||
public async Task<List<AttachedDto>?> SelectImageFromGallery()
|
||||
@@ -48,6 +47,7 @@ public class AttachedService : IAttachedService
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
logger.LogError(ex, ex.Message);
|
||||
Console.WriteLine($"Errore selezione galleria: {ex.Message}");
|
||||
SentrySdk.CaptureException(ex);
|
||||
return null;
|
||||
@@ -58,308 +58,9 @@ public class AttachedService : IAttachedService
|
||||
List<AttachedDto> returnList = [];
|
||||
foreach (var fileResult in resultList)
|
||||
{
|
||||
returnList.Add(await ConvertToDto(fileResult, AttachedDto.TypeAttached.Image));
|
||||
returnList.Add(await UtilityFile.ConvertToDto(fileResult, AttachedDto.TypeAttached.Image));
|
||||
}
|
||||
|
||||
return returnList;
|
||||
}
|
||||
|
||||
private static async Task<AttachedDto> ConvertToDto(FileResult file, AttachedDto.TypeAttached type)
|
||||
{
|
||||
var stream = await file.OpenReadAsync();
|
||||
using var ms = new MemoryStream();
|
||||
await stream.CopyToAsync(ms);
|
||||
|
||||
return new AttachedDto
|
||||
{
|
||||
Name = file.FileName,
|
||||
Path = file.FullPath,
|
||||
MimeType = file.ContentType,
|
||||
DimensionBytes = ms.Length,
|
||||
FileBytes = ms.ToArray(),
|
||||
Type = type
|
||||
};
|
||||
}
|
||||
|
||||
private async Task<AttachedDto> ConvertToDto(FileInfo file, AttachedDto.TypeAttached type, bool isFromToUpload)
|
||||
{
|
||||
var (origUrl, thumbUrl) = await SaveAndCreateThumbAsync(
|
||||
await File.ReadAllBytesAsync(file.FullName),
|
||||
file.Name
|
||||
);
|
||||
|
||||
return new AttachedDto
|
||||
{
|
||||
Name = file.Name,
|
||||
Path = file.FullName,
|
||||
TempPath = origUrl,
|
||||
ThumbPath = thumbUrl,
|
||||
Type = type,
|
||||
SavedOnAppData = true,
|
||||
ToUpload = isFromToUpload
|
||||
};
|
||||
}
|
||||
|
||||
private const string ToUploadFolderName = "toUpload";
|
||||
|
||||
private string GetInspectionBaseDir(Ispezione ispezione)
|
||||
{
|
||||
var baseDir = FileSystem.AppDataDirectory;
|
||||
return Path.Combine(baseDir, $"attached_{GetInspectionKey(ispezione)}");
|
||||
}
|
||||
|
||||
private string GetInspectionToUploadDir(Ispezione ispezione)
|
||||
=> Path.Combine(GetInspectionBaseDir(ispezione), ToUploadFolderName);
|
||||
|
||||
private string GetInspectionFinalDir(Ispezione ispezione)
|
||||
=> GetInspectionBaseDir(ispezione);
|
||||
|
||||
/// <summary>
|
||||
/// Ritorna i file dell'ispezione filtrati per nome.
|
||||
/// Per default include sia "final" sia "toUpload" (utile per UI).
|
||||
/// </summary>
|
||||
public async Task<List<AttachedDto>?> GetInspectionFiles(
|
||||
Ispezione ispezione,
|
||||
List<string> fileNameFilter,
|
||||
bool includeToUpload,
|
||||
CancellationToken ct)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(ispezione);
|
||||
ArgumentNullException.ThrowIfNull(fileNameFilter);
|
||||
|
||||
var baseDir = GetInspectionBaseDir(ispezione);
|
||||
if (!Directory.Exists(baseDir)) return null;
|
||||
|
||||
var result = new List<AttachedDto>();
|
||||
|
||||
var finalDir = GetInspectionFinalDir(ispezione);
|
||||
if (Directory.Exists(finalDir))
|
||||
{
|
||||
var finalFiles = new DirectoryInfo(finalDir)
|
||||
.GetFiles("*", SearchOption.TopDirectoryOnly);
|
||||
|
||||
foreach (var file in finalFiles)
|
||||
{
|
||||
if (file.Directory?.Name == ToUploadFolderName)
|
||||
continue;
|
||||
|
||||
if (!fileNameFilter.Contains(file.Name))
|
||||
continue;
|
||||
|
||||
ct.ThrowIfCancellationRequested();
|
||||
|
||||
result.Add(await ConvertToDto(
|
||||
file,
|
||||
AttachedDto.TypeAttached.Image,
|
||||
isFromToUpload: false));
|
||||
}
|
||||
}
|
||||
|
||||
if (!includeToUpload) return result;
|
||||
|
||||
var toUploadDir = GetInspectionToUploadDir(ispezione);
|
||||
if (!Directory.Exists(toUploadDir)) return result;
|
||||
|
||||
var toUploadFiles = new DirectoryInfo(toUploadDir)
|
||||
.GetFiles("*", SearchOption.TopDirectoryOnly);
|
||||
|
||||
foreach (var file in toUploadFiles)
|
||||
{
|
||||
if (!fileNameFilter.Contains(file.Name))
|
||||
continue;
|
||||
|
||||
ct.ThrowIfCancellationRequested();
|
||||
|
||||
result.Add(await ConvertToDto(
|
||||
file,
|
||||
AttachedDto.TypeAttached.Image,
|
||||
isFromToUpload: true));
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Salva SEMPRE in /toUpload.
|
||||
/// </summary>
|
||||
public async Task<string?> SaveInspectionFile(
|
||||
Ispezione ispezione,
|
||||
byte[] file,
|
||||
string fileName,
|
||||
CancellationToken ct)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(ispezione);
|
||||
ArgumentNullException.ThrowIfNull(file);
|
||||
ArgumentException.ThrowIfNullOrWhiteSpace(fileName);
|
||||
|
||||
var toUploadDir = GetInspectionToUploadDir(ispezione);
|
||||
Directory.CreateDirectory(toUploadDir);
|
||||
|
||||
var filePath = Path.Combine(toUploadDir, fileName);
|
||||
await File.WriteAllBytesAsync(filePath, file, ct);
|
||||
|
||||
return filePath;
|
||||
}
|
||||
|
||||
public Task<bool> MoveInspectionFileFromToUploadToFinal(
|
||||
Ispezione ispezione,
|
||||
string fileName,
|
||||
bool overwrite,
|
||||
CancellationToken ct)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(ispezione);
|
||||
ArgumentException.ThrowIfNullOrWhiteSpace(fileName);
|
||||
|
||||
ct.ThrowIfCancellationRequested();
|
||||
|
||||
var toUploadDir = GetInspectionToUploadDir(ispezione);
|
||||
var finalDir = GetInspectionFinalDir(ispezione);
|
||||
|
||||
if (!Directory.Exists(toUploadDir)) return Task.FromResult(false);
|
||||
|
||||
var sourcePath = Path.Combine(toUploadDir, fileName);
|
||||
if (!File.Exists(sourcePath)) return Task.FromResult(false);
|
||||
|
||||
Directory.CreateDirectory(finalDir);
|
||||
|
||||
var destPath = Path.Combine(finalDir, fileName);
|
||||
|
||||
if (File.Exists(destPath))
|
||||
{
|
||||
if (!overwrite) return Task.FromResult(false);
|
||||
File.Delete(destPath);
|
||||
}
|
||||
|
||||
File.Move(sourcePath, destPath);
|
||||
|
||||
// Pulizia: se /toUpload resta vuota la elimino
|
||||
CleanupDirectoriesIfEmpty(ispezione);
|
||||
|
||||
return Task.FromResult(true);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Rimuove un file cercandolo prima in /toUpload e poi in final (o viceversa).
|
||||
/// Default: prova a cancellare ovunque.
|
||||
/// </summary>
|
||||
public bool RemoveInspectionFile(
|
||||
Ispezione ispezione,
|
||||
string fileName,
|
||||
bool removeAlsoFromFinal,
|
||||
bool removeAlsoFromToUpload)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(ispezione);
|
||||
if (string.IsNullOrWhiteSpace(fileName)) return false;
|
||||
|
||||
var removed = false;
|
||||
|
||||
if (removeAlsoFromToUpload)
|
||||
{
|
||||
var toUploadPath = Path.Combine(GetInspectionToUploadDir(ispezione), fileName);
|
||||
if (File.Exists(toUploadPath))
|
||||
{
|
||||
File.Delete(toUploadPath);
|
||||
removed = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (removeAlsoFromFinal)
|
||||
{
|
||||
var finalPath = Path.Combine(GetInspectionFinalDir(ispezione), fileName);
|
||||
if (File.Exists(finalPath))
|
||||
{
|
||||
File.Delete(finalPath);
|
||||
removed = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (removed)
|
||||
CleanupDirectoriesIfEmpty(ispezione);
|
||||
|
||||
return removed;
|
||||
}
|
||||
|
||||
private void CleanupDirectoriesIfEmpty(Ispezione ispezione)
|
||||
{
|
||||
var baseDir = GetInspectionBaseDir(ispezione);
|
||||
var toUploadDir = GetInspectionToUploadDir(ispezione);
|
||||
|
||||
// 1) se /toUpload esiste e vuota => delete
|
||||
if (Directory.Exists(toUploadDir) && !Directory.EnumerateFileSystemEntries(toUploadDir).Any())
|
||||
Directory.Delete(toUploadDir);
|
||||
|
||||
// 2) se base dir vuota (attenzione: dopo delete toUpload) => delete
|
||||
if (Directory.Exists(baseDir) && !Directory.EnumerateFileSystemEntries(baseDir).Any())
|
||||
Directory.Delete(baseDir);
|
||||
}
|
||||
|
||||
public async Task<string> SaveToTempStorage(Stream file, string fileName, CancellationToken ct = default)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(file);
|
||||
|
||||
if (file.CanSeek)
|
||||
file.Position = 0;
|
||||
|
||||
fileName = Path.GetFileName(fileName);
|
||||
|
||||
var dir = FileSystem.CacheDirectory;
|
||||
var filePath = Path.Combine(dir, fileName);
|
||||
|
||||
await using var fileStream = File.Create(filePath);
|
||||
await file.CopyToAsync(fileStream, ct);
|
||||
|
||||
return filePath;
|
||||
}
|
||||
|
||||
public Task CleanTempStorageAsync(CancellationToken ct = default)
|
||||
{
|
||||
return Task.Run(() =>
|
||||
{
|
||||
if (Directory.Exists(AttachedRoot))
|
||||
Directory.Delete(AttachedRoot, true);
|
||||
}, ct);
|
||||
}
|
||||
|
||||
public Task OpenFile(string fileName, string filePath)
|
||||
{
|
||||
#if IOS
|
||||
throw new NotImplementedException();
|
||||
#else
|
||||
return Launcher.OpenAsync(new OpenFileRequest
|
||||
{
|
||||
Title = "Apri file",
|
||||
File = new ReadOnlyFile(filePath)
|
||||
});
|
||||
#endif
|
||||
}
|
||||
|
||||
public async Task<(string originalUrl, string thumbUrl)> SaveAndCreateThumbAsync(
|
||||
byte[] bytes, string fileName, CancellationToken ct = default)
|
||||
{
|
||||
Directory.CreateDirectory(AttachedRoot);
|
||||
|
||||
var id = Guid.NewGuid().ToString("N");
|
||||
var safeName = SanitizeFileName(fileName);
|
||||
|
||||
var originalFile = $"{id}_{safeName}";
|
||||
var thumbFile = $"{id}_thumb.jpg";
|
||||
|
||||
var originalPath = Path.Combine(AttachedRoot, originalFile);
|
||||
await File.WriteAllBytesAsync(originalPath, bytes, ct);
|
||||
|
||||
var thumbPath = Path.Combine(AttachedRoot, thumbFile);
|
||||
await ImageThumb.CreateThumbnailAsync(originalPath, thumbPath, maxSide: 320, quality: 70, ct);
|
||||
|
||||
return ($"https://localfiles/attached/{originalFile}",
|
||||
$"https://localfiles/attached/{thumbFile}");
|
||||
}
|
||||
|
||||
private static string SanitizeFileName(string fileName)
|
||||
{
|
||||
var name = Path.GetFileName(fileName);
|
||||
return Path.GetInvalidFileNameChars().Aggregate(name, (current, c) => current.Replace(c, '_'));
|
||||
}
|
||||
|
||||
private static string GetInspectionKey(Ispezione ispezione) =>
|
||||
$"{ispezione.CodMdep}_{ispezione.Data:ddMMyyyy}_{ispezione.Rilevatore.ToLower()}";
|
||||
}
|
||||
Reference in New Issue
Block a user