Files
Disco/Disco.Services/Documents/DocumentTemplateExtensions.cs
T
Gary Sharp 47e11c0fd6 bugs: minor
2023-01-29 10:10:37 +11:00

173 lines
7.9 KiB
C#

using Disco.Data.Repository;
using Disco.Models.Repository;
using Disco.Services.Authorization;
using Disco.Services.Interop.ActiveDirectory;
using Disco.Services.Users;
using System;
using System.Data.Entity;
using System.Drawing;
using System.IO;
using System.Linq;
namespace Disco.Services
{
public static class DocumentTemplateExtensions
{
public static Bitmap GenerateTemplatePreview(this DocumentTemplate DocumentTemplate, DiscoDataContext Database, int Width, int PageGapHeight, bool DrawPageBorder)
{
string filename = DocumentTemplate.RepositoryFilename(Database);
if (File.Exists(filename))
{
using (var fileStream = new FileStream(filename, FileMode.Open, FileAccess.Read, FileShare.Read))
{
using (var pdfDocument = PdfiumViewer.PdfDocument.Load(fileStream))
{
var pageMaxWidth = (int)pdfDocument.PageSizes.Max(s => s.Width);
var pageScale = (float)(Width + (DrawPageBorder ? -2 : 0)) / pageMaxWidth;
var previewTotalHeight = pdfDocument.PageSizes
.Take(40)
.Select(s => (int)(pageScale * s.Height))
.Sum() +
(DrawPageBorder ? (Math.Min(40, pdfDocument.PageCount) * 2) : 0) +
((Math.Min(40, pdfDocument.PageCount) - 1) * PageGapHeight);
var result = new Bitmap(Width, previewTotalHeight);
result.SetResolution(72, 72);
using (var graphics = Graphics.FromImage(result))
{
var yPosition = 0;
for (int pageIndex = 0; pageIndex < Math.Min(40, pdfDocument.PageCount); pageIndex++)
{
var pageSize = pdfDocument.PageSizes[pageIndex];
var previewWidth = Math.Floor(pageScale * pageSize.Width);
var previewHeight = Math.Floor(pageScale * pageSize.Height);
// Calculate box
var destination = new Rectangle(
x: (int)((Width - previewWidth) / 2),
y: yPosition + (DrawPageBorder ? 1 : 0),
width: (int)previewWidth,
height: (int)previewHeight
);
// Fill white background
graphics.FillRectangle(Brushes.White, destination);
using (var image = pdfDocument.Render(pageIndex, (int)previewWidth, (int)previewHeight, 72F, 72F, true))
{
graphics.DrawImage(image, destination.X, destination.Y);
}
if (DrawPageBorder)
{
destination.X -= 1;
destination.Y -= 1;
destination.Width += 1;
destination.Height += 1;
graphics.DrawRectangle(Pens.LightGray, destination);
}
yPosition += destination.Height + PageGapHeight;
}
}
return result;
}
}
}
return null;
}
public static IAttachmentTarget ResolveScopeTarget(this AttachmentTypes scope, DiscoDataContext database, string targetId)
=> ResolveScopeTarget(scope, database, targetId, out _);
public static IAttachmentTarget ResolveScopeTarget(this AttachmentTypes scope, DiscoDataContext database, string targetId, out User targetUser)
{
if (database == null)
throw new ArgumentNullException(nameof(database));
if (string.IsNullOrWhiteSpace(targetId))
throw new ArgumentNullException(nameof(targetId));
switch (scope)
{
case AttachmentTypes.Device:
var device = database.Devices.Include(d => d.AssignedUser).First(d => d.SerialNumber == targetId);
targetUser = device?.AssignedUser;
return device;
case AttachmentTypes.Job:
if (!int.TryParse(targetId, out var targetIdInt))
throw new ArgumentOutOfRangeException(nameof(targetId));
var job = database.Jobs.Include(j => j.User).First(j => j.Id == targetIdInt);
targetUser = job?.User;
return job;
case AttachmentTypes.User:
// special usecase in resolving users (they may not exist in the database yet)
targetId = ActiveDirectory.ParseDomainAccountId(targetId);
var user = database.Users.First(u => u.UserId == targetId);
if (user == null)
{
// try importing user
user = UserService.GetUser(targetId, database, true);
}
targetUser = user;
return user;
default:
throw new InvalidOperationException("Unexpected DocumentType Scope");
}
}
public static IAttachmentTarget ResolveScopeTarget(this DocumentTemplate template, DiscoDataContext database, string targetId)
=> ResolveScopeTarget(template, database, targetId, out _);
public static IAttachmentTarget ResolveScopeTarget(this DocumentTemplate template, DiscoDataContext database, string targetId, out User targetUser)
{
if (template == null)
throw new ArgumentNullException(nameof(template));
return ResolveScopeTarget(template.AttachmentType, database, targetId, out targetUser);
}
public static void GetTemplateAndTarget(DiscoDataContext database, AuthorizationToken authorization, string templateId, string targetId, out DocumentTemplate template, out IAttachmentTarget target, out User targetUser)
{
if (string.IsNullOrWhiteSpace(templateId))
throw new ArgumentNullException(nameof(templateId));
if (string.IsNullOrWhiteSpace(targetId))
throw new ArgumentNullException(nameof(targetId));
// get template
template = database.DocumentTemplates.Find(templateId);
if (template == null)
throw new ArgumentException("Invalid document template id", nameof(templateId));
// validate authorization
switch (template.Scope)
{
case DocumentTemplate.DocumentTemplateScopes.Device:
authorization.Require(Claims.Device.Actions.GenerateDocuments);
break;
case DocumentTemplate.DocumentTemplateScopes.Job:
authorization.Require(Claims.Job.Actions.GenerateDocuments);
break;
case DocumentTemplate.DocumentTemplateScopes.User:
authorization.Require(Claims.User.Actions.GenerateDocuments);
break;
default:
throw new InvalidOperationException("Unknown DocumentType Scope");
}
// resolve target
target = template.ResolveScopeTarget(database, targetId, out targetUser);
if (target == null)
throw new ArgumentException("Target not found", nameof(targetId));
}
}
}