370 lines
16 KiB
C#
370 lines
16 KiB
C#
using Disco.Data.Repository;
|
|
using Disco.Models.Repository;
|
|
using Disco.Services.Authorization;
|
|
using Disco.Services.Documents.ManagedGroups;
|
|
using Disco.Services.Users;
|
|
using System;
|
|
using System.Drawing;
|
|
using System.IO;
|
|
using System.Threading;
|
|
|
|
namespace Disco.Services
|
|
{
|
|
public static class AttachmentActionExtensions
|
|
{
|
|
#region Delete
|
|
public static bool CanDelete(this DeviceAttachment da)
|
|
{
|
|
if (UserService.CurrentAuthorization.Has(Claims.Device.Actions.RemoveAnyAttachments))
|
|
return true;
|
|
|
|
if (UserService.CurrentAuthorization.Has(Claims.Device.Actions.RemoveOwnAttachments)
|
|
&& da.TechUserId.Equals(UserService.CurrentUserId, StringComparison.OrdinalIgnoreCase))
|
|
return true;
|
|
|
|
return false;
|
|
}
|
|
public static void OnDelete(this DeviceAttachment da, DiscoDataContext Database)
|
|
{
|
|
if (!da.CanDelete())
|
|
throw new InvalidOperationException("Deletion of Attachment is Denied");
|
|
|
|
var attachmentId = da.Id;
|
|
var documentTemplateId = da.DocumentTemplateId;
|
|
var deviceSerialNumber = da.DeviceSerialNumber;
|
|
|
|
da.RepositoryDelete(Database);
|
|
Database.DeviceAttachments.Remove(da);
|
|
|
|
DocumentTemplateManagedGroups.TriggerDeviceAttachmentDeleted(Database, attachmentId, documentTemplateId, deviceSerialNumber);
|
|
}
|
|
public static bool CanDelete(this DeviceBatchAttachment attachment)
|
|
{
|
|
if (UserService.CurrentAuthorization.Has(Claims.Config.DeviceBatch.Configure))
|
|
return true;
|
|
|
|
return false;
|
|
}
|
|
public static void OnDelete(this DeviceBatchAttachment attachment, DiscoDataContext Database)
|
|
{
|
|
if (!attachment.CanDelete())
|
|
throw new InvalidOperationException("Deletion of Attachment is Denied");
|
|
|
|
attachment.RepositoryDelete(Database);
|
|
Database.DeviceBatchAttachments.Remove(attachment);
|
|
}
|
|
public static bool CanDelete(this JobAttachment ja)
|
|
{
|
|
if (UserService.CurrentAuthorization.Has(Claims.Job.Actions.RemoveAnyAttachments))
|
|
return true;
|
|
|
|
if (UserService.CurrentAuthorization.Has(Claims.Job.Actions.RemoveOwnAttachments)
|
|
&& ja.TechUserId.Equals(UserService.CurrentUserId, StringComparison.OrdinalIgnoreCase))
|
|
return true;
|
|
|
|
return false;
|
|
}
|
|
public static void OnDelete(this JobAttachment ja, DiscoDataContext Database)
|
|
{
|
|
if (!ja.CanDelete())
|
|
throw new InvalidOperationException("Deletion of Attachment is Denied");
|
|
|
|
var attachmentId = ja.Id;
|
|
var documentTemplateId = ja.DocumentTemplateId;
|
|
var jobId = ja.JobId;
|
|
|
|
ja.RepositoryDelete(Database);
|
|
Database.JobAttachments.Remove(ja);
|
|
|
|
DocumentTemplateManagedGroups.TriggerJobAttachmentDeleted(Database, attachmentId, documentTemplateId, jobId);
|
|
}
|
|
public static bool CanDelete(this UserAttachment ua)
|
|
{
|
|
if (UserService.CurrentAuthorization.Has(Claims.User.Actions.RemoveAnyAttachments))
|
|
return true;
|
|
|
|
if (UserService.CurrentAuthorization.Has(Claims.User.Actions.RemoveOwnAttachments)
|
|
&& ua.TechUserId.Equals(UserService.CurrentUserId, StringComparison.OrdinalIgnoreCase))
|
|
return true;
|
|
|
|
return false;
|
|
}
|
|
public static void OnDelete(this UserAttachment ua, DiscoDataContext Database)
|
|
{
|
|
if (!ua.CanDelete())
|
|
throw new InvalidOperationException("Deletion of Attachment is Denied");
|
|
|
|
var attachmentId = ua.Id;
|
|
var documentTemplateId = ua.DocumentTemplateId;
|
|
var userId = ua.UserId;
|
|
|
|
ua.RepositoryDelete(Database);
|
|
Database.UserAttachments.Remove(ua);
|
|
|
|
DocumentTemplateManagedGroups.TriggerUserAttachmentDeleted(Database, attachmentId, documentTemplateId, userId);
|
|
}
|
|
#endregion
|
|
|
|
public static DeviceAttachment CreateAttachment(this Device Device, DiscoDataContext Database, User CreatorUser, string Filename, string MimeType, string Comments, Stream Content, DocumentTemplate DocumentTemplate = null, Image PdfThumbnail = null)
|
|
=> Device.CreateAttachment(Database, CreatorUser, Filename, DateTime.Now, MimeType, Comments, Content, DocumentTemplate, PdfThumbnail);
|
|
|
|
public static DeviceAttachment CreateAttachment(this Device Device, DiscoDataContext Database, User CreatorUser, string Filename, DateTime timestamp, string MimeType, string Comments, Stream Content, DocumentTemplate DocumentTemplate = null, Image PdfThumbnail = null, string HandlerId = null, string HandlerReferenceId = null, string HandlerData = null)
|
|
{
|
|
if (string.IsNullOrEmpty(MimeType) || MimeType.Equals("unknown/unknown", StringComparison.OrdinalIgnoreCase))
|
|
MimeType = Interop.MimeTypes.ResolveMimeType(Filename);
|
|
|
|
DeviceAttachment da = new DeviceAttachment()
|
|
{
|
|
DeviceSerialNumber = Device.SerialNumber,
|
|
TechUserId = CreatorUser.UserId,
|
|
Filename = Filename,
|
|
MimeType = MimeType,
|
|
Timestamp = timestamp,
|
|
Comments = Comments,
|
|
HandlerId = HandlerId,
|
|
HandlerReferenceId = HandlerReferenceId,
|
|
HandlerData = HandlerData,
|
|
};
|
|
|
|
if (DocumentTemplate != null)
|
|
da.DocumentTemplateId = DocumentTemplate.Id;
|
|
|
|
Database.DeviceAttachments.Add(da);
|
|
Database.SaveChanges();
|
|
|
|
da.SaveAttachment(Database, Content);
|
|
Content.Position = 0;
|
|
if (PdfThumbnail == null)
|
|
da.GenerateThumbnail(Database, Content);
|
|
else
|
|
da.SaveThumbnailAttachment(Database, PdfThumbnail);
|
|
|
|
return da;
|
|
}
|
|
|
|
public static JobAttachment CreateAttachment(this Job Job, DiscoDataContext Database, User CreatorUser, string Filename, string MimeType, string Comments, Stream Content, DocumentTemplate DocumentTemplate = null, Image PdfThumbnail = null)
|
|
=> Job.CreateAttachment(Database, CreatorUser, Filename, DateTime.Now, MimeType, Comments, Content, DocumentTemplate, PdfThumbnail);
|
|
|
|
public static JobAttachment CreateAttachment(this Job Job, DiscoDataContext Database, User CreatorUser, string Filename, DateTime Timestamp, string MimeType, string Comments, Stream Content, DocumentTemplate DocumentTemplate = null, Image PdfThumbnail = null, string HandlerId = null, string HandlerReferenceId = null, string HandlerData = null)
|
|
{
|
|
if (string.IsNullOrEmpty(MimeType) || MimeType.Equals("unknown/unknown", StringComparison.OrdinalIgnoreCase))
|
|
MimeType = Interop.MimeTypes.ResolveMimeType(Filename);
|
|
|
|
JobAttachment ja = new JobAttachment()
|
|
{
|
|
JobId = Job.Id,
|
|
TechUserId = CreatorUser.UserId,
|
|
Filename = Filename,
|
|
MimeType = MimeType,
|
|
Timestamp = Timestamp,
|
|
Comments = Comments,
|
|
HandlerId = HandlerId,
|
|
HandlerReferenceId = HandlerReferenceId,
|
|
HandlerData = HandlerData,
|
|
};
|
|
|
|
if (DocumentTemplate != null)
|
|
ja.DocumentTemplateId = DocumentTemplate.Id;
|
|
|
|
Database.JobAttachments.Add(ja);
|
|
Database.SaveChanges();
|
|
|
|
ja.SaveAttachment(Database, Content);
|
|
Content.Position = 0;
|
|
if (PdfThumbnail == null)
|
|
ja.GenerateThumbnail(Database, Content);
|
|
else
|
|
ja.SaveThumbnailAttachment(Database, PdfThumbnail);
|
|
|
|
return ja;
|
|
}
|
|
|
|
public static UserAttachment CreateAttachment(this User User, DiscoDataContext Database, User CreatorUser, string Filename, string MimeType, string Comments, Stream Content, DocumentTemplate DocumentTemplate = null, Image PdfThumbnail = null)
|
|
=> User.CreateAttachment(Database, CreatorUser, Filename, DateTime.Now, MimeType, Comments, Content, DocumentTemplate, PdfThumbnail);
|
|
|
|
public static UserAttachment CreateAttachment(this User User, DiscoDataContext Database, User CreatorUser, string Filename, DateTime Timestamp, string MimeType, string Comments, Stream Content, DocumentTemplate DocumentTemplate = null, Image PdfThumbnail = null, string HandlerId = null, string HandlerReferenceId = null, string HandlerData = null)
|
|
{
|
|
if (string.IsNullOrEmpty(MimeType) || MimeType.Equals("unknown/unknown", StringComparison.OrdinalIgnoreCase))
|
|
MimeType = Interop.MimeTypes.ResolveMimeType(Filename);
|
|
|
|
UserAttachment ua = new UserAttachment()
|
|
{
|
|
UserId = User.UserId,
|
|
TechUserId = CreatorUser.UserId,
|
|
Filename = Filename,
|
|
MimeType = MimeType,
|
|
Timestamp = Timestamp,
|
|
Comments = Comments,
|
|
HandlerId = HandlerId,
|
|
HandlerReferenceId = HandlerReferenceId,
|
|
HandlerData = HandlerData,
|
|
};
|
|
|
|
if (DocumentTemplate != null)
|
|
ua.DocumentTemplateId = DocumentTemplate.Id;
|
|
|
|
Database.UserAttachments.Add(ua);
|
|
Database.SaveChanges();
|
|
|
|
ua.SaveAttachment(Database, Content);
|
|
Content.Position = 0;
|
|
if (PdfThumbnail == null)
|
|
ua.GenerateThumbnail(Database, Content);
|
|
else
|
|
ua.SaveThumbnailAttachment(Database, PdfThumbnail);
|
|
|
|
return ua;
|
|
}
|
|
|
|
public static bool WaitForThumbnailGeneration(this IAttachment attachment, DiscoDataContext database, out string thumbnailPath, out string mimeType)
|
|
{
|
|
thumbnailPath = attachment.RepositoryThumbnailFilename(database);
|
|
if (thumbnailPath.EndsWith(".png"))
|
|
mimeType = "image/png";
|
|
else
|
|
mimeType = "image/jpeg";
|
|
|
|
if (File.Exists(thumbnailPath))
|
|
return true;
|
|
|
|
// recently created attachments may not have a thumbnail yet
|
|
var timestamp = attachment.Timestamp;
|
|
if (timestamp > DateTime.Now.AddSeconds(-5) && attachment.SupportsThumbnailGeneration(out _, out _))
|
|
{
|
|
while (!File.Exists(thumbnailPath) && timestamp > DateTime.Now.AddSeconds(-5))
|
|
Thread.Sleep(250);
|
|
|
|
if (File.Exists(thumbnailPath))
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
public static string GenerateThumbnail(this IAttachment attachment, DiscoDataContext Database, Stream AttachmentStream)
|
|
{
|
|
string thumbnailFilePath = attachment.RepositoryThumbnailFilename(Database);
|
|
|
|
if (attachment.GenerateThumbnail(AttachmentStream, out var thumbnail))
|
|
{
|
|
thumbnail.SaveJpg(90, thumbnailFilePath);
|
|
}
|
|
|
|
return thumbnailFilePath;
|
|
}
|
|
|
|
public static string GenerateThumbnail(this IAttachment attachment, DiscoDataContext Database)
|
|
{
|
|
string thumbnailFilePath = attachment.RepositoryThumbnailFilename(Database);
|
|
|
|
using (var attachmentStream = File.OpenRead(attachment.RepositoryFilename(Database)))
|
|
{
|
|
if (attachment.GenerateThumbnail(attachmentStream, out var thumbnail))
|
|
{
|
|
thumbnail.SaveJpg(90, thumbnailFilePath);
|
|
}
|
|
}
|
|
|
|
return thumbnailFilePath;
|
|
}
|
|
|
|
|
|
private const string pdfMimeType = "application/pdf";
|
|
private const string pdfExtension = "pdf";
|
|
private static readonly string[] imageMimeTypes = new string[] { "image/jpeg", "image/png", "image/gif", "image/bmp" };
|
|
private static readonly string[] imageExtensions = new string[] { ".jpg", ".jpeg", ".png", ".gif", ".bmp" };
|
|
public static (bool supported, bool isImage, bool isPdf) SupportsThumbnailGeneration(string mimeType, string fileName)
|
|
{
|
|
if (!string.IsNullOrEmpty(mimeType))
|
|
{
|
|
if (pdfMimeType.Equals(mimeType, StringComparison.OrdinalIgnoreCase))
|
|
return (true, false, true);
|
|
foreach (var imageMimeType in imageMimeTypes)
|
|
if (mimeType.Equals(imageMimeType, StringComparison.OrdinalIgnoreCase))
|
|
return (true, true, false);
|
|
}
|
|
|
|
if (!string.IsNullOrEmpty(fileName))
|
|
{
|
|
if (fileName.EndsWith(pdfExtension, StringComparison.OrdinalIgnoreCase))
|
|
return (true, false, true);
|
|
foreach (var imageExtension in imageExtensions)
|
|
if (fileName.EndsWith(imageExtension, StringComparison.OrdinalIgnoreCase))
|
|
return (true, true, false);
|
|
}
|
|
|
|
return (false, false, false);
|
|
}
|
|
|
|
public static bool SupportsThumbnailGeneration(this IAttachment attachment, out bool isImage, out bool isPdf)
|
|
{
|
|
var result = SupportsThumbnailGeneration(attachment.MimeType, attachment.Filename);
|
|
|
|
isImage = result.isImage;
|
|
isPdf = result.isPdf;
|
|
|
|
return result.supported;
|
|
}
|
|
|
|
public static bool GenerateThumbnail(this IAttachment attachment, Stream source, out Image thumbnail)
|
|
{
|
|
if (source != null)
|
|
{
|
|
var (supported, isImage, isPdf) = SupportsThumbnailGeneration(attachment.MimeType, attachment.Filename);
|
|
|
|
if (supported)
|
|
{
|
|
// GDI+ (jpg, png, gif, bmp)
|
|
if (isImage)
|
|
{
|
|
try
|
|
{
|
|
using (Image sourceImage = Image.FromStream(source))
|
|
{
|
|
thumbnail = sourceImage.ResizeImage(48, 48, Brushes.Black);
|
|
using (Image mimeTypeIcon = Properties.Resources.MimeType_img16)
|
|
{
|
|
thumbnail.EmbedIconOverlay(mimeTypeIcon);
|
|
}
|
|
return true;
|
|
}
|
|
}
|
|
catch (Exception) { }
|
|
|
|
}
|
|
|
|
// PDF
|
|
if (isPdf)
|
|
{
|
|
try
|
|
{
|
|
using (var pdfiumDocument = PdfiumViewer.PdfDocument.Load(source))
|
|
{
|
|
|
|
if (pdfiumDocument.PageCount > 0)
|
|
{
|
|
var pageSize = pdfiumDocument.PageSizes[0];
|
|
var size = ImagingExtensions.CalculateResize((int)pageSize.Width, (int)pageSize.Height, 48, 48);
|
|
|
|
using (var sourceImage = pdfiumDocument.Render(0, (int)size.Width, (int)size.Height, 72, 72, true))
|
|
{
|
|
thumbnail = sourceImage.ResizeImage(48, 48, Brushes.White);
|
|
using (Image mimeTypeIcon = Properties.Resources.MimeType_pdf16)
|
|
{
|
|
thumbnail.EmbedIconOverlay(mimeTypeIcon);
|
|
}
|
|
return true;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
catch (Exception) { }
|
|
}
|
|
}
|
|
}
|
|
thumbnail = null;
|
|
return false;
|
|
}
|
|
}
|
|
}
|