Pdf Import Rewrite
Pdf Import rewritten to greatly improve QR Code detection, reduce reliance on iTextSharp and improve thumbnails. Fixes #50
This commit is contained in:
@@ -1,102 +0,0 @@
|
|||||||
using Disco.BI.Extensions;
|
|
||||||
using Exceptionless;
|
|
||||||
using iTextSharp.text.pdf;
|
|
||||||
using System;
|
|
||||||
using System.Drawing;
|
|
||||||
using System.IO;
|
|
||||||
using System.Linq;
|
|
||||||
|
|
||||||
namespace Disco.BI.AttachmentBI
|
|
||||||
{
|
|
||||||
public static class Utilities
|
|
||||||
{
|
|
||||||
|
|
||||||
public static bool GenerateThumbnail(Stream Source, string SourceMimeType, Stream OutStream)
|
|
||||||
{
|
|
||||||
if (Source != null)
|
|
||||||
{
|
|
||||||
// GDI+ (jpg, png, gif, bmp)
|
|
||||||
if (SourceMimeType.Equals("image/jpeg", StringComparison.OrdinalIgnoreCase) || SourceMimeType.Contains("jpg") ||
|
|
||||||
SourceMimeType.Equals("image/png", StringComparison.OrdinalIgnoreCase) || SourceMimeType.Contains("png") ||
|
|
||||||
SourceMimeType.Equals("image/gif", StringComparison.OrdinalIgnoreCase) || SourceMimeType.Contains("gif") ||
|
|
||||||
SourceMimeType.Equals("image/bmp", StringComparison.OrdinalIgnoreCase) || SourceMimeType.Contains("bmp"))
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
using (Image sourceImage = Image.FromStream(Source))
|
|
||||||
{
|
|
||||||
using (Image thumbImage = sourceImage.ResizeImage(48, 48))
|
|
||||||
{
|
|
||||||
using (Image mimeTypeIcon = Disco.Properties.Resources.MimeType_img16)
|
|
||||||
thumbImage.EmbedIconOverlay(mimeTypeIcon);
|
|
||||||
thumbImage.SaveJpg(90, OutStream);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
ex.ToExceptionless().Submit();
|
|
||||||
|
|
||||||
// Ignore Thumbnail Generation exceptions for images
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
// PDF
|
|
||||||
if (SourceMimeType.Equals("application/pdf", StringComparison.OrdinalIgnoreCase) || SourceMimeType.Contains("pdf"))
|
|
||||||
{
|
|
||||||
PdfReader pdfReader = new PdfReader(Source);
|
|
||||||
try
|
|
||||||
{
|
|
||||||
using (DisposableImageCollection pdfPageImages = pdfReader.PdfPageImages(1))
|
|
||||||
{
|
|
||||||
if (pdfPageImages.Count() > 0)
|
|
||||||
{
|
|
||||||
// Find Biggest Image on Page
|
|
||||||
Image biggestImage = pdfPageImages.OrderByDescending(i => i.Height * i.Width).First();
|
|
||||||
using (Image thumbImage = biggestImage.ResizeImage(48, 48, Brushes.White))
|
|
||||||
{
|
|
||||||
using (Image mimeTypeIcon = Disco.Properties.Resources.MimeType_pdf16)
|
|
||||||
thumbImage.EmbedIconOverlay(mimeTypeIcon);
|
|
||||||
thumbImage.SaveJpg(90, OutStream);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
ex.ToExceptionless().Submit();
|
|
||||||
}
|
|
||||||
finally
|
|
||||||
{
|
|
||||||
if (pdfReader != null)
|
|
||||||
pdfReader.Close();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
public static bool GenerateThumbnail(string SourceFilename, string SourceMimeType, string DestinationFilename)
|
|
||||||
{
|
|
||||||
using (FileStream sourceStream = new FileStream(SourceFilename, FileMode.Open, FileAccess.Read))
|
|
||||||
{
|
|
||||||
return GenerateThumbnail(sourceStream, SourceMimeType, DestinationFilename);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
public static bool GenerateThumbnail(Stream Source, string SourceMimeType, string DestinationFilename)
|
|
||||||
{
|
|
||||||
bool result;
|
|
||||||
using (FileStream destinationStream = new FileStream(DestinationFilename, FileMode.Create, FileAccess.Write, FileShare.None))
|
|
||||||
{
|
|
||||||
result = GenerateThumbnail(Source, SourceMimeType, destinationStream);
|
|
||||||
}
|
|
||||||
if (!result && File.Exists(DestinationFilename))
|
|
||||||
File.Delete(DestinationFilename);
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,78 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
|
||||||
using System.Collections.Concurrent;
|
|
||||||
using Disco.Models.Repository;
|
|
||||||
using Disco.Data.Repository;
|
|
||||||
using Disco.BI.Extensions;
|
|
||||||
using System.Web;
|
|
||||||
using System.Drawing;
|
|
||||||
using iTextSharp.text.pdf;
|
|
||||||
|
|
||||||
namespace Disco.BI.DocumentTemplateBI
|
|
||||||
{
|
|
||||||
class DocumentTemplateQRCodeLocationCache
|
|
||||||
{
|
|
||||||
private static ConcurrentDictionary<string, List<RectangleF>> _Cache = new ConcurrentDictionary<string, List<RectangleF>>();
|
|
||||||
|
|
||||||
public static List<RectangleF> GetLocations(DocumentTemplate dt, DiscoDataContext Database)
|
|
||||||
{
|
|
||||||
// Check Cache
|
|
||||||
List<RectangleF> locations;
|
|
||||||
if (_Cache.TryGetValue(dt.Id, out locations))
|
|
||||||
{
|
|
||||||
return locations;
|
|
||||||
}
|
|
||||||
// Generate Cache
|
|
||||||
return GenerateLocations(dt, Database);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static bool InvalidateLocations(DocumentTemplate dt)
|
|
||||||
{
|
|
||||||
List<RectangleF> locations;
|
|
||||||
return _Cache.TryRemove(dt.Id, out locations);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static bool SetValue(string DocumentTemplateId, List<RectangleF> Locations)
|
|
||||||
{
|
|
||||||
if (_Cache.ContainsKey(DocumentTemplateId))
|
|
||||||
{
|
|
||||||
List<RectangleF> oldLocations;
|
|
||||||
if (_Cache.TryGetValue(DocumentTemplateId, out oldLocations))
|
|
||||||
{
|
|
||||||
return _Cache.TryUpdate(DocumentTemplateId, Locations, oldLocations);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return _Cache.TryAdd(DocumentTemplateId, Locations);
|
|
||||||
}
|
|
||||||
|
|
||||||
internal static List<RectangleF> GenerateLocations(DocumentTemplate dt, DiscoDataContext Database)
|
|
||||||
{
|
|
||||||
string templateFilename = dt.RepositoryFilename(Database);
|
|
||||||
PdfReader pdfReader = new PdfReader(templateFilename);
|
|
||||||
List<RectangleF> locations = new List<RectangleF>();
|
|
||||||
|
|
||||||
if (pdfReader.AcroFields.Fields.ContainsKey("DiscoAttachmentId"))
|
|
||||||
{
|
|
||||||
foreach (var pdfFieldPosition in pdfReader.AcroFields.GetFieldPositions("DiscoAttachmentId"))
|
|
||||||
{
|
|
||||||
var pdfPageSize = pdfReader.GetPageSize(pdfFieldPosition.page);
|
|
||||||
// Original Position
|
|
||||||
locations.Add(new RectangleF(
|
|
||||||
(float)System.Math.Min(1.0, System.Math.Max(0.0, (double)(pdfFieldPosition.position.Left / pdfPageSize.Width) - 0.05)),
|
|
||||||
(float)System.Math.Min(1.0, System.Math.Max(0.0, (double)((pdfPageSize.Height - pdfFieldPosition.position.Top) / pdfPageSize.Height) - 0.05)),
|
|
||||||
(float)System.Math.Min(1.0, System.Math.Max(0.0, (double)(pdfFieldPosition.position.Width / pdfPageSize.Width) + 0.1)),
|
|
||||||
(float)System.Math.Min(1.0, System.Math.Max(0.0, (double)(pdfFieldPosition.position.Height / pdfPageSize.Height) + 0.1))
|
|
||||||
));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
pdfReader.Close();
|
|
||||||
|
|
||||||
// Update Cache
|
|
||||||
SetValue(dt.Id, locations);
|
|
||||||
return locations;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,204 +0,0 @@
|
|||||||
using Disco.Data.Repository;
|
|
||||||
using Disco.Models.Repository;
|
|
||||||
using Disco.Services.Interop.ActiveDirectory;
|
|
||||||
using System;
|
|
||||||
namespace Disco.BI.DocumentTemplateBI
|
|
||||||
{
|
|
||||||
public class DocumentUniqueIdentifier
|
|
||||||
{
|
|
||||||
private bool? _loadedComponentsOk;
|
|
||||||
private DocumentTemplate _documentTemplate;
|
|
||||||
private object _data;
|
|
||||||
private string _dataDescription;
|
|
||||||
public string TemplateTypeId { get; private set; }
|
|
||||||
public string DataId { get; private set; }
|
|
||||||
public string DocumentUniqueId
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
return string.Format("{0}|{1}", this.TemplateTypeId, this.DataId);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
public string CreatorId { get; private set; }
|
|
||||||
public System.DateTime TimeStamp { get; private set; }
|
|
||||||
public int Page { get; private set; }
|
|
||||||
public string Tag { get; private set; }
|
|
||||||
public DocumentTemplate DocumentTemplate
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
bool flag = this._loadedComponentsOk.HasValue && this._loadedComponentsOk.Value;
|
|
||||||
if (flag)
|
|
||||||
{
|
|
||||||
return this._documentTemplate;
|
|
||||||
}
|
|
||||||
throw new System.Exception("Document Unique Identifier Components not loaded or invalid");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
public object Data
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
bool flag = this._loadedComponentsOk.HasValue && this._loadedComponentsOk.Value;
|
|
||||||
if (flag)
|
|
||||||
{
|
|
||||||
return this._data;
|
|
||||||
}
|
|
||||||
throw new System.Exception("Document Unique Identifier Components not loaded or invalid");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
public string DataDescription
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
bool flag = this._loadedComponentsOk.HasValue && this._loadedComponentsOk.Value;
|
|
||||||
if (flag)
|
|
||||||
{
|
|
||||||
return this._dataDescription;
|
|
||||||
}
|
|
||||||
throw new System.Exception("Document Unique Identifier Components not loaded or invalid");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
public string DataScope { get; private set; }
|
|
||||||
public static bool IsDocumentUniqueIdentifier(string UniqueIdentifier)
|
|
||||||
{
|
|
||||||
return UniqueIdentifier.StartsWith("Disco|", System.StringComparison.OrdinalIgnoreCase);
|
|
||||||
}
|
|
||||||
public DocumentUniqueIdentifier(string TemplateTypeId, string DataId, string CreatorId, DateTime TimeStamp, int? Page = null, string Tag = null)
|
|
||||||
{
|
|
||||||
this.Tag = Tag;
|
|
||||||
this.TemplateTypeId = TemplateTypeId;
|
|
||||||
this.DataId = DataId;
|
|
||||||
this.CreatorId = ActiveDirectory.ParseDomainAccountId(CreatorId);
|
|
||||||
this.TimeStamp = TimeStamp;
|
|
||||||
this.Page = Page ?? 0;
|
|
||||||
}
|
|
||||||
public DocumentUniqueIdentifier(string UniqueIdentifier, string Tag)
|
|
||||||
{
|
|
||||||
if (!DocumentUniqueIdentifier.IsDocumentUniqueIdentifier(UniqueIdentifier))
|
|
||||||
{
|
|
||||||
throw new System.ArgumentException("Invalid Document Unique Identifier", "UniqueIdentifier");
|
|
||||||
}
|
|
||||||
this.Tag = Tag;
|
|
||||||
string[] s = UniqueIdentifier.Split(new char[] { '|' });
|
|
||||||
string left = s[1].ToUpper();
|
|
||||||
if (left == "AT" || left == "1")
|
|
||||||
{
|
|
||||||
if (s.Length >= 3)
|
|
||||||
{
|
|
||||||
this.TemplateTypeId = s[2];
|
|
||||||
}
|
|
||||||
if (s.Length >= 4)
|
|
||||||
{
|
|
||||||
this.DataId = s[3];
|
|
||||||
}
|
|
||||||
if (s.Length >= 5)
|
|
||||||
{
|
|
||||||
this.CreatorId = ActiveDirectory.ParseDomainAccountId(s[4]);
|
|
||||||
}
|
|
||||||
if (s.Length >= 6)
|
|
||||||
{
|
|
||||||
System.DateTime timeStamp;
|
|
||||||
if (System.DateTime.TryParse(s[5], out timeStamp))
|
|
||||||
{
|
|
||||||
this.TimeStamp = timeStamp;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (s.Length >= 7)
|
|
||||||
{
|
|
||||||
int page = 0;
|
|
||||||
if (int.TryParse(s[6], out page))
|
|
||||||
{
|
|
||||||
this.Page = page;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
throw new System.ArgumentException(string.Format("Invalid Document Unique Identifier Version ({0})", s[1]), "UniqueIdentifier");
|
|
||||||
}
|
|
||||||
public bool LoadComponents(DiscoDataContext Database)
|
|
||||||
{
|
|
||||||
bool LoadComponents;
|
|
||||||
if (!this._loadedComponentsOk.HasValue)
|
|
||||||
{
|
|
||||||
string scopeType;
|
|
||||||
if (this.TemplateTypeId.StartsWith("--"))
|
|
||||||
{
|
|
||||||
string templateTypeId = this.TemplateTypeId;
|
|
||||||
switch (this.TemplateTypeId)
|
|
||||||
{
|
|
||||||
case "--DEVICE":
|
|
||||||
scopeType = DocumentTemplate.DocumentTemplateScopes.Device;
|
|
||||||
break;
|
|
||||||
case "--JOB":
|
|
||||||
scopeType = DocumentTemplate.DocumentTemplateScopes.Job;
|
|
||||||
break;
|
|
||||||
case "--USER":
|
|
||||||
scopeType = DocumentTemplate.DocumentTemplateScopes.User;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
scopeType = null;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
this._documentTemplate = Database.DocumentTemplates.Find(this.TemplateTypeId);
|
|
||||||
if (this._documentTemplate != null)
|
|
||||||
{
|
|
||||||
scopeType = this._documentTemplate.Scope;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
scopeType = null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (scopeType != null)
|
|
||||||
{
|
|
||||||
this.DataScope = scopeType;
|
|
||||||
switch (scopeType)
|
|
||||||
{
|
|
||||||
case DocumentTemplate.DocumentTemplateScopes.Device:
|
|
||||||
Device d = Database.Devices.Find(this.DataId);
|
|
||||||
if (d != null)
|
|
||||||
{
|
|
||||||
this._data = d;
|
|
||||||
this._dataDescription = d.SerialNumber;
|
|
||||||
this._loadedComponentsOk = true;
|
|
||||||
LoadComponents = true;
|
|
||||||
return LoadComponents;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case DocumentTemplate.DocumentTemplateScopes.Job:
|
|
||||||
Job i = Database.Jobs.Find(int.Parse(this.DataId));
|
|
||||||
if (i != null)
|
|
||||||
{
|
|
||||||
this._data = i;
|
|
||||||
this._dataDescription = i.Id.ToString();
|
|
||||||
this._loadedComponentsOk = true;
|
|
||||||
LoadComponents = true;
|
|
||||||
return LoadComponents;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case DocumentTemplate.DocumentTemplateScopes.User:
|
|
||||||
User u = Database.Users.Find(ActiveDirectory.ParseDomainAccountId(this.DataId));
|
|
||||||
if (u != null)
|
|
||||||
{
|
|
||||||
this._data = u;
|
|
||||||
this._dataDescription = u.DisplayName;
|
|
||||||
this._loadedComponentsOk = true;
|
|
||||||
LoadComponents = true;
|
|
||||||
return LoadComponents;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
this._loadedComponentsOk = false;
|
|
||||||
}
|
|
||||||
LoadComponents = this._loadedComponentsOk.Value;
|
|
||||||
return LoadComponents;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,478 +0,0 @@
|
|||||||
using Disco.Models.Repository;
|
|
||||||
using Disco.Services.Logging;
|
|
||||||
using Disco.Services.Logging.Models;
|
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Diagnostics;
|
|
||||||
namespace Disco.BI.DocumentTemplateBI
|
|
||||||
{
|
|
||||||
public class DocumentsLog : LogBase
|
|
||||||
{
|
|
||||||
public enum EventTypeIds
|
|
||||||
{
|
|
||||||
ImportStarting = 10,
|
|
||||||
ImportProgress,
|
|
||||||
ImportFinished,
|
|
||||||
ImportWarning = 15,
|
|
||||||
ImportError,
|
|
||||||
ImportAttachmentExpressionEvaluated = 50,
|
|
||||||
ImportPageStarting = 100,
|
|
||||||
ImportPageImageUpdate = 104,
|
|
||||||
ImportPageProgress,
|
|
||||||
ImportPageDetected = 110,
|
|
||||||
ImportPageUndetected = 115,
|
|
||||||
ImportPageError = 120,
|
|
||||||
ImportPageUndetectedStored = 150,
|
|
||||||
DocumentGenerated = 500,
|
|
||||||
DocumentGeneratedWithExpression
|
|
||||||
}
|
|
||||||
|
|
||||||
private const int _ModuleId = 40;
|
|
||||||
|
|
||||||
public static DocumentsLog Current
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
return (DocumentsLog)LogContext.LogModules[_ModuleId];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public override string ModuleDescription
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
return "Documents";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
public override int ModuleId
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
return _ModuleId;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
public override string ModuleName
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
return "Documents";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
private static void Log(DocumentsLog.EventTypeIds EventTypeId, params object[] Args)
|
|
||||||
{
|
|
||||||
DocumentsLog.Current.Log((int)EventTypeId, Args);
|
|
||||||
}
|
|
||||||
public static void LogImportStarting(string SessionId, string DocumentName)
|
|
||||||
{
|
|
||||||
DocumentsLog.Log(DocumentsLog.EventTypeIds.ImportStarting, new object[]
|
|
||||||
{
|
|
||||||
SessionId,
|
|
||||||
DocumentName
|
|
||||||
});
|
|
||||||
}
|
|
||||||
public static void LogImportProgress(string SessionId, int? Progress, string Status)
|
|
||||||
{
|
|
||||||
DocumentsLog.Log(DocumentsLog.EventTypeIds.ImportProgress, new object[]
|
|
||||||
{
|
|
||||||
SessionId,
|
|
||||||
Progress,
|
|
||||||
Status
|
|
||||||
});
|
|
||||||
}
|
|
||||||
public static void LogImportFinished(string SessionId)
|
|
||||||
{
|
|
||||||
DocumentsLog.Log(DocumentsLog.EventTypeIds.ImportFinished, new object[]
|
|
||||||
{
|
|
||||||
SessionId
|
|
||||||
});
|
|
||||||
}
|
|
||||||
public static void LogImportWarning(string SessionId, string Message)
|
|
||||||
{
|
|
||||||
DocumentsLog.Log(DocumentsLog.EventTypeIds.ImportWarning, new object[]
|
|
||||||
{
|
|
||||||
SessionId,
|
|
||||||
Message
|
|
||||||
});
|
|
||||||
}
|
|
||||||
public static void LogImportError(string SessionId, string Message)
|
|
||||||
{
|
|
||||||
DocumentsLog.Log(DocumentsLog.EventTypeIds.ImportError, new object[]
|
|
||||||
{
|
|
||||||
SessionId,
|
|
||||||
Message
|
|
||||||
});
|
|
||||||
}
|
|
||||||
public static void LogImportAttachmentExpressionEvaluated(DocumentTemplate template, Device device, DeviceAttachment attachment, string Result)
|
|
||||||
{
|
|
||||||
DocumentsLog.Log(DocumentsLog.EventTypeIds.ImportAttachmentExpressionEvaluated, new object[]
|
|
||||||
{
|
|
||||||
template.Id,
|
|
||||||
device.SerialNumber,
|
|
||||||
attachment.Id,
|
|
||||||
Result
|
|
||||||
});
|
|
||||||
}
|
|
||||||
public static void LogImportAttachmentExpressionEvaluated(DocumentTemplate template, Job job, JobAttachment attachment, string Result)
|
|
||||||
{
|
|
||||||
DocumentsLog.Log(DocumentsLog.EventTypeIds.ImportAttachmentExpressionEvaluated, new object[]
|
|
||||||
{
|
|
||||||
template.Id,
|
|
||||||
job.Id,
|
|
||||||
attachment.Id,
|
|
||||||
Result
|
|
||||||
});
|
|
||||||
}
|
|
||||||
public static void LogImportAttachmentExpressionEvaluated(DocumentTemplate template, User user, UserAttachment attachment, string Result)
|
|
||||||
{
|
|
||||||
DocumentsLog.Log(DocumentsLog.EventTypeIds.ImportAttachmentExpressionEvaluated, new object[]
|
|
||||||
{
|
|
||||||
template.Id,
|
|
||||||
user.UserId,
|
|
||||||
attachment.Id,
|
|
||||||
Result
|
|
||||||
});
|
|
||||||
}
|
|
||||||
public static void LogImportAttachmentExpressionEvaluated(DocumentTemplate Template, object Data, object Attachment, string Result)
|
|
||||||
{
|
|
||||||
if (Data is Job)
|
|
||||||
LogImportAttachmentExpressionEvaluated(Template, (Job)Data, (JobAttachment)Attachment, Result);
|
|
||||||
else if (Data is User)
|
|
||||||
LogImportAttachmentExpressionEvaluated(Template, (User)Data, (UserAttachment)Attachment, Result);
|
|
||||||
else if (Data is Device)
|
|
||||||
LogImportAttachmentExpressionEvaluated(Template, (Device)Data, (DeviceAttachment)Attachment, Result);
|
|
||||||
else
|
|
||||||
DocumentsLog.Log(DocumentsLog.EventTypeIds.ImportAttachmentExpressionEvaluated, new object[]
|
|
||||||
{
|
|
||||||
Template.Id,
|
|
||||||
Data.ToString(),
|
|
||||||
Attachment.ToString(),
|
|
||||||
Result
|
|
||||||
});
|
|
||||||
}
|
|
||||||
public static void LogImportPageStarting(string SessionId, int PageNumber)
|
|
||||||
{
|
|
||||||
DocumentsLog.Log(DocumentsLog.EventTypeIds.ImportPageStarting, new object[]
|
|
||||||
{
|
|
||||||
SessionId,
|
|
||||||
PageNumber
|
|
||||||
});
|
|
||||||
}
|
|
||||||
public static void LogImportPageImageUpdate(string SessionId, int PageNumber)
|
|
||||||
{
|
|
||||||
DocumentsLog.Log(DocumentsLog.EventTypeIds.ImportPageImageUpdate, new object[]
|
|
||||||
{
|
|
||||||
SessionId,
|
|
||||||
PageNumber
|
|
||||||
});
|
|
||||||
}
|
|
||||||
public static void LogImportPageProgress(string SessionId, int PageNumber, int? Progress, string Status)
|
|
||||||
{
|
|
||||||
DocumentsLog.Log(DocumentsLog.EventTypeIds.ImportPageProgress, new object[]
|
|
||||||
{
|
|
||||||
SessionId,
|
|
||||||
PageNumber,
|
|
||||||
Progress,
|
|
||||||
Status
|
|
||||||
});
|
|
||||||
}
|
|
||||||
public static void LogImportPageDetected(string SessionId, int PageNumber, string DocumentTypeId, string DocumentTypeName, string TargetType, string AssignedId, string AssignedName)
|
|
||||||
{
|
|
||||||
DocumentsLog.Log(DocumentsLog.EventTypeIds.ImportPageDetected, new object[]
|
|
||||||
{
|
|
||||||
SessionId,
|
|
||||||
PageNumber,
|
|
||||||
DocumentTypeId,
|
|
||||||
DocumentTypeName,
|
|
||||||
TargetType,
|
|
||||||
AssignedId,
|
|
||||||
AssignedName
|
|
||||||
});
|
|
||||||
}
|
|
||||||
public static void LogImportPageUndetected(string SessionId, int PageNumber)
|
|
||||||
{
|
|
||||||
DocumentsLog.Log(DocumentsLog.EventTypeIds.ImportPageUndetected, new object[]
|
|
||||||
{
|
|
||||||
SessionId,
|
|
||||||
PageNumber
|
|
||||||
});
|
|
||||||
}
|
|
||||||
public static void LogImportPageError(string SessionId, int PageNumber, string Message)
|
|
||||||
{
|
|
||||||
DocumentsLog.Log(DocumentsLog.EventTypeIds.ImportPageError, new object[]
|
|
||||||
{
|
|
||||||
SessionId,
|
|
||||||
PageNumber,
|
|
||||||
Message
|
|
||||||
});
|
|
||||||
}
|
|
||||||
public static void LogImportPageUndetectedStored(string SessionId, int PageNumber)
|
|
||||||
{
|
|
||||||
DocumentsLog.Log(DocumentsLog.EventTypeIds.ImportPageUndetectedStored, new object[]
|
|
||||||
{
|
|
||||||
SessionId,
|
|
||||||
PageNumber
|
|
||||||
});
|
|
||||||
}
|
|
||||||
public static void LogDocumentGenerated(DocumentTemplate Template, Device Device, User Author, string ExpressionResult)
|
|
||||||
{
|
|
||||||
DocumentsLog.Log(DocumentsLog.EventTypeIds.DocumentGeneratedWithExpression, new object[]
|
|
||||||
{
|
|
||||||
Template.Id,
|
|
||||||
Device.SerialNumber,
|
|
||||||
Author.UserId,
|
|
||||||
ExpressionResult
|
|
||||||
});
|
|
||||||
}
|
|
||||||
public static void LogDocumentGenerated(DocumentTemplate Template, Job Job, User Author, string ExpressionResult)
|
|
||||||
{
|
|
||||||
DocumentsLog.Log(DocumentsLog.EventTypeIds.DocumentGeneratedWithExpression, new object[]
|
|
||||||
{
|
|
||||||
Template.Id,
|
|
||||||
Job.Id,
|
|
||||||
Author.UserId,
|
|
||||||
ExpressionResult
|
|
||||||
});
|
|
||||||
}
|
|
||||||
public static void LogDocumentGenerated(DocumentTemplate Template, User User, User Author, string ExpressionResult)
|
|
||||||
{
|
|
||||||
DocumentsLog.Log(DocumentsLog.EventTypeIds.DocumentGeneratedWithExpression, new object[]
|
|
||||||
{
|
|
||||||
Template.Id,
|
|
||||||
User.UserId,
|
|
||||||
Author.UserId,
|
|
||||||
ExpressionResult
|
|
||||||
});
|
|
||||||
}
|
|
||||||
public static void LogDocumentGenerated(DocumentTemplate Template, object Data, User Author, string ExpressionResult)
|
|
||||||
{
|
|
||||||
if (Data is Job)
|
|
||||||
LogDocumentGenerated(Template, (Job)Data, Author, ExpressionResult);
|
|
||||||
else if (Data is User)
|
|
||||||
LogDocumentGenerated(Template, (User)Data, Author, ExpressionResult);
|
|
||||||
else if (Data is Device)
|
|
||||||
LogDocumentGenerated(Template, (Device)Data, Author, ExpressionResult);
|
|
||||||
else
|
|
||||||
DocumentsLog.Log(DocumentsLog.EventTypeIds.DocumentGeneratedWithExpression, new object[]
|
|
||||||
{
|
|
||||||
Template.Id,
|
|
||||||
"UNKNOWN",
|
|
||||||
Author.UserId,
|
|
||||||
ExpressionResult
|
|
||||||
});
|
|
||||||
}
|
|
||||||
public static void LogDocumentGenerated(DocumentTemplate Template, Device Device, User Author)
|
|
||||||
{
|
|
||||||
DocumentsLog.Log(DocumentsLog.EventTypeIds.DocumentGenerated, new object[]
|
|
||||||
{
|
|
||||||
Template.Id,
|
|
||||||
Device.SerialNumber,
|
|
||||||
Author.UserId
|
|
||||||
});
|
|
||||||
}
|
|
||||||
public static void LogDocumentGenerated(DocumentTemplate Template, Job Job, User Author)
|
|
||||||
{
|
|
||||||
DocumentsLog.Log(DocumentsLog.EventTypeIds.DocumentGenerated, new object[]
|
|
||||||
{
|
|
||||||
Template.Id,
|
|
||||||
Job.Id,
|
|
||||||
Author.UserId
|
|
||||||
});
|
|
||||||
}
|
|
||||||
public static void LogDocumentGenerated(DocumentTemplate Template, User User, User Author)
|
|
||||||
{
|
|
||||||
DocumentsLog.Log(DocumentsLog.EventTypeIds.DocumentGenerated, new object[]
|
|
||||||
{
|
|
||||||
Template.Id,
|
|
||||||
User.UserId,
|
|
||||||
Author.UserId
|
|
||||||
});
|
|
||||||
}
|
|
||||||
public static void LogDocumentGenerated(DocumentTemplate Template, object Data, User Author)
|
|
||||||
{
|
|
||||||
if (Data is Job)
|
|
||||||
LogDocumentGenerated(Template, (Job)Data, Author);
|
|
||||||
else if (Data is User)
|
|
||||||
LogDocumentGenerated(Template, (User)Data, Author);
|
|
||||||
else if (Data is Device)
|
|
||||||
LogDocumentGenerated(Template, (Device)Data, Author);
|
|
||||||
else
|
|
||||||
DocumentsLog.Log(DocumentsLog.EventTypeIds.DocumentGenerated, new object[]
|
|
||||||
{
|
|
||||||
Template.Id,
|
|
||||||
"UNKNOWN",
|
|
||||||
Author.UserId
|
|
||||||
});
|
|
||||||
}
|
|
||||||
protected override System.Collections.Generic.List<LogEventType> LoadEventTypes()
|
|
||||||
{
|
|
||||||
return new System.Collections.Generic.List<LogEventType>
|
|
||||||
{
|
|
||||||
new LogEventType
|
|
||||||
{
|
|
||||||
Id = (int)EventTypeIds.ImportStarting,
|
|
||||||
ModuleId = _ModuleId,
|
|
||||||
Name = "Import Starting",
|
|
||||||
Format = "Starting import of document: {1} (SessionId: {0})",
|
|
||||||
Severity = (int)LogEventType.Severities.Information,
|
|
||||||
UseLive = true,
|
|
||||||
UsePersist = true,
|
|
||||||
UseDisplay = true
|
|
||||||
},
|
|
||||||
new LogEventType
|
|
||||||
{
|
|
||||||
Id = (int)EventTypeIds.ImportProgress,
|
|
||||||
ModuleId = _ModuleId,
|
|
||||||
Name = "Import Progress",
|
|
||||||
Format = "Processing: {1}% Complete; Status: {2}",
|
|
||||||
Severity = (int)LogEventType.Severities.Information,
|
|
||||||
UseLive = true,
|
|
||||||
UsePersist = false,
|
|
||||||
UseDisplay = false
|
|
||||||
},
|
|
||||||
new LogEventType
|
|
||||||
{
|
|
||||||
Id = (int)EventTypeIds.ImportFinished,
|
|
||||||
ModuleId = _ModuleId,
|
|
||||||
Name = "Import Finished",
|
|
||||||
Format = "Import of document complete (SessionId: {0})",
|
|
||||||
Severity = (int)LogEventType.Severities.Information,
|
|
||||||
UseLive = true,
|
|
||||||
UsePersist = true,
|
|
||||||
UseDisplay = true
|
|
||||||
},
|
|
||||||
new LogEventType
|
|
||||||
{
|
|
||||||
Id = (int)EventTypeIds.ImportWarning,
|
|
||||||
ModuleId = _ModuleId,
|
|
||||||
Name = "Import Warning",
|
|
||||||
Format = "Import Warning: {1} (SessionId: {0})",
|
|
||||||
Severity = (int)LogEventType.Severities.Warning,
|
|
||||||
UseLive = true,
|
|
||||||
UsePersist = true,
|
|
||||||
UseDisplay = true
|
|
||||||
},
|
|
||||||
new LogEventType
|
|
||||||
{
|
|
||||||
Id = (int)EventTypeIds.ImportError,
|
|
||||||
ModuleId = _ModuleId,
|
|
||||||
Name = "Import Error",
|
|
||||||
Format = "Import Error: {1} (SessionId: {0})",
|
|
||||||
Severity = (int)LogEventType.Severities.Error,
|
|
||||||
UseLive = true,
|
|
||||||
UsePersist = true,
|
|
||||||
UseDisplay = true
|
|
||||||
},
|
|
||||||
new LogEventType
|
|
||||||
{
|
|
||||||
Id = (int)EventTypeIds.ImportAttachmentExpressionEvaluated,
|
|
||||||
ModuleId = _ModuleId,
|
|
||||||
Name = "Import Attachment Expression Evaluated",
|
|
||||||
Format = "The import attachment expression for '{0}' was evaluated for '{1}' (attachment id: {2}) with the result: {3}",
|
|
||||||
Severity = (int)LogEventType.Severities.Information,
|
|
||||||
UseLive = true,
|
|
||||||
UsePersist = true,
|
|
||||||
UseDisplay = true
|
|
||||||
},
|
|
||||||
new LogEventType
|
|
||||||
{
|
|
||||||
Id = (int)EventTypeIds.ImportPageStarting,
|
|
||||||
ModuleId = _ModuleId,
|
|
||||||
Name = "Import Page Starting",
|
|
||||||
Format = "Starting import of page: {1} (SessionId: {0})",
|
|
||||||
Severity = (int)LogEventType.Severities.Information,
|
|
||||||
UseLive = true,
|
|
||||||
UsePersist = true,
|
|
||||||
UseDisplay = true
|
|
||||||
},
|
|
||||||
new LogEventType
|
|
||||||
{
|
|
||||||
Id = (int)EventTypeIds.ImportPageImageUpdate,
|
|
||||||
ModuleId = _ModuleId,
|
|
||||||
Name = "Import Page Image Update",
|
|
||||||
Format = null,
|
|
||||||
Severity = (int)LogEventType.Severities.Information,
|
|
||||||
UseLive = true,
|
|
||||||
UsePersist = false,
|
|
||||||
UseDisplay = false
|
|
||||||
},
|
|
||||||
new LogEventType
|
|
||||||
{
|
|
||||||
Id = (int)EventTypeIds.ImportPageProgress,
|
|
||||||
ModuleId = _ModuleId,
|
|
||||||
Name = "Import Page Progress",
|
|
||||||
Format = "Processing: Page {1}; {2}% Complete; Status: {3}",
|
|
||||||
Severity = (int)LogEventType.Severities.Information,
|
|
||||||
UseLive = true,
|
|
||||||
UsePersist = false,
|
|
||||||
UseDisplay = false
|
|
||||||
},
|
|
||||||
new LogEventType
|
|
||||||
{
|
|
||||||
Id = (int)EventTypeIds.ImportPageDetected,
|
|
||||||
ModuleId = _ModuleId,
|
|
||||||
Name = "Import Page Assigned",
|
|
||||||
Format = "Page {1} of type '{3}' assigned to {4}: '{6}'",
|
|
||||||
Severity = (int)LogEventType.Severities.Information,
|
|
||||||
UseLive = true,
|
|
||||||
UsePersist = true,
|
|
||||||
UseDisplay = true
|
|
||||||
},
|
|
||||||
new LogEventType
|
|
||||||
{
|
|
||||||
Id = (int)EventTypeIds.ImportPageUndetected,
|
|
||||||
ModuleId = _ModuleId,
|
|
||||||
Name = "Import Page Undetected",
|
|
||||||
Format = "Page {1} not detected",
|
|
||||||
Severity = (int)LogEventType.Severities.Warning,
|
|
||||||
UseLive = true,
|
|
||||||
UsePersist = true,
|
|
||||||
UseDisplay = true
|
|
||||||
},
|
|
||||||
new LogEventType
|
|
||||||
{
|
|
||||||
Id = (int)EventTypeIds.ImportPageError,
|
|
||||||
ModuleId = _ModuleId,
|
|
||||||
Name = "Import Page Error",
|
|
||||||
Format = "Page {1}, Import Error: {2}",
|
|
||||||
Severity = (int)LogEventType.Severities.Error,
|
|
||||||
UseLive = true,
|
|
||||||
UsePersist = true,
|
|
||||||
UseDisplay = true
|
|
||||||
},
|
|
||||||
new LogEventType
|
|
||||||
{
|
|
||||||
Id = (int)EventTypeIds.ImportPageUndetectedStored,
|
|
||||||
ModuleId = _ModuleId,
|
|
||||||
Name = "Import Page Undetected Stored",
|
|
||||||
Format = null,
|
|
||||||
Severity = (int)LogEventType.Severities.Information,
|
|
||||||
UseLive = true,
|
|
||||||
UsePersist = false,
|
|
||||||
UseDisplay = false
|
|
||||||
},
|
|
||||||
new LogEventType
|
|
||||||
{
|
|
||||||
Id = (int)EventTypeIds.DocumentGenerated,
|
|
||||||
ModuleId = _ModuleId,
|
|
||||||
Name = "Document Generated",
|
|
||||||
Format = "A '{0}' document was generated for '{1}' by '{2}'",
|
|
||||||
Severity = (int)LogEventType.Severities.Information,
|
|
||||||
UseLive = true,
|
|
||||||
UsePersist = true,
|
|
||||||
UseDisplay = true
|
|
||||||
},
|
|
||||||
new LogEventType
|
|
||||||
{
|
|
||||||
Id = (int)EventTypeIds.DocumentGeneratedWithExpression,
|
|
||||||
ModuleId = _ModuleId,
|
|
||||||
Name = "Document Generated with Expression",
|
|
||||||
Format = "A '{0}' document was generated for '{1}' by '{2}'. The expression returned: {3}",
|
|
||||||
Severity = (int)LogEventType.Severities.Information,
|
|
||||||
UseLive = true,
|
|
||||||
UsePersist = true,
|
|
||||||
UseDisplay = true
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,85 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.IO;
|
|
||||||
using System.Web.Caching;
|
|
||||||
using Disco.Data.Repository;
|
|
||||||
using Quartz;
|
|
||||||
using Quartz.Impl;
|
|
||||||
using Quartz.Impl.Triggers;
|
|
||||||
|
|
||||||
namespace Disco.BI.DocumentTemplateBI.Importer
|
|
||||||
{
|
|
||||||
public class DocumentDropBoxMonitor : System.IDisposable
|
|
||||||
{
|
|
||||||
private IScheduler _scheduler;
|
|
||||||
private FileSystemWatcher _fsw;
|
|
||||||
private Cache _httpCache;
|
|
||||||
|
|
||||||
public const string WatcherFilter = "*.pdf";
|
|
||||||
public string DropBoxLocation { get; private set; }
|
|
||||||
|
|
||||||
public DocumentDropBoxMonitor(DiscoDataContext Database, ISchedulerFactory SchedulerFactory, Cache HttpCache)
|
|
||||||
{
|
|
||||||
if (Database == null)
|
|
||||||
throw new System.ArgumentNullException("Context");
|
|
||||||
|
|
||||||
this._httpCache = HttpCache;
|
|
||||||
|
|
||||||
var location = DataStore.CreateLocation(Database, "DocumentDropBox");
|
|
||||||
this.DropBoxLocation = location.EndsWith(@"\") ? location : string.Concat(location, @"\");
|
|
||||||
|
|
||||||
this._scheduler = SchedulerFactory.GetScheduler();
|
|
||||||
this._scheduler.Start();
|
|
||||||
}
|
|
||||||
public void ScheduleCurrentFiles(int Delay)
|
|
||||||
{
|
|
||||||
foreach (var filename in System.IO.Directory.GetFiles(this.DropBoxLocation, "*.pdf"))
|
|
||||||
{
|
|
||||||
this.ScheduleFile(filename, Delay);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
public void StartWatching()
|
|
||||||
{
|
|
||||||
if (this._fsw == null)
|
|
||||||
{
|
|
||||||
this._fsw = new FileSystemWatcher(this.DropBoxLocation, "*.pdf");
|
|
||||||
this._fsw.Created += new FileSystemEventHandler(this.FSW_Created);
|
|
||||||
}
|
|
||||||
this._fsw.EnableRaisingEvents = true;
|
|
||||||
}
|
|
||||||
public void StopWatching()
|
|
||||||
{
|
|
||||||
if (this._fsw != null)
|
|
||||||
{
|
|
||||||
this._fsw.EnableRaisingEvents = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
public void ScheduleFile(string Filename, int Delay)
|
|
||||||
{
|
|
||||||
System.Guid guid = System.Guid.NewGuid();
|
|
||||||
JobDetailImpl jd = new JobDetailImpl(guid.ToString(), typeof(DocumentImporterJob));
|
|
||||||
jd.JobDataMap.Add("Filename", Filename);
|
|
||||||
jd.JobDataMap.Add("RetryCount", 0);
|
|
||||||
jd.JobDataMap.Add("HttpCache", this._httpCache);
|
|
||||||
guid = System.Guid.NewGuid();
|
|
||||||
|
|
||||||
System.DateTimeOffset startTimeUtc = new System.DateTimeOffset(DateTime.Now.AddSeconds((double)Delay));
|
|
||||||
SimpleTriggerImpl trig = new SimpleTriggerImpl(guid.ToString(), startTimeUtc);
|
|
||||||
|
|
||||||
this._scheduler.ScheduleJob(jd, trig);
|
|
||||||
}
|
|
||||||
private void FSW_Created(object sender, FileSystemEventArgs e)
|
|
||||||
{
|
|
||||||
if ((e.ChangeType & WatcherChangeTypes.Deleted) != WatcherChangeTypes.Deleted)
|
|
||||||
this.ScheduleFile(e.FullPath, 5);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Dispose()
|
|
||||||
{
|
|
||||||
this.StopWatching();
|
|
||||||
if (this._fsw != null)
|
|
||||||
this._fsw.Dispose();
|
|
||||||
if (this._scheduler != null)
|
|
||||||
this._scheduler.Shutdown(false);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,123 +0,0 @@
|
|||||||
using Disco.Data.Repository;
|
|
||||||
using Exceptionless;
|
|
||||||
using Quartz;
|
|
||||||
using Quartz.Impl.Triggers;
|
|
||||||
using System;
|
|
||||||
using System.IO;
|
|
||||||
using System.Web.Caching;
|
|
||||||
|
|
||||||
namespace Disco.BI.DocumentTemplateBI.Importer
|
|
||||||
{
|
|
||||||
[PersistJobDataAfterExecution]
|
|
||||||
public class DocumentImporterJob : IJob
|
|
||||||
{
|
|
||||||
|
|
||||||
void IJob.Execute(IJobExecutionContext context)
|
|
||||||
{
|
|
||||||
string sessionId = context.JobDetail.JobDataMap["SessionId"] as string;
|
|
||||||
if (string.IsNullOrEmpty(sessionId))
|
|
||||||
{
|
|
||||||
sessionId = Guid.NewGuid().ToString();
|
|
||||||
context.JobDetail.JobDataMap["SessionId"] = sessionId;
|
|
||||||
}
|
|
||||||
|
|
||||||
string filename = context.JobDetail.JobDataMap["Filename"] as string;
|
|
||||||
int retryCount = (int)context.JobDetail.JobDataMap["RetryCount"];
|
|
||||||
Cache httpCache = context.JobDetail.JobDataMap["HttpCache"] as Cache;
|
|
||||||
|
|
||||||
var friendlyFilename = filename;
|
|
||||||
if (!string.IsNullOrEmpty(friendlyFilename))
|
|
||||||
friendlyFilename = System.IO.Path.GetFileName(friendlyFilename);
|
|
||||||
|
|
||||||
DocumentsLog.LogImportStarting(sessionId, friendlyFilename);
|
|
||||||
|
|
||||||
if (!File.Exists(filename))
|
|
||||||
{
|
|
||||||
DocumentsLog.LogImportWarning(sessionId, string.Format("File not found: {0}", filename));
|
|
||||||
DocumentsLog.LogImportFinished(sessionId);
|
|
||||||
context.Scheduler.DeleteJob(context.JobDetail.Key);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
using (DiscoDataContext database = new DiscoDataContext())
|
|
||||||
{
|
|
||||||
if (retryCount < 18)
|
|
||||||
{
|
|
||||||
context.JobDetail.JobDataMap["RetryCount"] = (++retryCount);
|
|
||||||
bool processResult = Interop.Pdf.PdfImporter.ProcessPdfAttachment(filename, database, sessionId, httpCache);
|
|
||||||
|
|
||||||
if (processResult)
|
|
||||||
{
|
|
||||||
// Import Successful - Delete
|
|
||||||
if (File.Exists(filename))
|
|
||||||
File.Delete(filename);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// Import Failed - Move to Errors Folder
|
|
||||||
if (File.Exists(filename))
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
string folderError = DataStore.CreateLocation(database, "DocumentDropBox_Errors");
|
|
||||||
string filenameError = Path.Combine(folderError, Path.GetFileName(filename));
|
|
||||||
int filenameErrorCount = 0;
|
|
||||||
while (File.Exists(filenameError))
|
|
||||||
{
|
|
||||||
filenameError = Path.Combine(folderError, string.Format("{0} ({1}){2}", Path.GetFileNameWithoutExtension(filename), ++filenameErrorCount, Path.GetExtension(filename)));
|
|
||||||
}
|
|
||||||
File.Move(filename, filenameError);
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
ex.ToExceptionless().Submit();
|
|
||||||
// Ignore Errors
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// To Many Errors
|
|
||||||
DocumentsLog.LogImportError(sessionId, string.Format("To many errors occurred trying to import '{1}' (SessionId: {0})", sessionId, friendlyFilename));
|
|
||||||
// Move to Errors Folder
|
|
||||||
if (File.Exists(filename))
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
string folderError = DataStore.CreateLocation(database, "DocumentDropBox_Errors");
|
|
||||||
string filenameError = Path.Combine(folderError, Path.GetFileName(filename));
|
|
||||||
int filenameErrorCount = 0;
|
|
||||||
while (File.Exists(filenameError))
|
|
||||||
{
|
|
||||||
filenameError = Path.Combine(folderError, string.Format("{0} ({1}){2}", Path.GetFileNameWithoutExtension(filename), ++filenameErrorCount, Path.GetExtension(filename)));
|
|
||||||
}
|
|
||||||
File.Move(filename, filenameError);
|
|
||||||
}
|
|
||||||
catch
|
|
||||||
{
|
|
||||||
// Ignore Errors
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
DocumentsLog.LogImportFinished(sessionId);
|
|
||||||
|
|
||||||
// All Done
|
|
||||||
context.Scheduler.DeleteJob(context.JobDetail.Key);
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
ex.ToExceptionless().Submit();
|
|
||||||
DocumentsLog.LogImportWarning(sessionId, string.Format("{0}; Will try again in 10 Seconds", ex.Message));
|
|
||||||
// Reschedule Job for 10 seconds
|
|
||||||
SimpleTriggerImpl trig = new SimpleTriggerImpl(Guid.NewGuid().ToString(), new DateTimeOffset(DateTime.Now.AddSeconds(10)));
|
|
||||||
context.Scheduler.RescheduleJob(context.Trigger.Key, trig);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,61 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Diagnostics;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Reflection;
|
|
||||||
using System.Runtime.CompilerServices;
|
|
||||||
|
|
||||||
namespace Disco.BI.Expressions
|
|
||||||
{
|
|
||||||
public class ExpressionTypeMemberDescriptor
|
|
||||||
{
|
|
||||||
public const string FunctionKind = "function";
|
|
||||||
public const string PropertyKind = "property";
|
|
||||||
public const string ParameterKind = "parameter";
|
|
||||||
|
|
||||||
public string Kind {get;set;}
|
|
||||||
public string Name {get;set;}
|
|
||||||
public string ReturnType {get;set;}
|
|
||||||
public string ReturnExpressionType{get;set;}
|
|
||||||
public List<ExpressionTypeMemberDescriptor> Parameters{get;set;}
|
|
||||||
|
|
||||||
public static ExpressionTypeMemberDescriptor Build(System.Reflection.MethodInfo m)
|
|
||||||
{
|
|
||||||
ExpressionTypeMemberDescriptor md = new ExpressionTypeMemberDescriptor
|
|
||||||
{
|
|
||||||
Kind = "function",
|
|
||||||
Name = m.Name,
|
|
||||||
ReturnType = m.ReturnType.Name,
|
|
||||||
ReturnExpressionType = m.ReturnType.AssemblyQualifiedName
|
|
||||||
};
|
|
||||||
md.Parameters = (
|
|
||||||
from mdp in m.GetParameters()
|
|
||||||
select ExpressionTypeMemberDescriptor.Build(mdp)).ToList<ExpressionTypeMemberDescriptor>();
|
|
||||||
return md;
|
|
||||||
}
|
|
||||||
public static ExpressionTypeMemberDescriptor Build(System.Reflection.PropertyInfo p)
|
|
||||||
{
|
|
||||||
ExpressionTypeMemberDescriptor md = new ExpressionTypeMemberDescriptor
|
|
||||||
{
|
|
||||||
Kind = "property",
|
|
||||||
Name = p.Name,
|
|
||||||
ReturnType = p.PropertyType.Name,
|
|
||||||
ReturnExpressionType = p.PropertyType.AssemblyQualifiedName
|
|
||||||
};
|
|
||||||
md.Parameters = (
|
|
||||||
from mdp in p.GetIndexParameters()
|
|
||||||
select ExpressionTypeMemberDescriptor.Build(mdp)).ToList<ExpressionTypeMemberDescriptor>();
|
|
||||||
return md;
|
|
||||||
}
|
|
||||||
public static ExpressionTypeMemberDescriptor Build(System.Reflection.ParameterInfo pi)
|
|
||||||
{
|
|
||||||
return new ExpressionTypeMemberDescriptor
|
|
||||||
{
|
|
||||||
Kind = "parameter",
|
|
||||||
Name = pi.Name,
|
|
||||||
ReturnType = pi.ParameterType.Name,
|
|
||||||
ReturnExpressionType = pi.ParameterType.AssemblyQualifiedName
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -7,6 +7,7 @@ using Disco.Data.Repository;
|
|||||||
using Disco.Services.Users;
|
using Disco.Services.Users;
|
||||||
using Disco.Services.Authorization;
|
using Disco.Services.Authorization;
|
||||||
using Disco.BI.DocumentTemplateBI.ManagedGroups;
|
using Disco.BI.DocumentTemplateBI.ManagedGroups;
|
||||||
|
using Disco.Services;
|
||||||
|
|
||||||
namespace Disco.BI.Extensions
|
namespace Disco.BI.Extensions
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,209 +0,0 @@
|
|||||||
using Disco.BI.DocumentTemplateBI;
|
|
||||||
using Disco.Data.Repository;
|
|
||||||
using Disco.Models.Repository;
|
|
||||||
using Disco.Services.Logging;
|
|
||||||
using Disco.Services.Users;
|
|
||||||
using Exceptionless;
|
|
||||||
using System;
|
|
||||||
using System.IO;
|
|
||||||
|
|
||||||
namespace Disco.BI.Extensions
|
|
||||||
{
|
|
||||||
public static class AttachmentExtensions
|
|
||||||
{
|
|
||||||
|
|
||||||
public static bool ImportPdfAttachment(this DocumentUniqueIdentifier UniqueIdentifier, DiscoDataContext Database, System.IO.Stream PdfContent, byte[] PdfThumbnail)
|
|
||||||
{
|
|
||||||
UniqueIdentifier.LoadComponents(Database);
|
|
||||||
DocumentTemplate documentTemplate = UniqueIdentifier.DocumentTemplate;
|
|
||||||
string filename;
|
|
||||||
string comments;
|
|
||||||
object attachment;
|
|
||||||
|
|
||||||
if (documentTemplate == null)
|
|
||||||
{
|
|
||||||
filename = string.Format("{0}_{1:yyyyMMdd-HHmmss}.pdf", UniqueIdentifier.DataId.Replace('\\', '_'), UniqueIdentifier.TimeStamp);
|
|
||||||
comments = string.Format("Uploaded: {0:s}", UniqueIdentifier.TimeStamp);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
filename = string.Format("{0}_{1:yyyyMMdd-HHmmss}.pdf", UniqueIdentifier.TemplateTypeId, UniqueIdentifier.TimeStamp);
|
|
||||||
comments = string.Format("Generated: {0:s}", UniqueIdentifier.TimeStamp);
|
|
||||||
}
|
|
||||||
|
|
||||||
User creatorUser = UserService.GetUser(UniqueIdentifier.CreatorId, Database);
|
|
||||||
if (creatorUser == null)
|
|
||||||
{
|
|
||||||
// No Creator User (or Username invalid)
|
|
||||||
creatorUser = UserService.CurrentUser;
|
|
||||||
}
|
|
||||||
switch (UniqueIdentifier.DataScope)
|
|
||||||
{
|
|
||||||
case DocumentTemplate.DocumentTemplateScopes.Device:
|
|
||||||
Device d = (Device)UniqueIdentifier.Data;
|
|
||||||
attachment = d.CreateAttachment(Database, creatorUser, filename, DocumentTemplate.PdfMimeType, comments, PdfContent, documentTemplate, PdfThumbnail);
|
|
||||||
break;
|
|
||||||
case DocumentTemplate.DocumentTemplateScopes.Job:
|
|
||||||
Job j = (Job)UniqueIdentifier.Data;
|
|
||||||
attachment = j.CreateAttachment(Database, creatorUser, filename, DocumentTemplate.PdfMimeType, comments, PdfContent, documentTemplate, PdfThumbnail);
|
|
||||||
break;
|
|
||||||
case DocumentTemplate.DocumentTemplateScopes.User:
|
|
||||||
User u = (User)UniqueIdentifier.Data;
|
|
||||||
attachment = u.CreateAttachment(Database, creatorUser, filename, DocumentTemplate.PdfMimeType, comments, PdfContent, documentTemplate, PdfThumbnail);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (documentTemplate != null && !string.IsNullOrWhiteSpace(documentTemplate.OnImportAttachmentExpression))
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
var expressionResult = documentTemplate.EvaluateOnAttachmentImportExpression(attachment, Database, creatorUser, UniqueIdentifier.TimeStamp);
|
|
||||||
DocumentsLog.LogImportAttachmentExpressionEvaluated(documentTemplate, UniqueIdentifier.Data, attachment, expressionResult);
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
SystemLog.LogException("Document Importer - OnImportAttachmentExpression", ex);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static string RepositoryFilename(this DeviceAttachment da, DiscoDataContext Database)
|
|
||||||
{
|
|
||||||
return Path.Combine(DataStore.CreateLocation(Database, "DeviceAttachments", da.Timestamp), string.Format("{0}_{1}_file", da.DeviceSerialNumber, da.Id));
|
|
||||||
}
|
|
||||||
public static string RepositoryFilename(this JobAttachment ja, DiscoDataContext Database)
|
|
||||||
{
|
|
||||||
return Path.Combine(DataStore.CreateLocation(Database, "JobAttachments", ja.Timestamp), string.Format("{0}_{1}_file", ja.JobId, ja.Id));
|
|
||||||
}
|
|
||||||
public static string RepositoryFilename(this UserAttachment ua, DiscoDataContext Database)
|
|
||||||
{
|
|
||||||
return Path.Combine(DataStore.CreateLocation(Database, "UserAttachments", ua.Timestamp), string.Format("{0}_{1}_file", ua.UserId.Replace('\\', '_'), ua.Id));
|
|
||||||
}
|
|
||||||
|
|
||||||
private static string RepositoryThumbnailFilenameInternal(string DirectoryPath, string Filename)
|
|
||||||
{
|
|
||||||
return Path.Combine(DirectoryPath, Filename);
|
|
||||||
}
|
|
||||||
public static string RepositoryThumbnailFilename(this DeviceAttachment da, DiscoDataContext Database)
|
|
||||||
{
|
|
||||||
return RepositoryThumbnailFilenameInternal(DataStore.CreateLocation(Database, "DeviceAttachments", da.Timestamp), string.Format("{0}_{1}_thumb.jpg", da.DeviceSerialNumber, da.Id));
|
|
||||||
}
|
|
||||||
public static string RepositoryThumbnailFilename(this JobAttachment ja, DiscoDataContext Database)
|
|
||||||
{
|
|
||||||
return RepositoryThumbnailFilenameInternal(DataStore.CreateLocation(Database, "JobAttachments", ja.Timestamp), string.Format("{0}_{1}_thumb.jpg", ja.JobId, ja.Id));
|
|
||||||
}
|
|
||||||
public static string RepositoryThumbnailFilename(this UserAttachment ua, DiscoDataContext Database)
|
|
||||||
{
|
|
||||||
return RepositoryThumbnailFilenameInternal(DataStore.CreateLocation(Database, "UserAttachments", ua.Timestamp), string.Format("{0}_{1}_thumb.jpg", ua.UserId.Replace('\\', '_'), ua.Id));
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void RepositoryDelete(this DeviceAttachment da, DiscoDataContext Database)
|
|
||||||
{
|
|
||||||
RepositoryDelete(da.RepositoryFilename(Database), da.RepositoryThumbnailFilename(Database));
|
|
||||||
}
|
|
||||||
public static void RepositoryDelete(this JobAttachment ja, DiscoDataContext Database)
|
|
||||||
{
|
|
||||||
RepositoryDelete(ja.RepositoryFilename(Database), ja.RepositoryThumbnailFilename(Database));
|
|
||||||
}
|
|
||||||
public static void RepositoryDelete(this UserAttachment ua, DiscoDataContext Database)
|
|
||||||
{
|
|
||||||
RepositoryDelete(ua.RepositoryFilename(Database), ua.RepositoryThumbnailFilename(Database));
|
|
||||||
}
|
|
||||||
private static void RepositoryDelete(params string[] filePaths)
|
|
||||||
{
|
|
||||||
foreach (string filePath in filePaths)
|
|
||||||
{
|
|
||||||
if (File.Exists(filePath))
|
|
||||||
File.Delete(filePath);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static string SaveAttachment(this DeviceAttachment da, DiscoDataContext Database, Stream FileContent)
|
|
||||||
{
|
|
||||||
string filePath = da.RepositoryFilename(Database);
|
|
||||||
SaveAttachment(filePath, FileContent);
|
|
||||||
return filePath;
|
|
||||||
}
|
|
||||||
public static string SaveAttachment(this JobAttachment ja, DiscoDataContext Database, Stream FileContent)
|
|
||||||
{
|
|
||||||
string filePath = ja.RepositoryFilename(Database);
|
|
||||||
SaveAttachment(filePath, FileContent);
|
|
||||||
return filePath;
|
|
||||||
}
|
|
||||||
public static string SaveAttachment(this UserAttachment ua, DiscoDataContext Database, Stream FileContent)
|
|
||||||
{
|
|
||||||
string filePath = ua.RepositoryFilename(Database);
|
|
||||||
SaveAttachment(filePath, FileContent);
|
|
||||||
return filePath;
|
|
||||||
}
|
|
||||||
public static string SaveThumbnailAttachment(this DeviceAttachment da, DiscoDataContext Database, byte[] FileContent)
|
|
||||||
{
|
|
||||||
string filePath = da.RepositoryThumbnailFilename(Database);
|
|
||||||
File.WriteAllBytes(filePath, FileContent);
|
|
||||||
return filePath;
|
|
||||||
}
|
|
||||||
public static string SaveThumbnailAttachment(this JobAttachment ja, DiscoDataContext Database, byte[] FileContent)
|
|
||||||
{
|
|
||||||
string filePath = ja.RepositoryThumbnailFilename(Database);
|
|
||||||
File.WriteAllBytes(filePath, FileContent);
|
|
||||||
return filePath;
|
|
||||||
}
|
|
||||||
public static string SaveThumbnailAttachment(this UserAttachment ua, DiscoDataContext Database, byte[] FileContent)
|
|
||||||
{
|
|
||||||
string filePath = ua.RepositoryThumbnailFilename(Database);
|
|
||||||
File.WriteAllBytes(filePath, FileContent);
|
|
||||||
return filePath;
|
|
||||||
}
|
|
||||||
private static void SaveAttachment(string FilePath, Stream FileContent)
|
|
||||||
{
|
|
||||||
using (FileStream sw = new FileStream(FilePath, FileMode.Create, FileAccess.Write, FileShare.None))
|
|
||||||
{
|
|
||||||
FileContent.CopyTo(sw);
|
|
||||||
sw.Flush();
|
|
||||||
sw.Close();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static string GenerateThumbnail(this DeviceAttachment da, DiscoDataContext Database)
|
|
||||||
{
|
|
||||||
string filePath = da.RepositoryThumbnailFilename(Database);
|
|
||||||
AttachmentBI.Utilities.GenerateThumbnail(da.RepositoryFilename(Database), da.MimeType, filePath);
|
|
||||||
return filePath;
|
|
||||||
}
|
|
||||||
public static string GenerateThumbnail(this JobAttachment ja, DiscoDataContext Database)
|
|
||||||
{
|
|
||||||
string filePath = ja.RepositoryThumbnailFilename(Database);
|
|
||||||
AttachmentBI.Utilities.GenerateThumbnail(ja.RepositoryFilename(Database), ja.MimeType, filePath);
|
|
||||||
return filePath;
|
|
||||||
}
|
|
||||||
public static string GenerateThumbnail(this UserAttachment ua, DiscoDataContext Database)
|
|
||||||
{
|
|
||||||
string filePath = ua.RepositoryThumbnailFilename(Database);
|
|
||||||
AttachmentBI.Utilities.GenerateThumbnail(ua.RepositoryFilename(Database), ua.MimeType, filePath);
|
|
||||||
return filePath;
|
|
||||||
}
|
|
||||||
public static string GenerateThumbnail(this DeviceAttachment da, DiscoDataContext Database, Stream SourceFile)
|
|
||||||
{
|
|
||||||
string filePath = da.RepositoryThumbnailFilename(Database);
|
|
||||||
AttachmentBI.Utilities.GenerateThumbnail(SourceFile, da.MimeType, filePath);
|
|
||||||
return filePath;
|
|
||||||
}
|
|
||||||
public static string GenerateThumbnail(this JobAttachment ja, DiscoDataContext Database, Stream SourceFile)
|
|
||||||
{
|
|
||||||
string filePath = ja.RepositoryThumbnailFilename(Database);
|
|
||||||
AttachmentBI.Utilities.GenerateThumbnail(SourceFile, ja.MimeType, filePath);
|
|
||||||
return filePath;
|
|
||||||
}
|
|
||||||
public static string GenerateThumbnail(this UserAttachment ua, DiscoDataContext Database, Stream SourceFile)
|
|
||||||
{
|
|
||||||
string filePath = ua.RepositoryThumbnailFilename(Database);
|
|
||||||
AttachmentBI.Utilities.GenerateThumbnail(SourceFile, ua.MimeType, filePath);
|
|
||||||
return filePath;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,5 +1,6 @@
|
|||||||
using Disco.Data.Repository;
|
using Disco.Data.Repository;
|
||||||
using Disco.Models.Repository;
|
using Disco.Models.Repository;
|
||||||
|
using Disco.Services;
|
||||||
using Disco.Services.Authorization;
|
using Disco.Services.Authorization;
|
||||||
using Disco.Services.Interop.ActiveDirectory;
|
using Disco.Services.Interop.ActiveDirectory;
|
||||||
using Disco.Services.Users;
|
using Disco.Services.Users;
|
||||||
|
|||||||
@@ -1,15 +1,16 @@
|
|||||||
using System.Linq;
|
|
||||||
using Disco.Data.Configuration;
|
|
||||||
using Disco.Data.Repository;
|
using Disco.Data.Repository;
|
||||||
using Disco.Models.BI.DocumentTemplates;
|
|
||||||
using Disco.Models.Repository;
|
using Disco.Models.Repository;
|
||||||
using System.Collections.Generic;
|
using Disco.Models.Services.Documents;
|
||||||
using System;
|
using Disco.Services;
|
||||||
using System.IO;
|
|
||||||
using Disco.Services.Users;
|
|
||||||
using Disco.Services.Authorization;
|
using Disco.Services.Authorization;
|
||||||
|
using Disco.Services.Expressions;
|
||||||
using Disco.Services.Interop.ActiveDirectory;
|
using Disco.Services.Interop.ActiveDirectory;
|
||||||
|
using Disco.Services.Users;
|
||||||
using Exceptionless;
|
using Exceptionless;
|
||||||
|
using System;
|
||||||
|
using System.Collections;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
|
||||||
namespace Disco.BI.Extensions
|
namespace Disco.BI.Extensions
|
||||||
{
|
{
|
||||||
@@ -21,15 +22,15 @@ namespace Disco.BI.Extensions
|
|||||||
if (Domain == null)
|
if (Domain == null)
|
||||||
throw new ArgumentNullException("Domain");
|
throw new ArgumentNullException("Domain");
|
||||||
|
|
||||||
DeviceProfile deviceProfile = device.DeviceProfile;
|
var deviceProfile = device.DeviceProfile;
|
||||||
Expressions.Expression computerNameTemplateExpression = null;
|
Expression computerNameTemplateExpression = null;
|
||||||
computerNameTemplateExpression = Expressions.ExpressionCache.GetValue(DeviceProfileExtensions.ComputerNameExpressionCacheModule, deviceProfile.Id.ToString(), () =>
|
computerNameTemplateExpression = ExpressionCache.GetValue(DeviceProfileExtensions.ComputerNameExpressionCacheModule, deviceProfile.Id.ToString(), () =>
|
||||||
{
|
{
|
||||||
// Removed 2012-06-14 G# - Properties moved to DeviceProfile model & DB Migrated in DBv3.
|
// Removed 2012-06-14 G# - Properties moved to DeviceProfile model & DB Migrated in DBv3.
|
||||||
//return Expressions.Expression.TokenizeSingleDynamic(null, deviceProfile.Configuration(context).ComputerNameTemplate, 0);
|
//return Expressions.Expression.TokenizeSingleDynamic(null, deviceProfile.Configuration(context).ComputerNameTemplate, 0);
|
||||||
return Expressions.Expression.TokenizeSingleDynamic(null, deviceProfile.ComputerNameTemplate, 0);
|
return Expression.TokenizeSingleDynamic(null, deviceProfile.ComputerNameTemplate, 0);
|
||||||
});
|
});
|
||||||
System.Collections.IDictionary evaluatorVariables = Expressions.Expression.StandardVariables(null, Database, UserService.CurrentUser, System.DateTime.Now, null);
|
var evaluatorVariables = Expression.StandardVariables(null, Database, UserService.CurrentUser, DateTime.Now, null);
|
||||||
string rendered;
|
string rendered;
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
@@ -42,53 +43,22 @@ namespace Disco.BI.Extensions
|
|||||||
}
|
}
|
||||||
if (rendered == null || rendered.Length > 24)
|
if (rendered == null || rendered.Length > 24)
|
||||||
{
|
{
|
||||||
throw new System.InvalidOperationException("The rendered computer name would be invalid or longer than 24 characters");
|
throw new InvalidOperationException("The rendered computer name would be invalid or longer than 24 characters");
|
||||||
}
|
}
|
||||||
|
|
||||||
return string.Format(@"{0}\{1}", Domain.NetBiosName, rendered);
|
return string.Format(@"{0}\{1}", Domain.NetBiosName, rendered);
|
||||||
}
|
}
|
||||||
public static System.Collections.Generic.List<DocumentTemplate> AvailableDocumentTemplates(this Device d, DiscoDataContext Database, User User, System.DateTime TimeStamp)
|
public static List<DocumentTemplate> AvailableDocumentTemplates(this Device d, DiscoDataContext Database, User User, DateTime TimeStamp)
|
||||||
{
|
{
|
||||||
List<DocumentTemplate> ats = Database.DocumentTemplates
|
List<DocumentTemplate> ats = Database.DocumentTemplates
|
||||||
.Where(at => at.Scope == Disco.Models.Repository.DocumentTemplate.DocumentTemplateScopes.Device).ToList();
|
.Where(at => at.Scope == DocumentTemplate.DocumentTemplateScopes.Device).ToList();
|
||||||
|
|
||||||
return ats.Where(at => at.FilterExpressionMatches(d, Database, User, TimeStamp, DocumentState.DefaultState())).ToList();
|
return ats.Where(at => at.FilterExpressionMatches(d, Database, User, TimeStamp, DocumentState.DefaultState())).ToList();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static bool UpdateLastNetworkLogonDate(this Device Device)
|
public static bool UpdateLastNetworkLogonDate(this Device Device)
|
||||||
{
|
{
|
||||||
return Disco.Services.Interop.ActiveDirectory.ADNetworkLogonDatesUpdateTask.UpdateLastNetworkLogonDate(Device);
|
return ADNetworkLogonDatesUpdateTask.UpdateLastNetworkLogonDate(Device);
|
||||||
}
|
|
||||||
|
|
||||||
public static DeviceAttachment CreateAttachment(this Device Device, DiscoDataContext Database, User CreatorUser, string Filename, string MimeType, string Comments, Stream Content, DocumentTemplate DocumentTemplate = null, byte[] PdfThumbnail = 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 = DateTime.Now,
|
|
||||||
Comments = Comments
|
|
||||||
};
|
|
||||||
|
|
||||||
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 Device AddOffline(this Device d, DiscoDataContext Database)
|
public static Device AddOffline(this Device d, DiscoDataContext Database)
|
||||||
@@ -189,15 +159,7 @@ namespace Disco.BI.Extensions
|
|||||||
return newDua;
|
return newDua;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static ADMachineAccount ActiveDirectoryAccount(this Device Device, params string[] AdditionalProperties)
|
public static string ReasonMessage(this DecommissionReasons r)
|
||||||
{
|
|
||||||
if (ActiveDirectory.IsValidDomainAccountId(Device.DeviceDomainId))
|
|
||||||
return ActiveDirectory.RetrieveADMachineAccount(Device.DeviceDomainId, AdditionalProperties: AdditionalProperties);
|
|
||||||
else
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static string ReasonMessage(this Disco.Models.Repository.DecommissionReasons r)
|
|
||||||
{
|
{
|
||||||
switch (r)
|
switch (r)
|
||||||
{
|
{
|
||||||
@@ -220,7 +182,7 @@ namespace Disco.BI.Extensions
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static string ReasonMessage(this Disco.Models.Repository.DecommissionReasons? r)
|
public static string ReasonMessage(this DecommissionReasons? r)
|
||||||
{
|
{
|
||||||
if (!r.HasValue)
|
if (!r.HasValue)
|
||||||
return "Not Decommissioned";
|
return "Not Decommissioned";
|
||||||
|
|||||||
@@ -1,79 +1,16 @@
|
|||||||
using System;
|
using Disco.Data.Repository;
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
|
||||||
using Disco.Models.Repository;
|
using Disco.Models.Repository;
|
||||||
using System.IO;
|
using Disco.Services;
|
||||||
using System.Drawing;
|
|
||||||
using Disco.Data.Repository;
|
|
||||||
using Disco.Services.Users;
|
|
||||||
using Disco.Services.Authorization;
|
using Disco.Services.Authorization;
|
||||||
|
using Disco.Services.Users;
|
||||||
|
using System;
|
||||||
|
using System.IO;
|
||||||
|
using System.Linq;
|
||||||
|
|
||||||
namespace Disco.BI.Extensions
|
namespace Disco.BI.Extensions
|
||||||
{
|
{
|
||||||
public static class DeviceModelExtensions
|
public static class DeviceModelExtensions
|
||||||
{
|
{
|
||||||
public static bool ImageImport(this DeviceModel deviceModel, Stream ImageStream)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
using (Bitmap inputBitmap = new Bitmap(ImageStream))
|
|
||||||
{
|
|
||||||
using (Image outputBitmap = inputBitmap.ResizeImage(256, 256))
|
|
||||||
{
|
|
||||||
using (MemoryStream ms = new MemoryStream())
|
|
||||||
{
|
|
||||||
outputBitmap.SavePng(ms);
|
|
||||||
ms.Position = 0;
|
|
||||||
|
|
||||||
var deviceModelImagePath = deviceModel.ImageFilePath();
|
|
||||||
|
|
||||||
|
|
||||||
using (var storeStream = new FileStream(deviceModelImagePath, FileMode.Create, FileAccess.Write, FileShare.None))
|
|
||||||
{
|
|
||||||
ms.CopyTo(storeStream);
|
|
||||||
}
|
|
||||||
//deviceModel.Image = ms.ToArray();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
catch (Exception)
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static FileStream Image(this DeviceModel deviceModel)
|
|
||||||
{
|
|
||||||
var deviceModelImagePath = deviceModel.ImageFilePath();
|
|
||||||
|
|
||||||
if (File.Exists(deviceModelImagePath))
|
|
||||||
return new FileStream(deviceModelImagePath, FileMode.Open, FileAccess.Read, FileShare.Read);
|
|
||||||
else
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static string ImageFilePath(this DeviceModel deviceModel)
|
|
||||||
{
|
|
||||||
var configCache = new Disco.Data.Configuration.SystemConfiguration(null);
|
|
||||||
|
|
||||||
var deviceModelImagesDataStore = DataStore.CreateLocation(configCache, "DeviceModelImages");
|
|
||||||
|
|
||||||
return Path.Combine(deviceModelImagesDataStore, string.Format("{0}.png", deviceModel.Id));
|
|
||||||
}
|
|
||||||
|
|
||||||
public static string ImageHash(this DeviceModel deviceModel)
|
|
||||||
{
|
|
||||||
var deviceModelImagePath = deviceModel.ImageFilePath();
|
|
||||||
|
|
||||||
if (File.Exists(deviceModelImagePath))
|
|
||||||
return File.GetLastWriteTimeUtc(deviceModelImagePath).ToBinary().ToString();
|
|
||||||
else
|
|
||||||
return "-1";
|
|
||||||
}
|
|
||||||
|
|
||||||
#region Actions
|
#region Actions
|
||||||
public static bool CanDelete(this DeviceModel dm, DiscoDataContext Database)
|
public static bool CanDelete(this DeviceModel dm, DiscoDataContext Database)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ using Disco.Models.BI.Config;
|
|||||||
using Disco.Models.Repository;
|
using Disco.Models.Repository;
|
||||||
using Disco.Services.Authorization;
|
using Disco.Services.Authorization;
|
||||||
using Disco.Services.Devices.ManagedGroups;
|
using Disco.Services.Devices.ManagedGroups;
|
||||||
|
using Disco.Services.Expressions;
|
||||||
using Disco.Services.Interop.ActiveDirectory;
|
using Disco.Services.Interop.ActiveDirectory;
|
||||||
using Disco.Services.Users;
|
using Disco.Services.Users;
|
||||||
using System;
|
using System;
|
||||||
@@ -16,7 +17,7 @@ namespace Disco.BI.Extensions
|
|||||||
|
|
||||||
public static void ComputerNameInvalidateCache(this DeviceProfile deviceProfile)
|
public static void ComputerNameInvalidateCache(this DeviceProfile deviceProfile)
|
||||||
{
|
{
|
||||||
Expressions.ExpressionCache.InvalidateKey(ComputerNameExpressionCacheModule, deviceProfile.Id.ToString());
|
ExpressionCache.InvalidateKey(ComputerNameExpressionCacheModule, deviceProfile.Id.ToString());
|
||||||
}
|
}
|
||||||
|
|
||||||
public static OrganisationAddress DefaultOrganisationAddressDetails(this DeviceProfile deviceProfile, DiscoDataContext Database)
|
public static OrganisationAddress DefaultOrganisationAddressDetails(this DeviceProfile deviceProfile, DiscoDataContext Database)
|
||||||
|
|||||||
@@ -1,48 +1,27 @@
|
|||||||
using Disco.BI.DocumentTemplateBI;
|
|
||||||
using Disco.BI.DocumentTemplateBI.ManagedGroups;
|
using Disco.BI.DocumentTemplateBI.ManagedGroups;
|
||||||
using Disco.BI.Expressions;
|
|
||||||
using Disco.Data.Repository;
|
using Disco.Data.Repository;
|
||||||
using Disco.Models.BI.DocumentTemplates;
|
|
||||||
using Disco.Models.Repository;
|
using Disco.Models.Repository;
|
||||||
|
using Disco.Models.Services.Documents;
|
||||||
|
using Disco.Services;
|
||||||
|
using Disco.Services.Documents;
|
||||||
|
using Disco.Services.Expressions;
|
||||||
using Disco.Services.Interop.ActiveDirectory;
|
using Disco.Services.Interop.ActiveDirectory;
|
||||||
using iTextSharp.text.pdf;
|
using iTextSharp.text.pdf;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Concurrent;
|
using System.Collections.Concurrent;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Drawing;
|
|
||||||
using System.IO;
|
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
|
||||||
namespace Disco.BI.Extensions
|
namespace Disco.BI.Extensions
|
||||||
{
|
{
|
||||||
public static class DocumentTemplateExtensions
|
public static class DocumentTemplateExtensions
|
||||||
{
|
{
|
||||||
private const string DocumentTemplateExpressionCacheTemplate = "DocumentTemplate_{0}";
|
internal const string CacheTemplate = "DocumentTemplate_{0}";
|
||||||
|
|
||||||
public static string RepositoryFilename(this DocumentTemplate dt, DiscoDataContext Database)
|
|
||||||
{
|
|
||||||
return System.IO.Path.Combine(DataStore.CreateLocation(Database, "DocumentTemplates"), string.Format("{0}.pdf", dt.Id));
|
|
||||||
}
|
|
||||||
public static string SavePdfTemplate(this DocumentTemplate dt, DiscoDataContext Database, Stream TemplateFile)
|
|
||||||
{
|
|
||||||
string filePath = dt.RepositoryFilename(Database);
|
|
||||||
using (FileStream fs = new FileStream(filePath, FileMode.Create, FileAccess.Write))
|
|
||||||
{
|
|
||||||
TemplateFile.CopyTo(fs);
|
|
||||||
}
|
|
||||||
Expressions.ExpressionCache.InvalidModule(string.Format(DocumentTemplateExpressionCacheTemplate, dt.Id));
|
|
||||||
return filePath;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static DisposableImageCollection PdfPageImages(this PdfReader pdfReader, int PageNumber)
|
|
||||||
{
|
|
||||||
return Interop.Pdf.PdfImporter.GetPageImages(pdfReader, PageNumber);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static ConcurrentDictionary<string, Expression> PdfExpressionsFromCache(this DocumentTemplate dt, DiscoDataContext Database)
|
public static ConcurrentDictionary<string, Expression> PdfExpressionsFromCache(this DocumentTemplate dt, DiscoDataContext Database)
|
||||||
{
|
{
|
||||||
string cacheModuleKey = string.Format(DocumentTemplateExpressionCacheTemplate, dt.Id);
|
string cacheModuleKey = string.Format(CacheTemplate, dt.Id);
|
||||||
var module = Expressions.ExpressionCache.GetModule(cacheModuleKey);
|
var module = ExpressionCache.GetModule(cacheModuleKey);
|
||||||
if (module == null)
|
if (module == null)
|
||||||
{
|
{
|
||||||
// Cache
|
// Cache
|
||||||
@@ -52,199 +31,46 @@ namespace Disco.BI.Extensions
|
|||||||
foreach (string pdfFieldKey in pdfReader.AcroFields.Fields.Keys)
|
foreach (string pdfFieldKey in pdfReader.AcroFields.Fields.Keys)
|
||||||
{
|
{
|
||||||
var pdfFieldValue = pdfReader.AcroFields.GetField(pdfFieldKey);
|
var pdfFieldValue = pdfReader.AcroFields.GetField(pdfFieldKey);
|
||||||
Expressions.ExpressionCache.SetValue(cacheModuleKey, pdfFieldKey, Expressions.Expression.Tokenize(pdfFieldKey, pdfFieldValue, pdfFieldOrdinal));
|
ExpressionCache.SetValue(cacheModuleKey, pdfFieldKey, Expression.Tokenize(pdfFieldKey, pdfFieldValue, pdfFieldOrdinal));
|
||||||
pdfFieldOrdinal++;
|
pdfFieldOrdinal++;
|
||||||
}
|
}
|
||||||
pdfReader.Close();
|
pdfReader.Close();
|
||||||
module = Expressions.ExpressionCache.GetModule(cacheModuleKey, true);
|
module = ExpressionCache.GetModule(cacheModuleKey, true);
|
||||||
}
|
}
|
||||||
return module;
|
return module;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static List<BI.Expressions.Expression> ExtractPdfExpressions(this DocumentTemplate dt, DiscoDataContext Database)
|
public static List<Expression> ExtractPdfExpressions(this DocumentTemplate dt, DiscoDataContext Database)
|
||||||
{
|
{
|
||||||
return dt.PdfExpressionsFromCache(Database).Values.OrderBy(e => e.Ordinal).ToList();
|
return dt.PdfExpressionsFromCache(Database).Values.OrderBy(e => e.Ordinal).ToList();
|
||||||
}
|
}
|
||||||
public static System.IO.Stream GeneratePdfBulk(this DocumentTemplate dt, DiscoDataContext Database, User CreatorUser, System.DateTime Timestamp, params string[] DataObjectsIds)
|
|
||||||
|
public static System.IO.Stream GeneratePdfBulk(this DocumentTemplate dt, DiscoDataContext Database, User CreatorUser, DateTime Timestamp, params string[] DataObjectsIds)
|
||||||
{
|
{
|
||||||
return Interop.Pdf.PdfGenerator.GenerateBulkFromTemplate(dt, Database, CreatorUser, Timestamp, DataObjectsIds);
|
return Interop.Pdf.PdfGenerator.GenerateBulkFromTemplate(dt, Database, CreatorUser, Timestamp, DataObjectsIds);
|
||||||
}
|
}
|
||||||
public static System.IO.Stream GeneratePdfBulk(this DocumentTemplate dt, DiscoDataContext Database, User CreatorUser, System.DateTime Timestamp, params object[] DataObjects)
|
public static System.IO.Stream GeneratePdfBulk(this DocumentTemplate dt, DiscoDataContext Database, User CreatorUser, DateTime Timestamp, params IAttachmentTarget[] DataObjects)
|
||||||
{
|
{
|
||||||
return Interop.Pdf.PdfGenerator.GenerateBulkFromTemplate(dt, Database, CreatorUser, Timestamp, DataObjects);
|
return Interop.Pdf.PdfGenerator.GenerateBulkFromTemplate(dt, Database, CreatorUser, Timestamp, DataObjects);
|
||||||
}
|
}
|
||||||
public static System.IO.Stream GeneratePdf(this DocumentTemplate dt, DiscoDataContext Database, object Data, User CreatorUser, System.DateTime TimeStamp, DocumentState State, bool FlattenFields = false)
|
public static System.IO.Stream GeneratePdf(this DocumentTemplate dt, DiscoDataContext Database, IAttachmentTarget Target, User CreatorUser, DateTime TimeStamp, DocumentState State, bool FlattenFields = false)
|
||||||
{
|
{
|
||||||
bool generateExpression = !string.IsNullOrEmpty(dt.OnGenerateExpression);
|
bool generateExpression = !string.IsNullOrEmpty(dt.OnGenerateExpression);
|
||||||
string generateExpressionResult = null;
|
string generateExpressionResult = null;
|
||||||
|
|
||||||
if (generateExpression)
|
if (generateExpression)
|
||||||
generateExpressionResult = dt.EvaluateOnGenerateExpression(Data, Database, CreatorUser, TimeStamp, State);
|
generateExpressionResult = dt.EvaluateOnGenerateExpression(Target, Database, CreatorUser, TimeStamp, State);
|
||||||
|
|
||||||
var pdfStream = Interop.Pdf.PdfGenerator.GenerateFromTemplate(dt, Database, Data, CreatorUser, TimeStamp, State, FlattenFields);
|
var pdfStream = Interop.Pdf.PdfGenerator.GenerateFromTemplate(dt, Database, Target, CreatorUser, TimeStamp, State, FlattenFields);
|
||||||
|
|
||||||
if (generateExpression)
|
if (generateExpression)
|
||||||
DocumentsLog.LogDocumentGenerated(dt, Data, CreatorUser, generateExpressionResult);
|
DocumentsLog.LogDocumentGenerated(dt, Target, CreatorUser, generateExpressionResult);
|
||||||
else
|
else
|
||||||
DocumentsLog.LogDocumentGenerated(dt, Data, CreatorUser);
|
DocumentsLog.LogDocumentGenerated(dt, Target, CreatorUser);
|
||||||
|
|
||||||
return pdfStream;
|
return pdfStream;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Expression FilterExpressionFromCache(this DocumentTemplate dt)
|
|
||||||
{
|
|
||||||
return ExpressionCache.GetValue("DocumentTemplate_FilterExpression", dt.Id, () => { return Expression.TokenizeSingleDynamic(null, dt.FilterExpression, 0); });
|
|
||||||
}
|
|
||||||
public static void FilterExpressionInvalidateCache(this DocumentTemplate dt)
|
|
||||||
{
|
|
||||||
ExpressionCache.InvalidateKey("DocumentTemplate_FilterExpression", dt.Id);
|
|
||||||
}
|
|
||||||
public static bool FilterExpressionMatches(this DocumentTemplate dt, object Data, DiscoDataContext Database, User User, System.DateTime TimeStamp, DocumentState State)
|
|
||||||
{
|
|
||||||
if (!string.IsNullOrEmpty(dt.FilterExpression))
|
|
||||||
{
|
|
||||||
Expression compiledExpression = dt.FilterExpressionFromCache();
|
|
||||||
System.Collections.IDictionary evaluatorVariables = Expression.StandardVariables(dt, Database, User, TimeStamp, State);
|
|
||||||
try
|
|
||||||
{
|
|
||||||
object er = compiledExpression.EvaluateFirst<object>(Data, evaluatorVariables);
|
|
||||||
if (er is bool)
|
|
||||||
{
|
|
||||||
return (bool)er;
|
|
||||||
}
|
|
||||||
bool erBool;
|
|
||||||
if (bool.TryParse(er.ToString(), out erBool))
|
|
||||||
{
|
|
||||||
return erBool;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static Expression OnImportAttachmentExpressionFromCache(this DocumentTemplate dt)
|
|
||||||
{
|
|
||||||
return ExpressionCache.GetValue("DocumentTemplate_OnImportExpression", dt.Id, () => { return Expression.TokenizeSingleDynamic(null, dt.OnImportAttachmentExpression, 0); });
|
|
||||||
}
|
|
||||||
public static void OnImportAttachmentExpressionInvalidateCache(this DocumentTemplate dt)
|
|
||||||
{
|
|
||||||
ExpressionCache.InvalidateKey("DocumentTemplate_OnImportExpression", dt.Id);
|
|
||||||
}
|
|
||||||
public static string EvaluateOnAttachmentImportExpression(this DocumentTemplate dt, object Data, DiscoDataContext Database, User User, System.DateTime TimeStamp)
|
|
||||||
{
|
|
||||||
if (!string.IsNullOrEmpty(dt.OnImportAttachmentExpression))
|
|
||||||
{
|
|
||||||
Expression compiledExpression = dt.OnImportAttachmentExpressionFromCache();
|
|
||||||
System.Collections.IDictionary evaluatorVariables = Expression.StandardVariables(dt, Database, User, TimeStamp, null);
|
|
||||||
try
|
|
||||||
{
|
|
||||||
object result = compiledExpression.EvaluateFirst<object>(Data, evaluatorVariables);
|
|
||||||
if (result == null)
|
|
||||||
return null;
|
|
||||||
else
|
|
||||||
return result.ToString();
|
|
||||||
}
|
|
||||||
catch
|
|
||||||
{
|
|
||||||
throw;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static Expression OnGenerateExpressionFromCache(this DocumentTemplate dt)
|
|
||||||
{
|
|
||||||
return ExpressionCache.GetValue("DocumentTemplate_OnGenerateExpression", dt.Id, () => { return Expression.TokenizeSingleDynamic(null, dt.OnGenerateExpression, 0); });
|
|
||||||
}
|
|
||||||
public static void OnGenerateExpressionInvalidateCache(this DocumentTemplate dt)
|
|
||||||
{
|
|
||||||
ExpressionCache.InvalidateKey("DocumentTemplate_OnGenerateExpression", dt.Id);
|
|
||||||
}
|
|
||||||
public static string EvaluateOnGenerateExpression(this DocumentTemplate dt, object Data, DiscoDataContext Database, User User, System.DateTime TimeStamp, DocumentState State)
|
|
||||||
{
|
|
||||||
if (!string.IsNullOrEmpty(dt.OnGenerateExpression))
|
|
||||||
{
|
|
||||||
Expression compiledExpression = dt.OnGenerateExpressionFromCache();
|
|
||||||
System.Collections.IDictionary evaluatorVariables = Expression.StandardVariables(dt, Database, User, TimeStamp, State);
|
|
||||||
try
|
|
||||||
{
|
|
||||||
object result = compiledExpression.EvaluateFirst<object>(Data, evaluatorVariables);
|
|
||||||
return result.ToString();
|
|
||||||
}
|
|
||||||
catch
|
|
||||||
{
|
|
||||||
throw;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static string GetDataId(this DocumentTemplate dt, object Data)
|
|
||||||
{
|
|
||||||
if (Data is string)
|
|
||||||
{
|
|
||||||
return (string)Data;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
switch (dt.Scope)
|
|
||||||
{
|
|
||||||
case Models.Repository.DocumentTemplate.DocumentTemplateScopes.Device:
|
|
||||||
if (!(Data is Device))
|
|
||||||
throw new ArgumentException("This Document Template is configured for Devices only", "Data");
|
|
||||||
Device d = (Device)Data;
|
|
||||||
return d.SerialNumber;
|
|
||||||
case Models.Repository.DocumentTemplate.DocumentTemplateScopes.Job:
|
|
||||||
if (!(Data is Job))
|
|
||||||
throw new ArgumentException("This Document Template is configured for Jobs only", "Data");
|
|
||||||
Job d2 = (Job)Data;
|
|
||||||
return d2.Id.ToString();
|
|
||||||
case Models.Repository.DocumentTemplate.DocumentTemplateScopes.User:
|
|
||||||
if (!(Data is User))
|
|
||||||
throw new ArgumentException("This Document Template is configured for Users only", "Data");
|
|
||||||
User d3 = (User)Data;
|
|
||||||
return d3.UserId;
|
|
||||||
default:
|
|
||||||
throw new InvalidOperationException("Invalid Document Template Scope");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
public static string UniqueIdentifier(string DocumentTemplateId, string DataId, string CreatorId, System.DateTime Timestamp)
|
|
||||||
{
|
|
||||||
return string.Format("Disco|1|{0}|{1}|{2}|{3:s}",
|
|
||||||
DocumentTemplateId,
|
|
||||||
DataId,
|
|
||||||
CreatorId,
|
|
||||||
Timestamp
|
|
||||||
);
|
|
||||||
}
|
|
||||||
public static string UniqueIdentifier(this DocumentTemplate dt, object Data, string CreatorId, System.DateTime Timestamp)
|
|
||||||
{
|
|
||||||
return string.Format("Disco|1|{0}|{1}|{2}|{3:s}",
|
|
||||||
dt.Id,
|
|
||||||
dt.GetDataId(System.Runtime.CompilerServices.RuntimeHelpers.GetObjectValue(Data)),
|
|
||||||
CreatorId,
|
|
||||||
Timestamp
|
|
||||||
);
|
|
||||||
}
|
|
||||||
public static string UniquePageIdentifier(this DocumentTemplate dt, object Data, string CreatorId, System.DateTime Timestamp, int Page)
|
|
||||||
{
|
|
||||||
return string.Format("Disco|1|{0}|{1}|{2}|{3:s}|{4}",
|
|
||||||
dt.Id,
|
|
||||||
dt.GetDataId(System.Runtime.CompilerServices.RuntimeHelpers.GetObjectValue(Data)),
|
|
||||||
CreatorId,
|
|
||||||
Timestamp,
|
|
||||||
Page
|
|
||||||
);
|
|
||||||
}
|
|
||||||
public static List<RectangleF> QRCodeLocations(this DocumentTemplate dt, DiscoDataContext Database)
|
|
||||||
{
|
|
||||||
return DocumentTemplateBI.DocumentTemplateQRCodeLocationCache.GetLocations(dt, Database);
|
|
||||||
}
|
|
||||||
public static void Delete(this DocumentTemplate dt, DiscoDataContext Database)
|
public static void Delete(this DocumentTemplate dt, DiscoDataContext Database)
|
||||||
{
|
{
|
||||||
// Find & Rename all references
|
// Find & Rename all references
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ using Disco.Services.Plugins.Features.RepairProvider;
|
|||||||
|
|
||||||
using PublishJobResult = Disco.Models.Services.Interop.DiscoServices.PublishJobResult;
|
using PublishJobResult = Disco.Models.Services.Interop.DiscoServices.PublishJobResult;
|
||||||
using DiscoServicesJobs = Disco.Services.Interop.DiscoServices.Jobs;
|
using DiscoServicesJobs = Disco.Services.Interop.DiscoServices.Jobs;
|
||||||
|
using Disco.Services;
|
||||||
|
|
||||||
namespace Disco.BI.Extensions
|
namespace Disco.BI.Extensions
|
||||||
{
|
{
|
||||||
@@ -176,7 +177,7 @@ namespace Disco.BI.Extensions
|
|||||||
null,
|
null,
|
||||||
FaultDescription,
|
FaultDescription,
|
||||||
SendAttachments,
|
SendAttachments,
|
||||||
Disco.BI.Extensions.AttachmentExtensions.RepositoryFilename);
|
AttachmentDataStoreExtensions.RepositoryFilename);
|
||||||
|
|
||||||
if (!publishJobResult.Success)
|
if (!publishJobResult.Success)
|
||||||
throw new Exception(string.Format("Disco ICT Online Services failed with the following message: ", publishJobResult.ErrorMessage));
|
throw new Exception(string.Format("Disco ICT Online Services failed with the following message: ", publishJobResult.ErrorMessage));
|
||||||
@@ -398,7 +399,7 @@ namespace Disco.BI.Extensions
|
|||||||
null,
|
null,
|
||||||
RepairDescription,
|
RepairDescription,
|
||||||
SendAttachments,
|
SendAttachments,
|
||||||
Disco.BI.Extensions.AttachmentExtensions.RepositoryFilename);
|
AttachmentDataStoreExtensions.RepositoryFilename);
|
||||||
|
|
||||||
if (!publishJobResult.Success)
|
if (!publishJobResult.Success)
|
||||||
throw new Exception(string.Format("Disco ICT Online Services failed with the following message: ", publishJobResult.ErrorMessage));
|
throw new Exception(string.Format("Disco ICT Online Services failed with the following message: ", publishJobResult.ErrorMessage));
|
||||||
|
|||||||
@@ -1,50 +1,18 @@
|
|||||||
using System;
|
using Disco.Data.Repository;
|
||||||
|
using Disco.Models.Repository;
|
||||||
|
using Disco.Models.Services.Documents;
|
||||||
|
using Disco.Services;
|
||||||
|
using Disco.Services.Authorization;
|
||||||
|
using Disco.Services.Plugins;
|
||||||
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using Disco.Models.Repository;
|
|
||||||
using Disco.Data.Repository;
|
|
||||||
using System.IO;
|
|
||||||
using Disco.Models.BI.DocumentTemplates;
|
|
||||||
using Disco.Services.Plugins;
|
|
||||||
using Disco.Models.BI.Job;
|
|
||||||
using Disco.Services.Authorization;
|
|
||||||
|
|
||||||
namespace Disco.BI.Extensions
|
namespace Disco.BI.Extensions
|
||||||
{
|
{
|
||||||
public static class JobExtensions
|
public static class JobExtensions
|
||||||
{
|
{
|
||||||
public static JobAttachment CreateAttachment(this Job Job, DiscoDataContext Database, User CreatorUser, string Filename, string MimeType, string Comments, Stream Content, DocumentTemplate DocumentTemplate = null, byte[] PdfThumbnail = 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 = DateTime.Now,
|
|
||||||
Comments = Comments
|
|
||||||
};
|
|
||||||
|
|
||||||
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 List<DocumentTemplate> AvailableDocumentTemplates(this Job j, DiscoDataContext Database, User User, DateTime TimeStamp)
|
public static List<DocumentTemplate> AvailableDocumentTemplates(this Job j, DiscoDataContext Database, User User, DateTime TimeStamp)
|
||||||
{
|
{
|
||||||
var dts = Database.DocumentTemplates.Include("JobSubTypes")
|
var dts = Database.DocumentTemplates.Include("JobSubTypes")
|
||||||
|
|||||||
@@ -1,48 +1,15 @@
|
|||||||
using System;
|
using Disco.Data.Repository;
|
||||||
|
using Disco.Models.Repository;
|
||||||
|
using Disco.Models.Services.Documents;
|
||||||
|
using Disco.Services;
|
||||||
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Text;
|
|
||||||
using Disco.Models.Repository;
|
|
||||||
using Disco.Data.Repository;
|
|
||||||
using System.IO;
|
|
||||||
using Disco.Models.BI.DocumentTemplates;
|
|
||||||
using Disco.Services.Interop.ActiveDirectory;
|
|
||||||
|
|
||||||
namespace Disco.BI.Extensions
|
namespace Disco.BI.Extensions
|
||||||
{
|
{
|
||||||
public static class UserExtensions
|
public static class UserExtensions
|
||||||
{
|
{
|
||||||
public static UserAttachment CreateAttachment(this User User, DiscoDataContext Database, User CreatorUser, string Filename, string MimeType, string Comments, Stream Content, DocumentTemplate DocumentTemplate = null, byte[] PdfThumbnail = 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 = DateTime.Now,
|
|
||||||
Comments = Comments
|
|
||||||
};
|
|
||||||
|
|
||||||
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 List<DocumentTemplate> AvailableDocumentTemplates(this User u, DiscoDataContext Database, User User, DateTime TimeStamp)
|
public static List<DocumentTemplate> AvailableDocumentTemplates(this User u, DiscoDataContext Database, User User, DateTime TimeStamp)
|
||||||
{
|
{
|
||||||
var dts = Database.DocumentTemplates.Include("JobSubTypes")
|
var dts = Database.DocumentTemplates.Include("JobSubTypes")
|
||||||
@@ -57,10 +24,6 @@ namespace Disco.BI.Extensions
|
|||||||
{
|
{
|
||||||
return u.DeviceUserAssignments.Where(dua => !dua.UnassignedDate.HasValue).ToList();
|
return u.DeviceUserAssignments.Where(dua => !dua.UnassignedDate.HasValue).ToList();
|
||||||
}
|
}
|
||||||
public static ADUserAccount ActiveDirectoryAccount(this User User, params string[] AdditionalProperties)
|
|
||||||
{
|
|
||||||
return ActiveDirectory.RetrieveADUserAccount(User.UserId, AdditionalProperties);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static bool CanCreateJob(this User u)
|
public static bool CanCreateJob(this User u)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -22,240 +22,6 @@ namespace Disco.BI.Extensions
|
|||||||
return sr.ReadToEnd();
|
return sr.ReadToEnd();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#region Image Extensions
|
|
||||||
|
|
||||||
public static Bitmap RotateImage(this Image Source, float Angle, Brush BackgroundColor = null, bool ResizeIfOver45Deg = true)
|
|
||||||
{
|
|
||||||
int destWidth = Source.Width;
|
|
||||||
int destHeight = Source.Height;
|
|
||||||
bool resizedDest = false;
|
|
||||||
|
|
||||||
if (ResizeIfOver45Deg && ((Angle > 45 && Angle < 135) || (Angle < -45 && Angle > -135)))
|
|
||||||
{
|
|
||||||
destWidth = Source.Height;
|
|
||||||
destHeight = Source.Width;
|
|
||||||
resizedDest = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
Bitmap destination = new Bitmap(destWidth, destHeight);
|
|
||||||
destination.SetResolution(Source.HorizontalResolution, Source.VerticalResolution);
|
|
||||||
|
|
||||||
using (Graphics destinationGraphics = Graphics.FromImage(destination))
|
|
||||||
{
|
|
||||||
destinationGraphics.CompositingQuality = CompositingQuality.HighQuality;
|
|
||||||
destinationGraphics.InterpolationMode = InterpolationMode.HighQualityBicubic;
|
|
||||||
destinationGraphics.SmoothingMode = SmoothingMode.HighQuality;
|
|
||||||
|
|
||||||
if (BackgroundColor != null)
|
|
||||||
destinationGraphics.FillRectangle(BackgroundColor, destinationGraphics.VisibleClipBounds);
|
|
||||||
|
|
||||||
float offsetWidth = destWidth / 2;
|
|
||||||
float offsetHeight = destHeight / 2;
|
|
||||||
|
|
||||||
destinationGraphics.TranslateTransform(offsetWidth, offsetHeight);
|
|
||||||
destinationGraphics.RotateTransform(Angle);
|
|
||||||
|
|
||||||
RectangleF destinationLocation;
|
|
||||||
|
|
||||||
if (resizedDest)
|
|
||||||
destinationLocation = new RectangleF(
|
|
||||||
offsetHeight * -1, offsetWidth * -1,
|
|
||||||
destHeight, destWidth);
|
|
||||||
else
|
|
||||||
destinationLocation = new RectangleF(
|
|
||||||
offsetWidth * -1, offsetHeight * -1,
|
|
||||||
destWidth, destHeight);
|
|
||||||
|
|
||||||
destinationGraphics.DrawImage(Source, destinationLocation, new RectangleF(0, 0, Source.Width, Source.Height), GraphicsUnit.Pixel);
|
|
||||||
}
|
|
||||||
return destination;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static Bitmap ResizeImage(this Image Source, int Width, int Height, Brush BackgroundColor = null)
|
|
||||||
{
|
|
||||||
Bitmap destination = new Bitmap(Width, Height);
|
|
||||||
destination.SetResolution(72, 72);
|
|
||||||
using (Graphics destinationGraphics = Graphics.FromImage(destination))
|
|
||||||
{
|
|
||||||
destinationGraphics.CompositingQuality = CompositingQuality.HighQuality;
|
|
||||||
destinationGraphics.InterpolationMode = InterpolationMode.HighQualityBicubic;
|
|
||||||
destinationGraphics.SmoothingMode = SmoothingMode.HighQuality;
|
|
||||||
|
|
||||||
if (BackgroundColor != null)
|
|
||||||
destinationGraphics.FillRectangle(BackgroundColor, destinationGraphics.VisibleClipBounds);
|
|
||||||
|
|
||||||
float ratio = Math.Min((float)(destination.Width) / (float)(Source.Width), (float)(destination.Height) / (float)(Source.Height));
|
|
||||||
|
|
||||||
destinationGraphics.DrawImageResized(Source, ratio);
|
|
||||||
}
|
|
||||||
|
|
||||||
return destination;
|
|
||||||
}
|
|
||||||
public static void DrawImageResized(this Graphics graphics, Image SourceImage, float? Scale = null, float LocationX = -1, float LocationY = -1)
|
|
||||||
{
|
|
||||||
RectangleF clipBounds = graphics.VisibleClipBounds;
|
|
||||||
if (Scale == null) // Calculate Scale
|
|
||||||
Scale = Math.Min(clipBounds.Width / SourceImage.Width, clipBounds.Height / SourceImage.Height);
|
|
||||||
float newWidth = SourceImage.Width * Scale.Value;
|
|
||||||
float newHeight = SourceImage.Height * Scale.Value;
|
|
||||||
float newLeft = LocationX;
|
|
||||||
float newTop = LocationY;
|
|
||||||
|
|
||||||
if (newLeft < 0 || newTop < 0)
|
|
||||||
{
|
|
||||||
if (newWidth < clipBounds.Width)
|
|
||||||
newLeft = (clipBounds.Width - newWidth) / 2;
|
|
||||||
else
|
|
||||||
newLeft = 0;
|
|
||||||
if (newHeight < clipBounds.Height)
|
|
||||||
newTop = (clipBounds.Height - newHeight) / 2;
|
|
||||||
else
|
|
||||||
newTop = 0;
|
|
||||||
}
|
|
||||||
newLeft += clipBounds.Left;
|
|
||||||
newTop += clipBounds.Top;
|
|
||||||
|
|
||||||
graphics.DrawImage(SourceImage, new RectangleF(newLeft, newTop, newWidth, newHeight), new RectangleF(0, 0, SourceImage.Width, SourceImage.Height), GraphicsUnit.Pixel);
|
|
||||||
}
|
|
||||||
public static void EmbedIconOverlay(this Image Source, Image Icon)
|
|
||||||
{
|
|
||||||
int top = Math.Max(0, Source.Height - Icon.Height);
|
|
||||||
int left = Math.Max(0, Source.Width - Icon.Width);
|
|
||||||
|
|
||||||
using (Graphics sourceGraphics = Graphics.FromImage(Source))
|
|
||||||
{
|
|
||||||
sourceGraphics.DrawImage(Icon, left, top);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
public static void SavePng(this Image Source, string Filename)
|
|
||||||
{
|
|
||||||
using (FileStream outStream = new FileStream(Filename, FileMode.Create, FileAccess.Write, FileShare.None))
|
|
||||||
{
|
|
||||||
SavePng(Source, outStream);
|
|
||||||
outStream.Flush();
|
|
||||||
outStream.Close();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
public static void SavePng(this Image Source, Stream OutStream)
|
|
||||||
{
|
|
||||||
Source.Save(OutStream, ImageFormat.Png);
|
|
||||||
}
|
|
||||||
public static Stream SavePng(this Image Source)
|
|
||||||
{
|
|
||||||
MemoryStream outStream = new MemoryStream();
|
|
||||||
Source.SavePng(outStream);
|
|
||||||
outStream.Position = 0;
|
|
||||||
return outStream;
|
|
||||||
}
|
|
||||||
public static Stream SaveJpg(this Image Source, int Quality)
|
|
||||||
{
|
|
||||||
MemoryStream outStream = new MemoryStream();
|
|
||||||
Source.SaveJpg(Quality, outStream);
|
|
||||||
outStream.Position = 0;
|
|
||||||
return outStream;
|
|
||||||
}
|
|
||||||
public static void SaveJpg(this Image Source, int Quality, string Filename)
|
|
||||||
{
|
|
||||||
using (FileStream outStream = new FileStream(Filename, FileMode.Create, FileAccess.Write, FileShare.None))
|
|
||||||
{
|
|
||||||
SaveJpg(Source, Quality, outStream);
|
|
||||||
outStream.Flush();
|
|
||||||
outStream.Close();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
public static void SaveJpg(this Image Source, int Quality, Stream OutStream)
|
|
||||||
{
|
|
||||||
ImageCodecInfo jpgCodec = ImageCodecInfo.GetImageEncoders().Where(c => c.MimeType.Equals("image/jpeg", StringComparison.OrdinalIgnoreCase)).FirstOrDefault();
|
|
||||||
if (jpgCodec != null)
|
|
||||||
{
|
|
||||||
if (Quality < 0 || Quality > 100)
|
|
||||||
throw new ArgumentOutOfRangeException("Quality", "Quality must be a positive integer <= 100");
|
|
||||||
using (EncoderParameters ep = new EncoderParameters(1))
|
|
||||||
{
|
|
||||||
ep.Param[0] = new EncoderParameter(Encoder.Quality, Quality);
|
|
||||||
Source.Save(OutStream, jpgCodec, ep);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// Fallback
|
|
||||||
Source.Save(OutStream, ImageFormat.Jpeg);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
public static ImageMontage BuildImageMontage(this IEnumerable<Image> Images, int MaxHeight = -1, int MaxWidth = -1, bool EnforceDimensions = false)
|
|
||||||
{
|
|
||||||
if (EnforceDimensions && (MaxHeight < 0 || MaxWidth < 0))
|
|
||||||
throw new ArgumentOutOfRangeException("EnforceDimensions", "Dimensions can only be enforced when a MaxHeight and MaxWidth is supplied");
|
|
||||||
|
|
||||||
Dictionary<Image, int> imageLocations = new Dictionary<Image, int>();
|
|
||||||
double imageScale = 1.0;
|
|
||||||
int totalHeight = Images.Max(i => i.Height);
|
|
||||||
int totalWidth = Images.Sum(i => i.Width);
|
|
||||||
if (MaxHeight > 0 && totalHeight > MaxHeight)
|
|
||||||
{
|
|
||||||
imageScale = (double)MaxHeight / (double)totalHeight;
|
|
||||||
}
|
|
||||||
if (MaxWidth > 0 && totalWidth > MaxWidth)
|
|
||||||
{
|
|
||||||
imageScale = System.Math.Min(imageScale, (double)MaxWidth / (double)totalWidth);
|
|
||||||
}
|
|
||||||
int scaledHeight = EnforceDimensions ? MaxHeight : (int)System.Math.Round((double)totalHeight * imageScale);
|
|
||||||
int scaledWidth = EnforceDimensions ? MaxWidth : (int)System.Math.Round((double)totalWidth * imageScale);
|
|
||||||
System.Drawing.Bitmap imageResult = new System.Drawing.Bitmap(scaledWidth, scaledHeight);
|
|
||||||
imageResult.SetResolution(72f, 72f);
|
|
||||||
|
|
||||||
using (Graphics g = Graphics.FromImage(imageResult))
|
|
||||||
{
|
|
||||||
g.FillRectangle(Brushes.White, new Rectangle(Point.Empty, imageResult.Size));
|
|
||||||
|
|
||||||
int imageResultNextOffset = 0;
|
|
||||||
foreach (Image i in Images)
|
|
||||||
{
|
|
||||||
Rectangle imagePosition = new Rectangle(imageResultNextOffset, 0, (int)System.Math.Round((double)i.Width * imageScale), (int)System.Math.Round((double)i.Height * imageScale));
|
|
||||||
System.Drawing.Rectangle imageSize = new System.Drawing.Rectangle(0, 0, i.Width, i.Height);
|
|
||||||
g.DrawImage(i, imagePosition, imageSize, System.Drawing.GraphicsUnit.Pixel);
|
|
||||||
imageLocations[i] = imageResultNextOffset;
|
|
||||||
imageResultNextOffset += imagePosition.Width;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return new ImageMontage() { Montage = imageResult, MontageScale = imageScale, MontageSourceImageOffsets = imageLocations };
|
|
||||||
}
|
|
||||||
public class ImageMontage : IDisposable
|
|
||||||
{
|
|
||||||
|
|
||||||
public Image Montage { get; set; }
|
|
||||||
public double MontageScale { get; set; }
|
|
||||||
public Dictionary<Image, int> MontageSourceImageOffsets { get; set; }
|
|
||||||
|
|
||||||
public void Dispose()
|
|
||||||
{
|
|
||||||
if (Montage != null)
|
|
||||||
{
|
|
||||||
Montage.Dispose();
|
|
||||||
Montage = null;
|
|
||||||
}
|
|
||||||
if (MontageSourceImageOffsets != null)
|
|
||||||
{
|
|
||||||
MontageSourceImageOffsets.Clear();
|
|
||||||
MontageSourceImageOffsets = null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static Color InterpolateColours(this Color Start, Color End, double Progress)
|
|
||||||
{
|
|
||||||
if (Progress > 1 || Progress < 0)
|
|
||||||
throw new ArgumentOutOfRangeException("Progress", "Progress must be >= 0 && <= 1");
|
|
||||||
|
|
||||||
return Color.FromArgb(
|
|
||||||
(byte)(Start.A * (1 - Progress) + (End.A * Progress)),
|
|
||||||
(byte)(Start.R * (1 - Progress) + (End.R * Progress)),
|
|
||||||
(byte)(Start.G * (1 - Progress) + (End.G * Progress)),
|
|
||||||
(byte)(Start.B * (1 - Progress) + (End.B * Progress))
|
|
||||||
);
|
|
||||||
}
|
|
||||||
#endregion
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,9 +1,10 @@
|
|||||||
using Disco.BI.Expressions;
|
using Disco.BI.Extensions;
|
||||||
using Disco.BI.Extensions;
|
|
||||||
using Disco.Data.Repository;
|
using Disco.Data.Repository;
|
||||||
using Disco.Models.BI.DocumentTemplates;
|
|
||||||
using Disco.Models.BI.Expressions;
|
using Disco.Models.BI.Expressions;
|
||||||
using Disco.Models.Repository;
|
using Disco.Models.Repository;
|
||||||
|
using Disco.Models.Services.Documents;
|
||||||
|
using Disco.Services;
|
||||||
|
using Disco.Services.Expressions;
|
||||||
using Disco.Services.Interop.ActiveDirectory;
|
using Disco.Services.Interop.ActiveDirectory;
|
||||||
using Disco.Services.Users;
|
using Disco.Services.Users;
|
||||||
using iTextSharp.text.pdf;
|
using iTextSharp.text.pdf;
|
||||||
@@ -19,14 +20,14 @@ namespace Disco.BI.Interop.Pdf
|
|||||||
public static class PdfGenerator
|
public static class PdfGenerator
|
||||||
{
|
{
|
||||||
|
|
||||||
public static System.IO.Stream GenerateBulkFromTemplate(DocumentTemplate dt, DiscoDataContext Database, User CreatorUser, System.DateTime Timestamp, params object[] DataObjects)
|
public static Stream GenerateBulkFromTemplate(DocumentTemplate dt, DiscoDataContext Database, User CreatorUser, System.DateTime Timestamp, params IAttachmentTarget[] DataObjects)
|
||||||
{
|
{
|
||||||
if (DataObjects.Length > 0)
|
if (DataObjects.Length > 0)
|
||||||
{
|
{
|
||||||
List<Stream> generatedPdfs = new List<Stream>(DataObjects.Length);
|
List<Stream> generatedPdfs = new List<Stream>(DataObjects.Length);
|
||||||
using (Models.BI.DocumentTemplates.DocumentState state = Models.BI.DocumentTemplates.DocumentState.DefaultState())
|
using (var state = DocumentState.DefaultState())
|
||||||
{
|
{
|
||||||
foreach (object d in DataObjects)
|
foreach (var d in DataObjects)
|
||||||
{
|
{
|
||||||
generatedPdfs.Add(dt.GeneratePdf(Database, d, CreatorUser, Timestamp, state, true));
|
generatedPdfs.Add(dt.GeneratePdf(Database, d, CreatorUser, Timestamp, state, true));
|
||||||
state.SequenceNumber++;
|
state.SequenceNumber++;
|
||||||
@@ -48,9 +49,9 @@ namespace Disco.BI.Interop.Pdf
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static System.IO.Stream GenerateBulkFromTemplate(DocumentTemplate dt, DiscoDataContext Database, User CreatorUser, System.DateTime Timestamp, params string[] DataObjectsIds)
|
public static Stream GenerateBulkFromTemplate(DocumentTemplate dt, DiscoDataContext Database, User CreatorUser, DateTime Timestamp, params string[] DataObjectsIds)
|
||||||
{
|
{
|
||||||
object[] DataObjects;
|
IAttachmentTarget[] DataObjects;
|
||||||
|
|
||||||
switch (dt.Scope)
|
switch (dt.Scope)
|
||||||
{
|
{
|
||||||
@@ -62,7 +63,7 @@ namespace Disco.BI.Interop.Pdf
|
|||||||
DataObjects = Database.Jobs.Where(j => intDataObjectsIds.Contains(j.Id)).ToArray();
|
DataObjects = Database.Jobs.Where(j => intDataObjectsIds.Contains(j.Id)).ToArray();
|
||||||
break;
|
break;
|
||||||
case DocumentTemplate.DocumentTemplateScopes.User:
|
case DocumentTemplate.DocumentTemplateScopes.User:
|
||||||
DataObjects = new object[DataObjectsIds.Length];
|
DataObjects = new IAttachmentTarget[DataObjectsIds.Length];
|
||||||
for (int idIndex = 0; idIndex < DataObjectsIds.Length; idIndex++)
|
for (int idIndex = 0; idIndex < DataObjectsIds.Length; idIndex++)
|
||||||
{
|
{
|
||||||
string dataObjectId = DataObjectsIds[idIndex];
|
string dataObjectId = DataObjectsIds[idIndex];
|
||||||
@@ -79,7 +80,7 @@ namespace Disco.BI.Interop.Pdf
|
|||||||
return GenerateBulkFromTemplate(dt, Database, CreatorUser, Timestamp, DataObjects);
|
return GenerateBulkFromTemplate(dt, Database, CreatorUser, Timestamp, DataObjects);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static System.IO.Stream GenerateFromTemplate(DocumentTemplate dt, DiscoDataContext Database, object Data, User CreatorUser, System.DateTime TimeStamp, DocumentState State, bool FlattenFields = false)
|
public static Stream GenerateFromTemplate(DocumentTemplate dt, DiscoDataContext Database, IAttachmentTarget Data, User CreatorUser, DateTime TimeStamp, DocumentState State, bool FlattenFields = false)
|
||||||
{
|
{
|
||||||
// Validate Data
|
// Validate Data
|
||||||
switch (dt.Scope)
|
switch (dt.Scope)
|
||||||
@@ -124,7 +125,7 @@ namespace Disco.BI.Interop.Pdf
|
|||||||
if (pdfFieldKey.Equals("DiscoAttachmentId", StringComparison.OrdinalIgnoreCase))
|
if (pdfFieldKey.Equals("DiscoAttachmentId", StringComparison.OrdinalIgnoreCase))
|
||||||
{
|
{
|
||||||
AcroFields.Item fields = pdfStamper.AcroFields.Fields[pdfFieldKey];
|
AcroFields.Item fields = pdfStamper.AcroFields.Fields[pdfFieldKey];
|
||||||
string fieldValue = dt.UniqueIdentifier(Data, CreatorUser.UserId, TimeStamp);
|
string fieldValue = dt.CreateUniqueIdentifier(Database, Data, CreatorUser, TimeStamp, 0).ToJson();
|
||||||
if (FlattenFields)
|
if (FlattenFields)
|
||||||
pdfStamper.AcroFields.SetField(pdfFieldKey, String.Empty);
|
pdfStamper.AcroFields.SetField(pdfFieldKey, String.Empty);
|
||||||
else
|
else
|
||||||
@@ -134,7 +135,7 @@ namespace Disco.BI.Interop.Pdf
|
|||||||
for (int pdfFieldOrdinal = 0; pdfFieldOrdinal < fields.Size; pdfFieldOrdinal++)
|
for (int pdfFieldOrdinal = 0; pdfFieldOrdinal < fields.Size; pdfFieldOrdinal++)
|
||||||
{
|
{
|
||||||
AcroFields.FieldPosition pdfFieldPosition = pdfFieldPositions[pdfFieldOrdinal];
|
AcroFields.FieldPosition pdfFieldPosition = pdfFieldPositions[pdfFieldOrdinal];
|
||||||
string pdfBarcodeContent = dt.UniquePageIdentifier(Data, CreatorUser.UserId, TimeStamp, pdfFieldPosition.page);
|
string pdfBarcodeContent = dt.CreateUniqueIdentifier(Database, Data, CreatorUser, TimeStamp, pdfFieldPosition.page).ToQRCodeString();
|
||||||
BarcodeQRCode pdfBarcode = new BarcodeQRCode(pdfBarcodeContent, (int)pdfFieldPosition.position.Width, (int)pdfFieldPosition.position.Height, null);
|
BarcodeQRCode pdfBarcode = new BarcodeQRCode(pdfBarcodeContent, (int)pdfFieldPosition.position.Width, (int)pdfFieldPosition.position.Height, null);
|
||||||
iTextSharp.text.Image pdfBarcodeImage = pdfBarcode.GetImage();
|
iTextSharp.text.Image pdfBarcodeImage = pdfBarcode.GetImage();
|
||||||
pdfBarcodeImage.SetAbsolutePosition(pdfFieldPosition.position.Left, pdfFieldPosition.position.Bottom);
|
pdfBarcodeImage.SetAbsolutePosition(pdfFieldPosition.position.Left, pdfFieldPosition.position.Bottom);
|
||||||
|
|||||||
@@ -1,977 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
|
||||||
using iTextSharp.text.pdf;
|
|
||||||
using System.IO;
|
|
||||||
using System.Drawing;
|
|
||||||
using Disco.BI.DocumentTemplateBI.Importer;
|
|
||||||
using Disco.BI.DocumentTemplateBI;
|
|
||||||
using System.Drawing.Drawing2D;
|
|
||||||
using com.google.zxing;
|
|
||||||
using com.google.zxing.multi.qrcode;
|
|
||||||
using Disco.Data.Repository;
|
|
||||||
using System.Web.Caching;
|
|
||||||
using Disco.BI.Extensions;
|
|
||||||
using Disco.Models.Repository;
|
|
||||||
using System.Collections;
|
|
||||||
using com.google.zxing.common;
|
|
||||||
using BitMiracle.LibTiff.Classic;
|
|
||||||
using System.Drawing.Imaging;
|
|
||||||
using System.Runtime.InteropServices;
|
|
||||||
|
|
||||||
namespace Disco.BI.Interop.Pdf
|
|
||||||
{
|
|
||||||
public static class PdfImporter
|
|
||||||
{
|
|
||||||
public static RectangleF CalculateLocationRatio(this Result zxingResult, int ImageWidth, int ImageHeight)
|
|
||||||
{
|
|
||||||
var orderedPoints = zxingResult.ResultPoints.OrderBy(p => p.X * p.Y).ToArray();
|
|
||||||
var topLeftPoint = orderedPoints.First();
|
|
||||||
var bottomRightPoint = orderedPoints.Last();
|
|
||||||
|
|
||||||
var x = topLeftPoint.X;
|
|
||||||
var y = topLeftPoint.Y;
|
|
||||||
var width = bottomRightPoint.X - x;
|
|
||||||
var height = bottomRightPoint.Y - y;
|
|
||||||
|
|
||||||
return new RectangleF(
|
|
||||||
(float)System.Math.Min(1.0, System.Math.Max(0.0, (double)(x / ImageWidth) - 0.05)),
|
|
||||||
(float)System.Math.Min(1.0, System.Math.Max(0.0, (double)(y / ImageHeight) - 0.05)),
|
|
||||||
(float)System.Math.Min(1.0, System.Math.Max(0.0, (double)(width / ImageWidth) + 0.1)),
|
|
||||||
(float)System.Math.Min(1.0, System.Math.Max(0.0, (double)(height / ImageHeight) + 0.1))
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
private class DetectImageResult : IDisposable
|
|
||||||
{
|
|
||||||
public Result Result { get; set; }
|
|
||||||
public Point ResultOffset { get; set; }
|
|
||||||
public double ResultScale { get; set; }
|
|
||||||
|
|
||||||
public float CalculateRotation()
|
|
||||||
{
|
|
||||||
var p1 = this.Result.ResultPoints[0];
|
|
||||||
var p2 = this.Result.ResultPoints[1];
|
|
||||||
double rotOpposite = p1.X - p2.X;
|
|
||||||
double rotAdjacent = p1.Y - p2.Y;
|
|
||||||
float rotation = 0;
|
|
||||||
|
|
||||||
if (rotOpposite != 0 || rotAdjacent != 0)
|
|
||||||
{
|
|
||||||
rotation = (float)(Math.Atan2(rotOpposite, rotAdjacent) * (180 / Math.PI)); // Degrees
|
|
||||||
}
|
|
||||||
|
|
||||||
return rotation;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Dispose()
|
|
||||||
{
|
|
||||||
// Do Nothing; yet...
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private class DetectStateHints
|
|
||||||
{
|
|
||||||
public List<Tuple<RectangleF, Rotation>> PriorDetections { get; set; }
|
|
||||||
|
|
||||||
public DetectStateHints()
|
|
||||||
{
|
|
||||||
this.PriorDetections = new List<Tuple<RectangleF, Rotation>>();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private enum Rotation
|
|
||||||
{
|
|
||||||
None = 0,
|
|
||||||
Degrees90 = 1,
|
|
||||||
DegreesNeg90 = 2,
|
|
||||||
Degrees180 = 3
|
|
||||||
}
|
|
||||||
|
|
||||||
private class DetectPageResult : IDisposable
|
|
||||||
{
|
|
||||||
public int PageNumber { get; set; }
|
|
||||||
public DocumentUniqueIdentifier DetectedIdentifier { get; set; }
|
|
||||||
public Disco.BI.Extensions.UtilityExtensions.ImageMontage ThumbnailImage { get; set; }
|
|
||||||
public MemoryStream AttachmentThumbnailImage { get; set; }
|
|
||||||
public Disco.BI.Extensions.UtilityExtensions.ImageMontage UndetectedPageImage { get; set; }
|
|
||||||
|
|
||||||
public void DrawThumbnailImageResult(DetectImageResult Result, Image DetectedImage)
|
|
||||||
{
|
|
||||||
if (Result.Result.ResultPoints.Length == 4)
|
|
||||||
{ // Draw Square on Thumbnail
|
|
||||||
using (Graphics thumbnailGraphics = Graphics.FromImage(ThumbnailImage.Montage))
|
|
||||||
{
|
|
||||||
var thumbnailOffset = ThumbnailImage.MontageSourceImageOffsets[DetectedImage];
|
|
||||||
|
|
||||||
var linePoints = Result.Result.ResultPoints.Select(p => new Point((int)(thumbnailOffset + ((Result.ResultOffset.X + p.X) * Result.ResultScale * ThumbnailImage.MontageScale)), (int)((p.Y + Result.ResultOffset.Y) * Result.ResultScale * ThumbnailImage.MontageScale))).ToArray();
|
|
||||||
using (GraphicsPath graphicsPath = new GraphicsPath())
|
|
||||||
{
|
|
||||||
for (int linePointIndex = 0; linePointIndex < (linePoints.Length - 1); linePointIndex++)
|
|
||||||
graphicsPath.AddLine(linePoints[linePointIndex], linePoints[linePointIndex + 1]);
|
|
||||||
graphicsPath.AddLine(linePoints[linePoints.Length - 1], linePoints[0]);
|
|
||||||
using (SolidBrush graphicsBrush = new SolidBrush(Color.FromArgb(128, 255, 0, 0)))
|
|
||||||
thumbnailGraphics.FillPath(graphicsBrush, graphicsPath);
|
|
||||||
using (Pen graphicsPen = new Pen(Color.FromArgb(200, 255, 0, 0), 2))
|
|
||||||
thumbnailGraphics.DrawPath(graphicsPen, graphicsPath);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Dispose()
|
|
||||||
{
|
|
||||||
if (ThumbnailImage != null)
|
|
||||||
{
|
|
||||||
ThumbnailImage.Dispose();
|
|
||||||
ThumbnailImage = null;
|
|
||||||
}
|
|
||||||
if (AttachmentThumbnailImage != null)
|
|
||||||
{
|
|
||||||
AttachmentThumbnailImage.Dispose();
|
|
||||||
AttachmentThumbnailImage = null;
|
|
||||||
}
|
|
||||||
if (UndetectedPageImage != null)
|
|
||||||
{
|
|
||||||
UndetectedPageImage.Dispose();
|
|
||||||
UndetectedPageImage = null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static Tuple<Result, Rectangle, Rotation> DetectImageFromSegment(Bitmap pageImage, QRCodeMultiReader zxingReader, Hashtable zxingReaderHints, RectangleF LocationPercentage, Rotation Rotation)
|
|
||||||
{
|
|
||||||
System.Drawing.Rectangle region;
|
|
||||||
|
|
||||||
switch (Rotation)
|
|
||||||
{
|
|
||||||
case Rotation.None: // Original Position
|
|
||||||
region = new Rectangle(
|
|
||||||
(int)(pageImage.Width * LocationPercentage.Left),
|
|
||||||
(int)(pageImage.Height * LocationPercentage.Top),
|
|
||||||
(int)(pageImage.Width * LocationPercentage.Width),
|
|
||||||
(int)(pageImage.Height * LocationPercentage.Height));
|
|
||||||
break;
|
|
||||||
case Rotation.Degrees90: // Clockwise 90 degrees
|
|
||||||
region = new Rectangle(
|
|
||||||
(int)(pageImage.Width - (pageImage.Width * (LocationPercentage.Top + LocationPercentage.Height))),
|
|
||||||
(int)(pageImage.Height * LocationPercentage.Left),
|
|
||||||
(int)(pageImage.Width * LocationPercentage.Height),
|
|
||||||
(int)(pageImage.Height * LocationPercentage.Width));
|
|
||||||
break;
|
|
||||||
case Rotation.DegreesNeg90: // Anti-clockwise 90 degrees
|
|
||||||
region = new Rectangle(
|
|
||||||
(int)(pageImage.Width * LocationPercentage.Top),
|
|
||||||
(int)(pageImage.Height - (pageImage.Height * (LocationPercentage.Left + LocationPercentage.Width))),
|
|
||||||
(int)(pageImage.Width * LocationPercentage.Height),
|
|
||||||
(int)(pageImage.Height * LocationPercentage.Width));
|
|
||||||
break;
|
|
||||||
case Rotation.Degrees180: // 180 degrees
|
|
||||||
region = new Rectangle(
|
|
||||||
(int)(pageImage.Width - (pageImage.Width * (LocationPercentage.Left + LocationPercentage.Width))),
|
|
||||||
(int)(pageImage.Height - (pageImage.Height * (LocationPercentage.Top + LocationPercentage.Height))),
|
|
||||||
(int)(pageImage.Width * LocationPercentage.Width),
|
|
||||||
(int)(pageImage.Height * LocationPercentage.Height));
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
throw new InvalidOperationException("Unknown Rotation");
|
|
||||||
}
|
|
||||||
|
|
||||||
LuminanceSource zxingSource;
|
|
||||||
using (Bitmap pageImageRegion = new Bitmap(region.Width, region.Height))
|
|
||||||
{
|
|
||||||
pageImageRegion.SetResolution(pageImage.HorizontalResolution, pageImage.VerticalResolution);
|
|
||||||
|
|
||||||
using (Graphics pageImageRegionGraphics = Graphics.FromImage(pageImageRegion))
|
|
||||||
{
|
|
||||||
pageImageRegionGraphics.DrawImage(pageImage, 0, 0, region, GraphicsUnit.Pixel);
|
|
||||||
}
|
|
||||||
|
|
||||||
zxingSource = new BitmapLuminanceSource(pageImageRegion);
|
|
||||||
}
|
|
||||||
var zxingHB = new HybridBinarizer(zxingSource);
|
|
||||||
var zxingBB = new BinaryBitmap(zxingHB);
|
|
||||||
try
|
|
||||||
{
|
|
||||||
var zxingResult = zxingReader.decode(zxingBB, zxingReaderHints);
|
|
||||||
if (zxingResult != null)
|
|
||||||
return new Tuple<Result, Rectangle, Rotation>(zxingResult, region, Rotation);
|
|
||||||
}
|
|
||||||
catch (ReaderException)
|
|
||||||
{
|
|
||||||
// Ignore Location Errors
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static DetectImageResult DetectImage(DiscoDataContext Database, Bitmap pageImageOriginal, string SessionId, IEnumerable<DocumentTemplate> detectDocumentTemplates, DetectStateHints StateHints)
|
|
||||||
{
|
|
||||||
Bitmap pageImage = pageImageOriginal;
|
|
||||||
double pageImageModifiedScale = 1;
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
// Resize if Resolution > 80; Set to 72 Dpi
|
|
||||||
if (pageImage.HorizontalResolution > 80 || pageImage.VerticalResolution > 80)
|
|
||||||
{
|
|
||||||
pageImageModifiedScale = pageImage.HorizontalResolution / 72;
|
|
||||||
int newWidth = (int)((72 / pageImage.HorizontalResolution) * pageImage.Width);
|
|
||||||
int newHeight = (int)((72 / pageImage.VerticalResolution) * pageImage.Height);
|
|
||||||
|
|
||||||
pageImage = pageImage.ResizeImage(newWidth, newHeight);
|
|
||||||
}
|
|
||||||
|
|
||||||
Tuple<Result, Rectangle, Rotation> result = default(Tuple<Result, Rectangle, Rotation>);
|
|
||||||
QRCodeMultiReader zxingMfr = new QRCodeMultiReader();
|
|
||||||
Hashtable zxingMfrHints = new Hashtable();
|
|
||||||
zxingMfrHints.Add(DecodeHintType.TRY_HARDER, true);
|
|
||||||
|
|
||||||
|
|
||||||
// Look in previously found locations
|
|
||||||
if (StateHints.PriorDetections.Count > 0)
|
|
||||||
{
|
|
||||||
foreach (var previousLocation in StateHints.PriorDetections)
|
|
||||||
{
|
|
||||||
result = DetectImageFromSegment(pageImage, zxingMfr, zxingMfrHints,
|
|
||||||
previousLocation.Item1, previousLocation.Item2);
|
|
||||||
if (result != null)
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (result == null)
|
|
||||||
{
|
|
||||||
// Try the whole image
|
|
||||||
var zxingSource = new BitmapLuminanceSource(pageImage);
|
|
||||||
var zxingHB = new HybridBinarizer(zxingSource);
|
|
||||||
var zxingBB = new BinaryBitmap(zxingHB);
|
|
||||||
try
|
|
||||||
{
|
|
||||||
var zxingResult = zxingMfr.decode(zxingBB, zxingMfrHints);
|
|
||||||
if (zxingResult != null)
|
|
||||||
{
|
|
||||||
result = new Tuple<Result, Rectangle, Rotation>(zxingResult, new Rectangle(0, 0, pageImage.Width, pageImage.Height), Rotation.None);
|
|
||||||
|
|
||||||
StateHints.PriorDetections.Insert(0, new Tuple<RectangleF, Rotation>(
|
|
||||||
result.Item1.CalculateLocationRatio(pageImage.Width, pageImage.Height)
|
|
||||||
, Rotation.None));
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (ReaderException)
|
|
||||||
{
|
|
||||||
// Ignore Errors
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (result == null)
|
|
||||||
{
|
|
||||||
// Look in 'Known' locations
|
|
||||||
for (int rotationIndex = 0; rotationIndex < 4; rotationIndex++)
|
|
||||||
{
|
|
||||||
foreach (DocumentTemplate dt in detectDocumentTemplates)
|
|
||||||
{
|
|
||||||
var locationBag = dt.QRCodeLocations(Database);
|
|
||||||
foreach (var location in locationBag)
|
|
||||||
{
|
|
||||||
result = DetectImageFromSegment(pageImage, zxingMfr, zxingMfrHints,
|
|
||||||
location, (Rotation)rotationIndex);
|
|
||||||
|
|
||||||
StateHints.PriorDetections.Insert(0, new Tuple<RectangleF, Rotation>(location, (Rotation)rotationIndex));
|
|
||||||
}
|
|
||||||
if (result != null)
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (result != null)
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (result != null)
|
|
||||||
|
|
||||||
return new DetectImageResult() { Result = result.Item1, ResultOffset = result.Item2.Location, ResultScale = pageImageModifiedScale };
|
|
||||||
else
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
throw ex;
|
|
||||||
}
|
|
||||||
finally
|
|
||||||
{
|
|
||||||
if (pageImageOriginal != pageImage)
|
|
||||||
pageImage.Dispose();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static DetectPageResult DetectPage(DiscoDataContext Database, PdfReader pdfReader, int PageNumber, string SessionId, string DataStoreSessionCacheLocation, IEnumerable<DocumentTemplate> detectDocumentTemplates, DetectStateHints StateHints)
|
|
||||||
{
|
|
||||||
DetectPageResult result = new DetectPageResult() { PageNumber = PageNumber };
|
|
||||||
|
|
||||||
DocumentsLog.LogImportPageProgress(SessionId, PageNumber, 10, "Loading Page Images");
|
|
||||||
|
|
||||||
using (DisposableImageCollection pageImages = pdfReader.PdfPageImages(PageNumber))
|
|
||||||
{
|
|
||||||
if (pageImages.Count > 0)
|
|
||||||
{
|
|
||||||
result.ThumbnailImage = pageImages.BuildImageMontage(256, 256);
|
|
||||||
var pageThumbnailFilename = Path.Combine(DataStoreSessionCacheLocation, string.Format("{0}-{1}", SessionId, PageNumber));
|
|
||||||
|
|
||||||
result.ThumbnailImage.Montage.SavePng(pageThumbnailFilename);
|
|
||||||
DocumentsLog.LogImportPageImageUpdate(SessionId, PageNumber);
|
|
||||||
|
|
||||||
double pageProgressInterval = 90 / pageImages.Count;
|
|
||||||
|
|
||||||
foreach (var pageImageOriginal in pageImages)
|
|
||||||
{
|
|
||||||
DocumentsLog.LogImportPageProgress(SessionId, PageNumber, (int)(10 + (pageProgressInterval * pageImages.IndexOf(pageImageOriginal))), String.Format("Processing Page Image {0} of {1}", pageImages.IndexOf(pageImageOriginal) + 1, pageImages.Count));
|
|
||||||
|
|
||||||
using (var zxingResult = DetectImage(Database, pageImageOriginal, SessionId, detectDocumentTemplates, StateHints))
|
|
||||||
{
|
|
||||||
if (zxingResult != null)
|
|
||||||
{
|
|
||||||
if (DocumentUniqueIdentifier.IsDocumentUniqueIdentifier(zxingResult.Result.Text))
|
|
||||||
{
|
|
||||||
float imageRotation = zxingResult.CalculateRotation();
|
|
||||||
|
|
||||||
result.DrawThumbnailImageResult(zxingResult, pageImageOriginal);
|
|
||||||
|
|
||||||
if (imageRotation != 0)
|
|
||||||
{
|
|
||||||
var preImageRotation = result.ThumbnailImage.Montage;
|
|
||||||
result.ThumbnailImage.Montage = result.ThumbnailImage.Montage.RotateImage(imageRotation);
|
|
||||||
preImageRotation.Dispose();
|
|
||||||
}
|
|
||||||
|
|
||||||
result.ThumbnailImage.Montage.SavePng(pageThumbnailFilename);
|
|
||||||
DocumentsLog.LogImportPageImageUpdate(SessionId, PageNumber);
|
|
||||||
|
|
||||||
result.AttachmentThumbnailImage = new MemoryStream();
|
|
||||||
using (var attachmentThumbImage = pageImages.BuildImageMontage(48, 48, true))
|
|
||||||
{
|
|
||||||
using (Image mimeTypeIcon = Disco.Properties.Resources.MimeType_pdf16)
|
|
||||||
attachmentThumbImage.Montage.EmbedIconOverlay(mimeTypeIcon);
|
|
||||||
|
|
||||||
if (imageRotation != 0)
|
|
||||||
{
|
|
||||||
var preImageRotation = attachmentThumbImage.Montage;
|
|
||||||
attachmentThumbImage.Montage = attachmentThumbImage.Montage.RotateImage(imageRotation, Brushes.White);
|
|
||||||
preImageRotation.Dispose();
|
|
||||||
}
|
|
||||||
|
|
||||||
attachmentThumbImage.Montage.SaveJpg(95, result.AttachmentThumbnailImage);
|
|
||||||
}
|
|
||||||
|
|
||||||
result.DetectedIdentifier = new DocumentUniqueIdentifier(zxingResult.Result.Text, PageNumber.ToString());
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Page Unassigned
|
|
||||||
result.UndetectedPageImage = pageImages.BuildImageMontage(700, 700);
|
|
||||||
}
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static bool ProcessPdfAttachment(string Filename, DiscoDataContext Database, string SessionId, Cache HttpCache)
|
|
||||||
{
|
|
||||||
var dataStoreUnassignedLocation = DataStore.CreateLocation(Database, "DocumentDropBox_Unassigned");
|
|
||||||
|
|
||||||
DocumentsLog.LogImportProgress(SessionId, 0, "Reading File");
|
|
||||||
|
|
||||||
using (FileStream fs = new FileStream(Filename, FileMode.Open, FileAccess.ReadWrite, FileShare.None))
|
|
||||||
{
|
|
||||||
var pdfReader = new PdfReader(fs);
|
|
||||||
|
|
||||||
var pdfPagesAssigned = new Dictionary<int, Tuple<DocumentUniqueIdentifier, byte[]>>();
|
|
||||||
|
|
||||||
var dataStoreSessionPagesCacheLocation = DataStore.CreateLocation(Database, "Cache\\DocumentDropBox_SessionPages");
|
|
||||||
var detectDocumentTemplates = Database.DocumentTemplates.ToArray();
|
|
||||||
|
|
||||||
double progressInterval = 70 / pdfReader.NumberOfPages;
|
|
||||||
|
|
||||||
DetectStateHints detectStateHints = new DetectStateHints();
|
|
||||||
|
|
||||||
for (int PageNumber = 1; PageNumber <= pdfReader.NumberOfPages; PageNumber++)
|
|
||||||
{
|
|
||||||
DocumentsLog.LogImportProgress(SessionId, (int)(PageNumber * progressInterval), string.Format("Processing Page {0} of {1}", PageNumber, pdfReader.NumberOfPages));
|
|
||||||
DocumentsLog.LogImportPageStarting(SessionId, PageNumber);
|
|
||||||
|
|
||||||
using (var pageResult = DetectPage(Database, pdfReader, PageNumber, SessionId, dataStoreSessionPagesCacheLocation, detectDocumentTemplates, detectStateHints))
|
|
||||||
{
|
|
||||||
if (pageResult.DetectedIdentifier != null)
|
|
||||||
{
|
|
||||||
var docId = pageResult.DetectedIdentifier;
|
|
||||||
pdfPagesAssigned.Add(PageNumber, new Tuple<DocumentUniqueIdentifier, byte[]>(docId, pageResult.AttachmentThumbnailImage.ToArray()));
|
|
||||||
|
|
||||||
docId.LoadComponents(Database);
|
|
||||||
DocumentsLog.LogImportPageDetected(SessionId, PageNumber, docId.TemplateTypeId, docId.DocumentTemplate.Description, docId.DocumentTemplate.Scope, docId.DataId, docId.DataDescription);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// Undetected Page - Write Preview-Images while still in Memory
|
|
||||||
DocumentsLog.LogImportPageUndetected(SessionId, PageNumber);
|
|
||||||
|
|
||||||
// Thumbnail:
|
|
||||||
string unassignedImageThumbnailFilename = Path.Combine(dataStoreUnassignedLocation, string.Format("{0}_{1}_thumbnail.png", SessionId, PageNumber));
|
|
||||||
if (pageResult.ThumbnailImage != null)
|
|
||||||
pageResult.ThumbnailImage.Montage.SavePng(unassignedImageThumbnailFilename);
|
|
||||||
else
|
|
||||||
Disco.Properties.Resources.MimeType_pdf48.SavePng(unassignedImageThumbnailFilename);
|
|
||||||
// Large Preview
|
|
||||||
string unassignedImageFilename = Path.Combine(dataStoreUnassignedLocation, string.Format("{0}_{1}.jpg", SessionId, PageNumber));
|
|
||||||
if (pageResult.UndetectedPageImage != null)
|
|
||||||
pageResult.UndetectedPageImage.Montage.SaveJpg(90, unassignedImageFilename);
|
|
||||||
else
|
|
||||||
Disco.Properties.Resources.MimeType_pdf48.SaveJpg(90, unassignedImageFilename);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
// Write out Assigned Documents
|
|
||||||
var assignedDocuments = pdfPagesAssigned.GroupBy(u => u.Value.Item1.DocumentUniqueId).ToList();
|
|
||||||
if (assignedDocuments.Count > 0)
|
|
||||||
{
|
|
||||||
progressInterval = 20 / assignedDocuments.Count;
|
|
||||||
|
|
||||||
foreach (var documentPortion in assignedDocuments)
|
|
||||||
{
|
|
||||||
DocumentsLog.LogImportProgress(SessionId, (int)(70 + (assignedDocuments.IndexOf(documentPortion) * progressInterval)), string.Format("Importing Documents {0} of {1}", assignedDocuments.IndexOf(documentPortion) + 1, assignedDocuments.Count));
|
|
||||||
|
|
||||||
var documentPortionInfo = documentPortion.First().Value;
|
|
||||||
var documentPortionIdentifier = documentPortionInfo.Item1;
|
|
||||||
var documentPortionThumbnail = documentPortionInfo.Item2;
|
|
||||||
|
|
||||||
if (!documentPortionIdentifier.LoadComponents(Database))
|
|
||||||
{
|
|
||||||
// Unknown Document Unique Id
|
|
||||||
foreach (var dp in documentPortion)
|
|
||||||
{
|
|
||||||
var tag = int.Parse(dp.Value.Item1.Tag);
|
|
||||||
if (pdfPagesAssigned.ContainsKey(tag))
|
|
||||||
pdfPagesAssigned.Remove(tag);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
using (MemoryStream msBuilder = new MemoryStream())
|
|
||||||
{
|
|
||||||
var pdfDoc = new iTextSharp.text.Document();
|
|
||||||
var pdfCopy = new PdfCopy(pdfDoc, msBuilder);
|
|
||||||
|
|
||||||
pdfDoc.Open();
|
|
||||||
pdfCopy.CloseStream = false;
|
|
||||||
|
|
||||||
foreach (var dp in documentPortion.OrderBy(dg => dg.Value.Item1.Page))
|
|
||||||
{
|
|
||||||
var pageSize = pdfReader.GetPageSizeWithRotation(dp.Key);
|
|
||||||
var page = pdfCopy.GetImportedPage(pdfReader, dp.Key);
|
|
||||||
|
|
||||||
pdfDoc.SetPageSize(pageSize);
|
|
||||||
pdfDoc.NewPage();
|
|
||||||
|
|
||||||
pdfCopy.AddPage(page);
|
|
||||||
}
|
|
||||||
|
|
||||||
pdfDoc.Close();
|
|
||||||
pdfCopy.Close();
|
|
||||||
|
|
||||||
msBuilder.Position = 0;
|
|
||||||
|
|
||||||
var attachmentSuccess = documentPortionIdentifier.ImportPdfAttachment(Database, msBuilder, documentPortionThumbnail);
|
|
||||||
|
|
||||||
if (!attachmentSuccess)
|
|
||||||
{ // Unable to add Attachment
|
|
||||||
foreach (var dp in documentPortion)
|
|
||||||
{
|
|
||||||
var tag = int.Parse(dp.Value.Item1.Tag);
|
|
||||||
if (pdfPagesAssigned.ContainsKey(tag))
|
|
||||||
pdfPagesAssigned.Remove(tag);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Write out Unassigned Pages
|
|
||||||
List<int> pdfPagesUnassigned = new List<int>();
|
|
||||||
for (int PageNumber = 1; PageNumber <= pdfReader.NumberOfPages; PageNumber++)
|
|
||||||
if (!pdfPagesAssigned.ContainsKey(PageNumber))
|
|
||||||
pdfPagesUnassigned.Add(PageNumber);
|
|
||||||
if (pdfPagesUnassigned.Count > 0)
|
|
||||||
{
|
|
||||||
progressInterval = 10 / pdfPagesUnassigned.Count;
|
|
||||||
//dataStoreUnassignedLocation
|
|
||||||
foreach (var PageNumber in pdfPagesUnassigned)
|
|
||||||
{
|
|
||||||
DocumentsLog.LogImportProgress(SessionId, (int)(90 + (pdfPagesUnassigned.IndexOf(PageNumber) * progressInterval)), string.Format("Processing Undetected Documents {0} of {1}", pdfPagesUnassigned.IndexOf(PageNumber) + 1, pdfPagesUnassigned.Count));
|
|
||||||
|
|
||||||
using (MemoryStream msBuilder = new MemoryStream())
|
|
||||||
{
|
|
||||||
var pdfDoc = new iTextSharp.text.Document();
|
|
||||||
var pdfCopy = new PdfCopy(pdfDoc, msBuilder);
|
|
||||||
|
|
||||||
pdfDoc.Open();
|
|
||||||
pdfCopy.CloseStream = false;
|
|
||||||
|
|
||||||
var pageSize = pdfReader.GetPageSizeWithRotation(PageNumber);
|
|
||||||
var page = pdfCopy.GetImportedPage(pdfReader, PageNumber);
|
|
||||||
pdfDoc.SetPageSize(pageSize);
|
|
||||||
pdfDoc.NewPage();
|
|
||||||
|
|
||||||
pdfCopy.AddPage(page);
|
|
||||||
pdfDoc.Close();
|
|
||||||
pdfCopy.Close();
|
|
||||||
|
|
||||||
File.WriteAllBytes(Path.Combine(dataStoreUnassignedLocation, string.Format("{0}_{1}.pdf", SessionId, PageNumber)), msBuilder.ToArray());
|
|
||||||
|
|
||||||
DocumentsLog.LogImportPageUndetectedStored(SessionId, PageNumber);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
DocumentsLog.LogImportProgress(SessionId, 100, "Finished Importing Document");
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
public static bool ProcessPdfAttachment(string Filename, DiscoDataContext Database, string DocumentTemplateId, string DataId, string UserId, DateTime Timestamp)
|
|
||||||
{
|
|
||||||
using (FileStream fs = new FileStream(Filename, FileMode.Open, FileAccess.ReadWrite, FileShare.None))
|
|
||||||
{
|
|
||||||
DocumentUniqueIdentifier identifier = new DocumentUniqueIdentifier(DocumentTemplateId, DataId, UserId, Timestamp);
|
|
||||||
identifier.LoadComponents(Database);
|
|
||||||
return identifier.ImportPdfAttachment(Database, fs, null);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static DisposableImageCollection GetPageImages(PdfReader pdfReader, int PageNumber)
|
|
||||||
{
|
|
||||||
var pageImages = new DisposableImageCollection();
|
|
||||||
|
|
||||||
var pdfPage = pdfReader.GetPageN(PageNumber);
|
|
||||||
PdfDictionary pdfPageResouces = (PdfDictionary)((PdfDictionary)pdfPage.GetDirectObject(PdfName.RESOURCES)).GetDirectObject(PdfName.XOBJECT);
|
|
||||||
|
|
||||||
foreach (var pdfResKey in pdfPageResouces.Keys)
|
|
||||||
{
|
|
||||||
var pdfRes = pdfPageResouces.GetDirectObject(pdfResKey);
|
|
||||||
if (pdfRes.IsStream())
|
|
||||||
{
|
|
||||||
var pdfResStream = (PdfStream)pdfRes;
|
|
||||||
var pdfResSubType = pdfResStream.Get(PdfName.SUBTYPE);
|
|
||||||
if (pdfResSubType != null && pdfResSubType == PdfName.IMAGE)
|
|
||||||
{
|
|
||||||
if (pdfResStream.Get(PdfName.FILTER) == PdfName.CCITTFAXDECODE)
|
|
||||||
{ // TIFF
|
|
||||||
// Try Using GDI+ for TIFF...
|
|
||||||
var width = ((PdfNumber)(pdfResStream.Get(PdfName.WIDTH))).IntValue;
|
|
||||||
var height = ((PdfNumber)(pdfResStream.Get(PdfName.HEIGHT))).IntValue;
|
|
||||||
var bpc = ((PdfNumber)(pdfResStream.Get(PdfName.BITSPERCOMPONENT))).IntValue;
|
|
||||||
|
|
||||||
var compressionMethod = Compression.CCITTFAX3;
|
|
||||||
|
|
||||||
var decodeParams = pdfResStream.GetAsDict(PdfName.DECODEPARMS);
|
|
||||||
if (decodeParams != null && decodeParams.Contains(PdfName.K) && decodeParams.GetAsNumber(PdfName.K).IntValue < 0)
|
|
||||||
compressionMethod = Compression.CCITTFAX4;
|
|
||||||
|
|
||||||
using (MemoryStream tiffStream = PdfToTiffStream(PdfReader.GetStreamBytesRaw((PRStream)pdfResStream), width, height, bpc, compressionMethod))
|
|
||||||
{
|
|
||||||
pageImages.Add((Bitmap)Bitmap.FromStream(tiffStream));
|
|
||||||
}
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (pdfResStream.Get(PdfName.FILTER) == PdfName.DCTDECODE)
|
|
||||||
{ // JPG
|
|
||||||
using (MemoryStream jpgStream = new MemoryStream(PdfReader.GetStreamBytesRaw((PRStream)pdfResStream)))
|
|
||||||
{
|
|
||||||
pageImages.Add((Bitmap)Bitmap.FromStream(jpgStream, true, true));
|
|
||||||
}
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return pageImages;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static MemoryStream PdfToTiffStream(byte[] PdfStream, int Width, int Height, int BitsPerComponent, Compression CompressionMethod)
|
|
||||||
{
|
|
||||||
var ms = new MemoryStream();
|
|
||||||
|
|
||||||
Tiff tif = Tiff.ClientOpen("in-memory", "w", ms, new TiffStream());
|
|
||||||
tif.SetField(TiffTag.IMAGEWIDTH, Width);
|
|
||||||
tif.SetField(TiffTag.IMAGELENGTH, Height);
|
|
||||||
tif.SetField(TiffTag.COMPRESSION, CompressionMethod);
|
|
||||||
tif.SetField(TiffTag.BITSPERSAMPLE, BitsPerComponent);
|
|
||||||
tif.SetField(TiffTag.SAMPLESPERPIXEL, 1);
|
|
||||||
tif.WriteRawStrip(0, PdfStream, PdfStream.Length);
|
|
||||||
tif.Flush();
|
|
||||||
|
|
||||||
return ms;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Copyright 2012 ZXing.Net authors
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
/// <summary>
|
|
||||||
/// The base class for luminance sources which supports
|
|
||||||
/// cropping and rotating based upon the luminance values.
|
|
||||||
/// </summary>
|
|
||||||
public abstract class BaseLuminanceSource : LuminanceSource
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
///
|
|
||||||
/// </summary>
|
|
||||||
protected sbyte[] luminances;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Initializes a new instance of the <see cref="BaseLuminanceSource"/> class.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="width">The width.</param>
|
|
||||||
/// <param name="height">The height.</param>
|
|
||||||
protected BaseLuminanceSource(int width, int height)
|
|
||||||
: base(width, height)
|
|
||||||
{
|
|
||||||
luminances = new sbyte[width * height];
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Initializes a new instance of the <see cref="BaseLuminanceSource"/> class.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="luminanceArray">The luminance array.</param>
|
|
||||||
/// <param name="width">The width.</param>
|
|
||||||
/// <param name="height">The height.</param>
|
|
||||||
protected BaseLuminanceSource(sbyte[] luminanceArray, int width, int height)
|
|
||||||
: base(width, height)
|
|
||||||
{
|
|
||||||
luminances = luminanceArray;
|
|
||||||
//Buffer.BlockCopy(luminanceArray, 0, luminances, 0, width * height);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Fetches one row of luminance data from the underlying platform's bitmap. Values range from
|
|
||||||
/// 0 (black) to 255 (white). It is preferable for implementations of this method
|
|
||||||
/// to only fetch this row rather than the whole image, since no 2D Readers may be installed and
|
|
||||||
/// getMatrix() may never be called.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="y">The row to fetch, 0 <= y < Height.</param>
|
|
||||||
/// <param name="row">An optional preallocated array. If null or too small, it will be ignored.
|
|
||||||
/// Always use the returned object, and ignore the .length of the array.</param>
|
|
||||||
/// <returns>
|
|
||||||
/// An array containing the luminance data.
|
|
||||||
/// </returns>
|
|
||||||
override public sbyte[] getRow(int y, sbyte[] row)
|
|
||||||
{
|
|
||||||
int width = Width;
|
|
||||||
if (row == null || row.Length < width)
|
|
||||||
{
|
|
||||||
row = new sbyte[width];
|
|
||||||
}
|
|
||||||
//for (int i = 0; i < width; i++)
|
|
||||||
// row[i] = luminances[y * width + i];
|
|
||||||
Buffer.BlockCopy(luminances, y * width, row, 0, width);
|
|
||||||
return row;
|
|
||||||
}
|
|
||||||
|
|
||||||
public override sbyte[] Matrix
|
|
||||||
{
|
|
||||||
get { return luminances; }
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Returns a new object with rotated image data by 90 degrees counterclockwise.
|
|
||||||
/// Only callable if {@link #isRotateSupported()} is true.
|
|
||||||
/// </summary>
|
|
||||||
/// <returns>
|
|
||||||
/// A rotated version of this object.
|
|
||||||
/// </returns>
|
|
||||||
public override LuminanceSource rotateCounterClockwise()
|
|
||||||
{
|
|
||||||
var rotatedLuminances = new sbyte[Width * Height];
|
|
||||||
var newWidth = Height;
|
|
||||||
var newHeight = Width;
|
|
||||||
var localLuminances = Matrix;
|
|
||||||
for (var yold = 0; yold < Height; yold++)
|
|
||||||
{
|
|
||||||
for (var xold = 0; xold < Width; xold++)
|
|
||||||
{
|
|
||||||
var ynew = xold;
|
|
||||||
var xnew = newWidth - yold - 1;
|
|
||||||
rotatedLuminances[ynew * newWidth + xnew] = localLuminances[yold * Width + xold];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return CreateLuminanceSource(rotatedLuminances, newWidth, newHeight);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// </summary>
|
|
||||||
/// <returns> Whether this subclass supports counter-clockwise rotation.</returns>
|
|
||||||
public override bool RotateSupported
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Returns a new object with cropped image data. Implementations may keep a reference to the
|
|
||||||
/// original data rather than a copy. Only callable if CropSupported is true.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="left">The left coordinate, 0 <= left < Width.</param>
|
|
||||||
/// <param name="top">The top coordinate, 0 <= top <= Height.</param>
|
|
||||||
/// <param name="width">The width of the rectangle to crop.</param>
|
|
||||||
/// <param name="height">The height of the rectangle to crop.</param>
|
|
||||||
/// <returns>
|
|
||||||
/// A cropped version of this object.
|
|
||||||
/// </returns>
|
|
||||||
public override LuminanceSource crop(int left, int top, int width, int height)
|
|
||||||
{
|
|
||||||
if (left + width > Width || top + height > Height)
|
|
||||||
{
|
|
||||||
throw new ArgumentException("Crop rectangle does not fit within image data.");
|
|
||||||
}
|
|
||||||
var croppedLuminances = new sbyte[width * height];
|
|
||||||
for (int yold = top, ynew = 0; yold < height; yold++, ynew++)
|
|
||||||
{
|
|
||||||
for (int xold = left, xnew = 0; xold < width; xold++, xnew++)
|
|
||||||
{
|
|
||||||
croppedLuminances[ynew * width + xnew] = luminances[yold * Width + xold];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return CreateLuminanceSource(croppedLuminances, width, height);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// </summary>
|
|
||||||
/// <returns> Whether this subclass supports cropping.</returns>
|
|
||||||
public override bool CropSupported
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Should create a new luminance source with the right class type.
|
|
||||||
/// The method is used in methods crop and rotate.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="newLuminances">The new luminances.</param>
|
|
||||||
/// <param name="width">The width.</param>
|
|
||||||
/// <param name="height">The height.</param>
|
|
||||||
/// <returns></returns>
|
|
||||||
protected abstract LuminanceSource CreateLuminanceSource(sbyte[] newLuminances, int width, int height);
|
|
||||||
}
|
|
||||||
public partial class BitmapLuminanceSource : BaseLuminanceSource
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Initializes a new instance of the <see cref="BitmapLuminanceSource"/> class.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="width">The width.</param>
|
|
||||||
/// <param name="height">The height.</param>
|
|
||||||
protected BitmapLuminanceSource(int width, int height)
|
|
||||||
: base(width, height)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Initializes a new instance of the <see cref="BitmapLuminanceSource"/> class
|
|
||||||
/// with the image of a Bitmap instance
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="bitmap">The bitmap.</param>
|
|
||||||
public BitmapLuminanceSource(Bitmap bitmap)
|
|
||||||
: base(bitmap.Width, bitmap.Height)
|
|
||||||
{
|
|
||||||
var height = bitmap.Height;
|
|
||||||
var width = bitmap.Width;
|
|
||||||
|
|
||||||
// In order to measure pure decoding speed, we convert the entire image to a greyscale array
|
|
||||||
luminances = new sbyte[width * height];
|
|
||||||
|
|
||||||
// The underlying raster of image consists of bytes with the luminance values
|
|
||||||
#if WindowsCE
|
|
||||||
var data = bitmap.LockBits(new Rectangle(0, 0, width, height), ImageLockMode.ReadOnly, PixelFormat.Format24bppRgb);
|
|
||||||
#else
|
|
||||||
var data = bitmap.LockBits(new Rectangle(0, 0, width, height), ImageLockMode.ReadOnly, bitmap.PixelFormat);
|
|
||||||
#endif
|
|
||||||
try
|
|
||||||
{
|
|
||||||
var stride = Math.Abs(data.Stride);
|
|
||||||
var pixelWidth = stride / width;
|
|
||||||
|
|
||||||
if (pixelWidth > 4)
|
|
||||||
{
|
|
||||||
// old slow way for unsupported bit depth
|
|
||||||
Color c;
|
|
||||||
for (int y = 0; y < height; y++)
|
|
||||||
{
|
|
||||||
int offset = y * width;
|
|
||||||
for (int x = 0; x < width; x++)
|
|
||||||
{
|
|
||||||
c = bitmap.GetPixel(x, y);
|
|
||||||
luminances[offset + x] = (sbyte)(0.3 * c.R + 0.59 * c.G + 0.11 * c.B + 0.01);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
var strideStep = data.Stride;
|
|
||||||
var buffer = new byte[stride];
|
|
||||||
var ptrInBitmap = data.Scan0;
|
|
||||||
|
|
||||||
#if !WindowsCE
|
|
||||||
// prepare palette for 1 and 8 bit indexed bitmaps
|
|
||||||
var luminancePalette = new sbyte[bitmap.Palette.Entries.Length];
|
|
||||||
for (var index = 0; index < bitmap.Palette.Entries.Length; index++)
|
|
||||||
{
|
|
||||||
var color = bitmap.Palette.Entries[index];
|
|
||||||
luminancePalette[index] = (sbyte)(0.3 * color.R +
|
|
||||||
0.59 * color.G +
|
|
||||||
0.11 * color.B + 0.01);
|
|
||||||
}
|
|
||||||
if (bitmap.PixelFormat == PixelFormat.Format32bppArgb ||
|
|
||||||
bitmap.PixelFormat == PixelFormat.Format32bppPArgb)
|
|
||||||
{
|
|
||||||
pixelWidth = 40;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
for (int y = 0; y < height; y++)
|
|
||||||
{
|
|
||||||
// copy a scanline not the whole bitmap because of memory usage
|
|
||||||
Marshal.Copy(ptrInBitmap, buffer, 0, stride);
|
|
||||||
#if NET40
|
|
||||||
ptrInBitmap = IntPtr.Add(ptrInBitmap, strideStep);
|
|
||||||
#else
|
|
||||||
ptrInBitmap = new IntPtr(ptrInBitmap.ToInt64() + strideStep);
|
|
||||||
#endif
|
|
||||||
var offset = y * width;
|
|
||||||
switch (pixelWidth)
|
|
||||||
{
|
|
||||||
#if !WindowsCE
|
|
||||||
case 0:
|
|
||||||
for (int x = 0; x * 8 < width; x++)
|
|
||||||
{
|
|
||||||
for (int subX = 0; subX < 8 && 8 * x + subX < width; subX++)
|
|
||||||
{
|
|
||||||
var index = (buffer[x] >> (7 - subX)) & 1;
|
|
||||||
luminances[offset + 8 * x + subX] = luminancePalette[index];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case 1:
|
|
||||||
for (int x = 0; x < width; x++)
|
|
||||||
{
|
|
||||||
luminances[offset + x] = luminancePalette[buffer[x]];
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
#endif
|
|
||||||
case 2:
|
|
||||||
// should be RGB565 or RGB555, assume RGB565
|
|
||||||
{
|
|
||||||
for (int index = 0, x = 0; index < 2 * width; index += 2, x++)
|
|
||||||
{
|
|
||||||
var byte1 = buffer[index];
|
|
||||||
var byte2 = buffer[index + 1];
|
|
||||||
|
|
||||||
var b5 = byte1 & 0x1F;
|
|
||||||
var g5 = (((byte1 & 0xE0) >> 5) | ((byte2 & 0x03) << 3)) & 0x1F;
|
|
||||||
var r5 = (byte2 >> 2) & 0x1F;
|
|
||||||
var r8 = (r5 * 527 + 23) >> 6;
|
|
||||||
var g8 = (g5 * 527 + 23) >> 6;
|
|
||||||
var b8 = (b5 * 527 + 23) >> 6;
|
|
||||||
|
|
||||||
luminances[offset + x] = (sbyte)(0.3 * r8 + 0.59 * g8 + 0.11 * b8 + 0.01);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case 3:
|
|
||||||
for (int x = 0; x < width; x++)
|
|
||||||
{
|
|
||||||
var luminance = (sbyte)(0.3 * buffer[x * 3] +
|
|
||||||
0.59 * buffer[x * 3 + 1] +
|
|
||||||
0.11 * buffer[x * 3 + 2] + 0.01);
|
|
||||||
luminances[offset + x] = luminance;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case 4:
|
|
||||||
// 4 bytes without alpha channel value
|
|
||||||
for (int x = 0; x < width; x++)
|
|
||||||
{
|
|
||||||
var luminance = (sbyte)(0.30 * buffer[x * 4] +
|
|
||||||
0.59 * buffer[x * 4 + 1] +
|
|
||||||
0.11 * buffer[x * 4 + 2] + 0.01);
|
|
||||||
|
|
||||||
luminances[offset + x] = luminance;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case 40:
|
|
||||||
// with alpha channel; some barcodes are completely black if you
|
|
||||||
// only look at the r, g and b channel but the alpha channel controls
|
|
||||||
// the view
|
|
||||||
for (int x = 0; x < width; x++)
|
|
||||||
{
|
|
||||||
var luminance = (sbyte)(0.30 * buffer[x * 4] +
|
|
||||||
0.59 * buffer[x * 4 + 1] +
|
|
||||||
0.11 * buffer[x * 4 + 2] + 0.01);
|
|
||||||
|
|
||||||
// calculating the resulting luminance based upon a white background
|
|
||||||
// var alpha = buffer[x * pixelWidth + 3] / 255.0;
|
|
||||||
// luminance = (byte)(luminance * alpha + 255 * (1 - alpha));
|
|
||||||
var alpha = buffer[x * 4 + 3];
|
|
||||||
luminance = (sbyte)(((luminance * alpha) >> 8) + (255 * (255 - alpha) >> 8));
|
|
||||||
luminances[offset + x] = luminance;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
throw new NotSupportedException();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
finally
|
|
||||||
{
|
|
||||||
bitmap.UnlockBits(data);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Should create a new luminance source with the right class type.
|
|
||||||
/// The method is used in methods crop and rotate.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="newLuminances">The new luminances.</param>
|
|
||||||
/// <param name="width">The width.</param>
|
|
||||||
/// <param name="height">The height.</param>
|
|
||||||
/// <returns></returns>
|
|
||||||
protected override LuminanceSource CreateLuminanceSource(sbyte[] newLuminances, int width, int height)
|
|
||||||
{
|
|
||||||
return new BitmapLuminanceSource(width, height) { luminances = newLuminances };
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -64,9 +64,6 @@
|
|||||||
<Reference Include="Renci.SshNet">
|
<Reference Include="Renci.SshNet">
|
||||||
<HintPath>..\..\..\Resources\Libraries\SshNet\Renci.SshNet.dll</HintPath>
|
<HintPath>..\..\..\Resources\Libraries\SshNet\Renci.SshNet.dll</HintPath>
|
||||||
</Reference>
|
</Reference>
|
||||||
<Reference Include="Spring.Core">
|
|
||||||
<HintPath>..\Resources\Libraries\Spring.NET\Spring.Core.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="System" />
|
<Reference Include="System" />
|
||||||
<Reference Include="System.ComponentModel.DataAnnotations" />
|
<Reference Include="System.ComponentModel.DataAnnotations" />
|
||||||
<Reference Include="System.Core" />
|
<Reference Include="System.Core" />
|
||||||
@@ -106,33 +103,16 @@
|
|||||||
<Reference Include="Microsoft.CSharp" />
|
<Reference Include="Microsoft.CSharp" />
|
||||||
<Reference Include="System.Data" />
|
<Reference Include="System.Data" />
|
||||||
<Reference Include="System.Xml" />
|
<Reference Include="System.Xml" />
|
||||||
<Reference Include="zxing">
|
|
||||||
<HintPath>..\Resources\Libraries\ZXing\zxing.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Compile Include="BI\DataStore.cs" />
|
|
||||||
<Compile Include="BI\AttachmentBI\Utilities.cs" />
|
|
||||||
<Compile Include="BI\DeviceBI\BatchUtilities.cs" />
|
<Compile Include="BI\DeviceBI\BatchUtilities.cs" />
|
||||||
<Compile Include="BI\DeviceBI\DeviceModelBI.cs" />
|
<Compile Include="BI\DeviceBI\DeviceModelBI.cs" />
|
||||||
<Compile Include="BI\DeviceBI\Migration\LogMacAddressImporting.cs" />
|
<Compile Include="BI\DeviceBI\Migration\LogMacAddressImporting.cs" />
|
||||||
<Compile Include="BI\DisposableImageCollection.cs" />
|
<Compile Include="BI\DisposableImageCollection.cs" />
|
||||||
<Compile Include="BI\DocumentTemplateBI\DocumentTemplateQRCodeLocationCache.cs" />
|
|
||||||
<Compile Include="BI\DocumentTemplateBI\ManagedGroups\DocumentTemplateUsersManagedGroup.cs" />
|
<Compile Include="BI\DocumentTemplateBI\ManagedGroups\DocumentTemplateUsersManagedGroup.cs" />
|
||||||
<Compile Include="BI\DocumentTemplateBI\ManagedGroups\DocumentTemplateDevicesManagedGroup.cs" />
|
<Compile Include="BI\DocumentTemplateBI\ManagedGroups\DocumentTemplateDevicesManagedGroup.cs" />
|
||||||
<Compile Include="BI\DocumentTemplateBI\ManagedGroups\DocumentTemplateManagedGroups.cs" />
|
<Compile Include="BI\DocumentTemplateBI\ManagedGroups\DocumentTemplateManagedGroups.cs" />
|
||||||
<Compile Include="BI\Expressions\EvaluateExpressionParseException.cs" />
|
|
||||||
<Compile Include="BI\Expressions\ExpressionCachePreloadTask.cs" />
|
|
||||||
<Compile Include="BI\Expressions\Extensions\DataExt.cs" />
|
|
||||||
<Compile Include="BI\Expressions\Extensions\DeviceExt.cs" />
|
|
||||||
<Compile Include="BI\Expressions\Extensions\ImageExt.cs" />
|
|
||||||
<Compile Include="BI\Expressions\Extensions\ImageResultImplementations\BaseImageExpressionResult.cs" />
|
|
||||||
<Compile Include="BI\Expressions\Extensions\ImageResultImplementations\FileMontageImageExpressionResult.cs" />
|
|
||||||
<Compile Include="BI\Expressions\Extensions\ImageResultImplementations\FileImageExpressionResult.cs" />
|
|
||||||
<Compile Include="BI\Expressions\Extensions\ImageResultImplementations\BitmapImageExpressionResult.cs" />
|
|
||||||
<Compile Include="BI\Expressions\Extensions\UserExt.cs" />
|
|
||||||
<Compile Include="BI\Extensions\AttachmentActionExtensions.cs" />
|
<Compile Include="BI\Extensions\AttachmentActionExtensions.cs" />
|
||||||
<Compile Include="BI\Extensions\AttachmentExtensions.cs" />
|
|
||||||
<Compile Include="BI\Extensions\AuthorizationRoleExtensions.cs" />
|
<Compile Include="BI\Extensions\AuthorizationRoleExtensions.cs" />
|
||||||
<Compile Include="BI\Extensions\ClientServicesExtensions.cs" />
|
<Compile Include="BI\Extensions\ClientServicesExtensions.cs" />
|
||||||
<Compile Include="BI\Extensions\UserFlagActionExtensions.cs" />
|
<Compile Include="BI\Extensions\UserFlagActionExtensions.cs" />
|
||||||
@@ -154,21 +134,7 @@
|
|||||||
<Compile Include="BI\DeviceBI\EnrolmentLog.cs" />
|
<Compile Include="BI\DeviceBI\EnrolmentLog.cs" />
|
||||||
<Compile Include="BI\Extensions\DocumentTemplateExtensions.cs" />
|
<Compile Include="BI\Extensions\DocumentTemplateExtensions.cs" />
|
||||||
<Compile Include="BI\DocumentTemplateBI\Utilities.cs" />
|
<Compile Include="BI\DocumentTemplateBI\Utilities.cs" />
|
||||||
<Compile Include="BI\DocumentTemplateBI\DocumentUniqueIdentifier.cs" />
|
|
||||||
<Compile Include="BI\Expressions\EvaluateExpressionPart.cs" />
|
|
||||||
<Compile Include="BI\Expressions\Expression.cs" />
|
|
||||||
<Compile Include="BI\Expressions\ExpressionTypeDescriptor.cs" />
|
|
||||||
<Compile Include="BI\Expressions\ExpressionTypeMemberDescriptor.cs" />
|
|
||||||
<Compile Include="BI\Expressions\IExpressionPart.cs" />
|
|
||||||
<Compile Include="BI\Expressions\TextExpressionPart.cs" />
|
|
||||||
<Compile Include="BI\DocumentTemplateBI\Importer\DocumentDropBoxMonitor.cs" />
|
|
||||||
<Compile Include="BI\DocumentTemplateBI\Importer\DocumentImporterJob.cs" />
|
|
||||||
<Compile Include="BI\DocumentTemplateBI\Importer\DocumentImporterCleanCacheJob.cs" />
|
|
||||||
<Compile Include="BI\DocumentTemplateBI\DocumentsLog.cs" />
|
|
||||||
<Compile Include="BI\Expressions\ExpressionCache.cs" />
|
|
||||||
<Compile Include="BI\Interop\MimeTypes.cs" />
|
|
||||||
<Compile Include="BI\Interop\Pdf\PdfGenerator.cs" />
|
<Compile Include="BI\Interop\Pdf\PdfGenerator.cs" />
|
||||||
<Compile Include="BI\Interop\Pdf\PdfImporter.cs" />
|
|
||||||
<Compile Include="BI\JobBI\Statistics\DailyOpenedClosed.cs" />
|
<Compile Include="BI\JobBI\Statistics\DailyOpenedClosed.cs" />
|
||||||
<Compile Include="BI\JobBI\Utilities.cs" />
|
<Compile Include="BI\JobBI\Utilities.cs" />
|
||||||
<Compile Include="BI\Extensions\UtilityExtensions.cs" />
|
<Compile Include="BI\Extensions\UtilityExtensions.cs" />
|
||||||
|
|||||||
@@ -276,6 +276,22 @@ namespace Disco.Data.Configuration
|
|||||||
return this.Get<string>(null);
|
return this.Get<string>(null);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
public short DeploymentChecksum
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
var deploymentIdBytes = Guid.Parse(DeploymentId).ToByteArray();
|
||||||
|
return
|
||||||
|
(short)(BitConverter.ToInt16(deploymentIdBytes, 0) ^
|
||||||
|
BitConverter.ToInt16(deploymentIdBytes, 2) ^
|
||||||
|
BitConverter.ToInt16(deploymentIdBytes, 2) ^
|
||||||
|
BitConverter.ToInt16(deploymentIdBytes, 2) ^
|
||||||
|
BitConverter.ToInt16(deploymentIdBytes, 2) ^
|
||||||
|
BitConverter.ToInt16(deploymentIdBytes, 2) ^
|
||||||
|
BitConverter.ToInt16(deploymentIdBytes, 2) ^
|
||||||
|
BitConverter.ToInt16(deploymentIdBytes, 2));
|
||||||
|
}
|
||||||
|
}
|
||||||
public UpdateResponseV2 UpdateLastCheckResponse
|
public UpdateResponseV2 UpdateLastCheckResponse
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
|
|||||||
@@ -51,7 +51,10 @@
|
|||||||
<Compile Include="BI\Job\LocationModes.cs" />
|
<Compile Include="BI\Job\LocationModes.cs" />
|
||||||
<Compile Include="ClientServices\Register.cs" />
|
<Compile Include="ClientServices\Register.cs" />
|
||||||
<Compile Include="ClientServices\RegisterResponse.cs" />
|
<Compile Include="ClientServices\RegisterResponse.cs" />
|
||||||
|
<Compile Include="Repository\Attachment\AttachmentTypes.cs" />
|
||||||
|
<Compile Include="Repository\Attachment\IAttachmentTarget.cs" />
|
||||||
<Compile Include="Repository\Device\DeviceDecommissionReasons.cs" />
|
<Compile Include="Repository\Device\DeviceDecommissionReasons.cs" />
|
||||||
|
<Compile Include="Repository\Attachment\IAttachment.cs" />
|
||||||
<Compile Include="Repository\User\Flag\UserFlag.cs" />
|
<Compile Include="Repository\User\Flag\UserFlag.cs" />
|
||||||
<Compile Include="Repository\User\Flag\UserFlagAssignment.cs" />
|
<Compile Include="Repository\User\Flag\UserFlagAssignment.cs" />
|
||||||
<Compile Include="Services\Authorization\IAuthorizationToken.cs" />
|
<Compile Include="Services\Authorization\IAuthorizationToken.cs" />
|
||||||
@@ -60,7 +63,7 @@
|
|||||||
<Compile Include="BI\Config\OrganisationAddress.cs" />
|
<Compile Include="BI\Config\OrganisationAddress.cs" />
|
||||||
<Compile Include="BI\Device\ImportDevice.cs" />
|
<Compile Include="BI\Device\ImportDevice.cs" />
|
||||||
<Compile Include="BI\Device\ImportDeviceSession.cs" />
|
<Compile Include="BI\Device\ImportDeviceSession.cs" />
|
||||||
<Compile Include="BI\DocumentTemplate\DocumentState.cs" />
|
<Compile Include="Services\Documents\DocumentState.cs" />
|
||||||
<Compile Include="BI\Expressions\IImageExpressionResult.cs" />
|
<Compile Include="BI\Expressions\IImageExpressionResult.cs" />
|
||||||
<Compile Include="BI\Job\Statistics\DailyOpenedClosedItem.cs" />
|
<Compile Include="BI\Job\Statistics\DailyOpenedClosedItem.cs" />
|
||||||
<Compile Include="ClientServices\EnrolResponse.cs" />
|
<Compile Include="ClientServices\EnrolResponse.cs" />
|
||||||
@@ -181,7 +184,9 @@
|
|||||||
<None Include="App.config" />
|
<None Include="App.config" />
|
||||||
<None Include="packages.config" />
|
<None Include="packages.config" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup />
|
<ItemGroup>
|
||||||
|
<Folder Include="BI\DocumentTemplate\" />
|
||||||
|
</ItemGroup>
|
||||||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||||
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
|
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
|
||||||
Other similar extension points exist, see Microsoft.Common.targets.
|
Other similar extension points exist, see Microsoft.Common.targets.
|
||||||
|
|||||||
@@ -0,0 +1,9 @@
|
|||||||
|
namespace Disco.Models.Repository
|
||||||
|
{
|
||||||
|
public enum AttachmentTypes
|
||||||
|
{
|
||||||
|
Device,
|
||||||
|
Job,
|
||||||
|
User
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,24 @@
|
|||||||
|
using System;
|
||||||
|
|
||||||
|
namespace Disco.Models.Repository
|
||||||
|
{
|
||||||
|
public interface IAttachment
|
||||||
|
{
|
||||||
|
int Id { get; set; }
|
||||||
|
|
||||||
|
object Reference { get; }
|
||||||
|
|
||||||
|
string TechUserId { get; set; }
|
||||||
|
|
||||||
|
string Filename { get; set; }
|
||||||
|
string MimeType { get; set; }
|
||||||
|
|
||||||
|
DateTime Timestamp { get; set; }
|
||||||
|
|
||||||
|
string Comments { get; set; }
|
||||||
|
|
||||||
|
string DocumentTemplateId { get; set; }
|
||||||
|
|
||||||
|
AttachmentTypes AttachmentType { get; }
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
namespace Disco.Models.Repository
|
||||||
|
{
|
||||||
|
public interface IAttachmentTarget
|
||||||
|
{
|
||||||
|
string AttachmentReferenceId { get; }
|
||||||
|
|
||||||
|
AttachmentTypes HasAttachmentType { get; }
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -7,9 +7,9 @@ using System.ComponentModel.DataAnnotations.Schema;
|
|||||||
|
|
||||||
namespace Disco.Models.Repository
|
namespace Disco.Models.Repository
|
||||||
{
|
{
|
||||||
public class Device
|
public class Device : IAttachmentTarget
|
||||||
{
|
{
|
||||||
[Required(ErrorMessage="The Serial Number is Required"), Key, StringLength(60)]
|
[Required(ErrorMessage = "The Serial Number is Required"), Key, StringLength(60)]
|
||||||
public string SerialNumber { get; set; }
|
public string SerialNumber { get; set; }
|
||||||
|
|
||||||
[StringLength(40)]
|
[StringLength(40)]
|
||||||
@@ -18,7 +18,7 @@ namespace Disco.Models.Repository
|
|||||||
public string Location { get; set; }
|
public string Location { get; set; }
|
||||||
|
|
||||||
public int? DeviceModelId { get; set; }
|
public int? DeviceModelId { get; set; }
|
||||||
[Range(1, int.MaxValue, ErrorMessage="A valid Device Profile is Required")]
|
[Range(1, int.MaxValue, ErrorMessage = "A valid Device Profile is Required")]
|
||||||
public int DeviceProfileId { get; set; }
|
public int DeviceProfileId { get; set; }
|
||||||
public int? DeviceBatchId { get; set; }
|
public int? DeviceBatchId { get; set; }
|
||||||
|
|
||||||
@@ -26,7 +26,7 @@ namespace Disco.Models.Repository
|
|||||||
public string DeviceDomainId { get; set; }
|
public string DeviceDomainId { get; set; }
|
||||||
public string AssignedUserId { get; set; }
|
public string AssignedUserId { get; set; }
|
||||||
public DateTime? LastNetworkLogonDate { get; set; }
|
public DateTime? LastNetworkLogonDate { get; set; }
|
||||||
|
|
||||||
public bool AllowUnauthenticatedEnrol { get; set; }
|
public bool AllowUnauthenticatedEnrol { get; set; }
|
||||||
|
|
||||||
public DateTime CreatedDate { get; set; }
|
public DateTime CreatedDate { get; set; }
|
||||||
@@ -48,7 +48,7 @@ namespace Disco.Models.Repository
|
|||||||
public virtual IList<DeviceDetail> DeviceDetails { get; set; }
|
public virtual IList<DeviceDetail> DeviceDetails { get; set; }
|
||||||
public virtual IList<DeviceAttachment> DeviceAttachments { get; set; }
|
public virtual IList<DeviceAttachment> DeviceAttachments { get; set; }
|
||||||
public virtual IList<DeviceCertificate> DeviceCertificates { get; set; }
|
public virtual IList<DeviceCertificate> DeviceCertificates { get; set; }
|
||||||
|
|
||||||
[InverseProperty("DeviceSerialNumber")]
|
[InverseProperty("DeviceSerialNumber")]
|
||||||
public virtual IList<Job> Jobs { get; set; }
|
public virtual IList<Job> Jobs { get; set; }
|
||||||
|
|
||||||
@@ -85,5 +85,11 @@ namespace Disco.Models.Repository
|
|||||||
return index < 0 ? null : DeviceDomainId.Substring(0, index);
|
return index < 0 ? null : DeviceDomainId.Substring(0, index);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[NotMapped]
|
||||||
|
public string AttachmentReferenceId { get { return SerialNumber; } }
|
||||||
|
|
||||||
|
[NotMapped]
|
||||||
|
public AttachmentTypes HasAttachmentType { get { return AttachmentTypes.Device; } }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,13 +1,10 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
|
||||||
using System.ComponentModel.DataAnnotations;
|
using System.ComponentModel.DataAnnotations;
|
||||||
using System.ComponentModel.DataAnnotations.Schema;
|
using System.ComponentModel.DataAnnotations.Schema;
|
||||||
|
|
||||||
namespace Disco.Models.Repository
|
namespace Disco.Models.Repository
|
||||||
{
|
{
|
||||||
public class DeviceAttachment
|
public class DeviceAttachment : IAttachment
|
||||||
{
|
{
|
||||||
[Key]
|
[Key]
|
||||||
public int Id { get; set; }
|
public int Id { get; set; }
|
||||||
@@ -24,6 +21,12 @@ namespace Disco.Models.Repository
|
|||||||
|
|
||||||
public string DocumentTemplateId { get; set; }
|
public string DocumentTemplateId { get; set; }
|
||||||
|
|
||||||
|
[NotMapped]
|
||||||
|
public object Reference { get { return DeviceSerialNumber; } }
|
||||||
|
|
||||||
|
[NotMapped]
|
||||||
|
public AttachmentTypes AttachmentType { get { return AttachmentTypes.Device; } }
|
||||||
|
|
||||||
[InverseProperty("DeviceAttachments"), ForeignKey("DeviceSerialNumber")]
|
[InverseProperty("DeviceAttachments"), ForeignKey("DeviceSerialNumber")]
|
||||||
public virtual Device Device { get; set; }
|
public virtual Device Device { get; set; }
|
||||||
|
|
||||||
@@ -32,6 +35,5 @@ namespace Disco.Models.Repository
|
|||||||
|
|
||||||
[ForeignKey("DocumentTemplateId")]
|
[ForeignKey("DocumentTemplateId")]
|
||||||
public virtual DocumentTemplate DocumentTemplate { get; set; }
|
public virtual DocumentTemplate DocumentTemplate { get; set; }
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -35,6 +35,25 @@ namespace Disco.Models.Repository
|
|||||||
[InverseProperty("DocumentTemplates")]
|
[InverseProperty("DocumentTemplates")]
|
||||||
public virtual IList<JobSubType> JobSubTypes { get; set; }
|
public virtual IList<JobSubType> JobSubTypes { get; set; }
|
||||||
|
|
||||||
|
[NotMapped]
|
||||||
|
public AttachmentTypes AttachmentType
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
switch (Scope)
|
||||||
|
{
|
||||||
|
case DocumentTemplateScopes.Device:
|
||||||
|
return AttachmentTypes.Device;
|
||||||
|
case DocumentTemplateScopes.Job:
|
||||||
|
return AttachmentTypes.Job;
|
||||||
|
case DocumentTemplateScopes.User:
|
||||||
|
return AttachmentTypes.User;
|
||||||
|
default:
|
||||||
|
throw new ArgumentException("Unexpected Document Scope");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public static class DocumentTemplateScopes
|
public static class DocumentTemplateScopes
|
||||||
{
|
{
|
||||||
public const string Device = "Device";
|
public const string Device = "Device";
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ using System.ComponentModel.DataAnnotations.Schema;
|
|||||||
|
|
||||||
namespace Disco.Models.Repository
|
namespace Disco.Models.Repository
|
||||||
{
|
{
|
||||||
public class Job
|
public class Job : IAttachmentTarget
|
||||||
{
|
{
|
||||||
[Key]
|
[Key]
|
||||||
public int Id { get; set; }
|
public int Id { get; set; }
|
||||||
@@ -75,6 +75,12 @@ namespace Disco.Models.Repository
|
|||||||
public virtual JobMetaWarranty JobMetaWarranty { get; set; }
|
public virtual JobMetaWarranty JobMetaWarranty { get; set; }
|
||||||
public virtual JobMetaNonWarranty JobMetaNonWarranty { get; set; }
|
public virtual JobMetaNonWarranty JobMetaNonWarranty { get; set; }
|
||||||
|
|
||||||
|
[NotMapped]
|
||||||
|
public string AttachmentReferenceId { get { return Id.ToString(); } }
|
||||||
|
|
||||||
|
[NotMapped]
|
||||||
|
public AttachmentTypes HasAttachmentType { get { return AttachmentTypes.Job; } }
|
||||||
|
|
||||||
#region Helper Members
|
#region Helper Members
|
||||||
public decimal JobComponentsTotalCost()
|
public decimal JobComponentsTotalCost()
|
||||||
{
|
{
|
||||||
@@ -86,6 +92,11 @@ namespace Disco.Models.Repository
|
|||||||
}
|
}
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
|
public override string ToString()
|
||||||
|
{
|
||||||
|
return $"Job #{Id}";
|
||||||
|
}
|
||||||
|
|
||||||
public static class JobStatusIds
|
public static class JobStatusIds
|
||||||
{
|
{
|
||||||
public const string AwaitingAccountingPayment = "AwaitingAccountingPayment";
|
public const string AwaitingAccountingPayment = "AwaitingAccountingPayment";
|
||||||
|
|||||||
@@ -1,13 +1,10 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
|
||||||
using System.ComponentModel.DataAnnotations;
|
using System.ComponentModel.DataAnnotations;
|
||||||
using System.ComponentModel.DataAnnotations.Schema;
|
using System.ComponentModel.DataAnnotations.Schema;
|
||||||
|
|
||||||
namespace Disco.Models.Repository
|
namespace Disco.Models.Repository
|
||||||
{
|
{
|
||||||
public class JobAttachment
|
public class JobAttachment : IAttachment
|
||||||
{
|
{
|
||||||
[Key]
|
[Key]
|
||||||
public int Id { get; set; }
|
public int Id { get; set; }
|
||||||
@@ -25,6 +22,12 @@ namespace Disco.Models.Repository
|
|||||||
|
|
||||||
public string DocumentTemplateId { get; set; }
|
public string DocumentTemplateId { get; set; }
|
||||||
|
|
||||||
|
[NotMapped]
|
||||||
|
public object Reference { get { return JobId; } }
|
||||||
|
|
||||||
|
[NotMapped]
|
||||||
|
public AttachmentTypes AttachmentType { get { return AttachmentTypes.Job; } }
|
||||||
|
|
||||||
[ForeignKey("JobId"), InverseProperty("JobAttachments")]
|
[ForeignKey("JobId"), InverseProperty("JobAttachments")]
|
||||||
public virtual Job Job { get; set; }
|
public virtual Job Job { get; set; }
|
||||||
|
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ using System.ComponentModel.DataAnnotations.Schema;
|
|||||||
|
|
||||||
namespace Disco.Models.Repository
|
namespace Disco.Models.Repository
|
||||||
{
|
{
|
||||||
public class User
|
public class User : IAttachmentTarget
|
||||||
{
|
{
|
||||||
[StringLength(50), Key, Column("Id")]
|
[StringLength(50), Key, Column("Id")]
|
||||||
public string UserId { get; set; }
|
public string UserId { get; set; }
|
||||||
@@ -60,6 +60,12 @@ namespace Disco.Models.Repository
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[NotMapped]
|
||||||
|
public string AttachmentReferenceId { get { return UserId; } }
|
||||||
|
|
||||||
|
[NotMapped]
|
||||||
|
public AttachmentTypes HasAttachmentType { get { return AttachmentTypes.User; } }
|
||||||
|
|
||||||
public override string ToString()
|
public override string ToString()
|
||||||
{
|
{
|
||||||
return string.Format("{0} ({1})", this.DisplayName, this.UserId);
|
return string.Format("{0} ({1})", this.DisplayName, this.UserId);
|
||||||
|
|||||||
@@ -1,13 +1,10 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
|
||||||
using System.ComponentModel.DataAnnotations;
|
using System.ComponentModel.DataAnnotations;
|
||||||
using System.ComponentModel.DataAnnotations.Schema;
|
using System.ComponentModel.DataAnnotations.Schema;
|
||||||
|
|
||||||
namespace Disco.Models.Repository
|
namespace Disco.Models.Repository
|
||||||
{
|
{
|
||||||
public class UserAttachment
|
public class UserAttachment : IAttachment
|
||||||
{
|
{
|
||||||
[Key]
|
[Key]
|
||||||
public int Id { get; set; }
|
public int Id { get; set; }
|
||||||
@@ -24,6 +21,12 @@ namespace Disco.Models.Repository
|
|||||||
|
|
||||||
public string DocumentTemplateId { get; set; }
|
public string DocumentTemplateId { get; set; }
|
||||||
|
|
||||||
|
[NotMapped]
|
||||||
|
public object Reference { get { return UserId; } }
|
||||||
|
|
||||||
|
[NotMapped]
|
||||||
|
public AttachmentTypes AttachmentType { get { return AttachmentTypes.User; } }
|
||||||
|
|
||||||
[ForeignKey("UserId"), InverseProperty("UserAttachments")]
|
[ForeignKey("UserId"), InverseProperty("UserAttachments")]
|
||||||
public virtual User User { get; set; }
|
public virtual User User { get; set; }
|
||||||
|
|
||||||
|
|||||||
+1
-1
@@ -1,7 +1,7 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections;
|
using System.Collections;
|
||||||
|
|
||||||
namespace Disco.Models.BI.DocumentTemplates
|
namespace Disco.Models.Services.Documents
|
||||||
{
|
{
|
||||||
public class DocumentState : IDisposable
|
public class DocumentState : IDisposable
|
||||||
{
|
{
|
||||||
@@ -16,6 +16,10 @@
|
|||||||
</startup>
|
</startup>
|
||||||
<runtime>
|
<runtime>
|
||||||
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
|
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
|
||||||
|
<dependentAssembly>
|
||||||
|
<assemblyIdentity name="Common.Logging" publicKeyToken="AF08829B84F0328E" culture="neutral" />
|
||||||
|
<bindingRedirect oldVersion="0.0.0.0-2.0.0.0" newVersion="2.0.0.0" />
|
||||||
|
</dependentAssembly>
|
||||||
<dependentAssembly>
|
<dependentAssembly>
|
||||||
<assemblyIdentity name="System.Web.Mvc" publicKeyToken="31bf3856ad364e35" culture="neutral" />
|
<assemblyIdentity name="System.Web.Mvc" publicKeyToken="31bf3856ad364e35" culture="neutral" />
|
||||||
<bindingRedirect oldVersion="0.0.0.0-4.0.0.0" newVersion="4.0.0.0" />
|
<bindingRedirect oldVersion="0.0.0.0-4.0.0.0" newVersion="4.0.0.0" />
|
||||||
@@ -46,4 +50,4 @@
|
|||||||
</dependentAssembly>
|
</dependentAssembly>
|
||||||
</assemblyBinding>
|
</assemblyBinding>
|
||||||
</runtime>
|
</runtime>
|
||||||
</configuration>
|
</configuration>
|
||||||
|
|||||||
@@ -0,0 +1,195 @@
|
|||||||
|
using Disco.Data.Repository;
|
||||||
|
using Disco.Models.Repository;
|
||||||
|
using Exceptionless;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Drawing;
|
||||||
|
using System.IO;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace Disco.Services
|
||||||
|
{
|
||||||
|
public static class AttachmentActionExtensions
|
||||||
|
{
|
||||||
|
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)
|
||||||
|
{
|
||||||
|
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 = DateTime.Now,
|
||||||
|
Comments = Comments
|
||||||
|
};
|
||||||
|
|
||||||
|
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)
|
||||||
|
{
|
||||||
|
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 = DateTime.Now,
|
||||||
|
Comments = Comments
|
||||||
|
};
|
||||||
|
|
||||||
|
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)
|
||||||
|
{
|
||||||
|
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 = DateTime.Now,
|
||||||
|
Comments = Comments
|
||||||
|
};
|
||||||
|
|
||||||
|
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 string GenerateThumbnail(this IAttachment attachment, DiscoDataContext Database, Stream AttachmentStream)
|
||||||
|
{
|
||||||
|
string thumbnailFilePath = attachment.RepositoryThumbnailFilename(Database);
|
||||||
|
|
||||||
|
Image thumbnail;
|
||||||
|
if (GenerateThumbnail(AttachmentStream, attachment.MimeType, out 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)))
|
||||||
|
{
|
||||||
|
Image thumbnail;
|
||||||
|
if (GenerateThumbnail(attachmentStream, attachment.MimeType, out thumbnail))
|
||||||
|
{
|
||||||
|
thumbnail.SaveJpg(90, thumbnailFilePath);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return thumbnailFilePath;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static bool GenerateThumbnail(Stream Source, string SourceMimeType, out Image Thumbnail)
|
||||||
|
{
|
||||||
|
if (Source != null)
|
||||||
|
{
|
||||||
|
// GDI+ (jpg, png, gif, bmp)
|
||||||
|
if (SourceMimeType.Equals("image/jpeg", StringComparison.OrdinalIgnoreCase) || SourceMimeType.Contains("jpg") ||
|
||||||
|
SourceMimeType.Equals("image/png", StringComparison.OrdinalIgnoreCase) || SourceMimeType.Contains("png") ||
|
||||||
|
SourceMimeType.Equals("image/gif", StringComparison.OrdinalIgnoreCase) || SourceMimeType.Contains("gif") ||
|
||||||
|
SourceMimeType.Equals("image/bmp", StringComparison.OrdinalIgnoreCase) || SourceMimeType.Contains("bmp"))
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
using (Image sourceImage = Image.FromStream(Source))
|
||||||
|
{
|
||||||
|
Thumbnail = sourceImage.ResizeImage(48, 48);
|
||||||
|
using (Image mimeTypeIcon = Disco.Services.Properties.Resources.MimeType_img16)
|
||||||
|
{
|
||||||
|
Thumbnail.EmbedIconOverlay(mimeTypeIcon);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
ex.ToExceptionless().Submit();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// PDF
|
||||||
|
if (SourceMimeType.Equals("application/pdf", StringComparison.OrdinalIgnoreCase) || SourceMimeType.Contains("pdf"))
|
||||||
|
{
|
||||||
|
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);
|
||||||
|
|
||||||
|
Thumbnail = pdfiumDocument.Render(0, (int)size.Width, (int)size.Height, 72, 72, true);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
ex.ToExceptionless().Submit();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Thumbnail = null;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,89 @@
|
|||||||
|
using Disco.Data.Repository;
|
||||||
|
using Disco.Models.Repository;
|
||||||
|
using System;
|
||||||
|
using System.Drawing;
|
||||||
|
using System.IO;
|
||||||
|
|
||||||
|
namespace Disco.Services
|
||||||
|
{
|
||||||
|
public static class AttachmentDataStoreExtensions
|
||||||
|
{
|
||||||
|
|
||||||
|
public static string RepositoryFilename(this IAttachment Attachment, DiscoDataContext Database)
|
||||||
|
{
|
||||||
|
switch (Attachment.AttachmentType)
|
||||||
|
{
|
||||||
|
case AttachmentTypes.Device:
|
||||||
|
return Path.Combine(DataStore.CreateLocation(Database, "DeviceAttachments", Attachment.Timestamp),
|
||||||
|
string.Format("{0}_{1}_file", Attachment.Reference, Attachment.Id));
|
||||||
|
case AttachmentTypes.Job:
|
||||||
|
return Path.Combine(DataStore.CreateLocation(Database, "JobAttachments", Attachment.Timestamp),
|
||||||
|
string.Format("{0}_{1}_file", Attachment.Reference, Attachment.Id));
|
||||||
|
case AttachmentTypes.User:
|
||||||
|
return Path.Combine(DataStore.CreateLocation(Database, "UserAttachments", Attachment.Timestamp),
|
||||||
|
string.Format("{0}_{1}_file", ((string)Attachment.Reference).Replace('\\', '_'), Attachment.Id));
|
||||||
|
default:
|
||||||
|
throw new ArgumentException("Unknown Attachment Type", nameof(Attachment));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static string RepositoryThumbnailFilename(this IAttachment Attachment, DiscoDataContext Database)
|
||||||
|
{
|
||||||
|
switch (Attachment.AttachmentType)
|
||||||
|
{
|
||||||
|
case AttachmentTypes.Device:
|
||||||
|
return Path.Combine(DataStore.CreateLocation(Database, "DeviceAttachments", Attachment.Timestamp),
|
||||||
|
string.Format("{0}_{1}_thumb.jpg", Attachment.Reference, Attachment.Id));
|
||||||
|
case AttachmentTypes.Job:
|
||||||
|
return Path.Combine(DataStore.CreateLocation(Database, "JobAttachments", Attachment.Timestamp),
|
||||||
|
string.Format("{0}_{1}_thumb.jpg", Attachment.Reference, Attachment.Id));
|
||||||
|
case AttachmentTypes.User:
|
||||||
|
return Path.Combine(DataStore.CreateLocation(Database, "UserAttachments", Attachment.Timestamp),
|
||||||
|
string.Format("{0}_{1}_thumb.jpg", ((string)Attachment.Reference).Replace('\\', '_'), Attachment.Id));
|
||||||
|
default:
|
||||||
|
throw new ArgumentException("Unknown Attachment Type", nameof(Attachment));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static string SaveAttachment(this IAttachment Attachment, DiscoDataContext Database, Stream FileContent)
|
||||||
|
{
|
||||||
|
string filePath = Attachment.RepositoryFilename(Database);
|
||||||
|
DataStore.WriteFile(filePath, FileContent);
|
||||||
|
return filePath;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static string SaveAttachment(this IAttachment Attachment, DiscoDataContext Database, byte[] FileContent)
|
||||||
|
{
|
||||||
|
string filePath = Attachment.RepositoryFilename(Database);
|
||||||
|
DataStore.WriteFile(filePath, FileContent);
|
||||||
|
return filePath;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static string SaveThumbnailAttachment(this IAttachment Attachment, DiscoDataContext Database, Image Thumbnail)
|
||||||
|
{
|
||||||
|
string filePath = Attachment.RepositoryThumbnailFilename(Database);
|
||||||
|
Thumbnail.SaveJpg(90, filePath);
|
||||||
|
return filePath;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static string SaveThumbnailAttachment(this IAttachment Attachment, DiscoDataContext Database, Stream FileContent)
|
||||||
|
{
|
||||||
|
string filePath = Attachment.RepositoryThumbnailFilename(Database);
|
||||||
|
DataStore.WriteFile(filePath, FileContent);
|
||||||
|
return filePath;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static string SaveThumbnailAttachment(this IAttachment Attachment, DiscoDataContext Database, byte[] FileContent)
|
||||||
|
{
|
||||||
|
string filePath = Attachment.RepositoryThumbnailFilename(Database);
|
||||||
|
DataStore.WriteFile(filePath, FileContent);
|
||||||
|
return filePath;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void RepositoryDelete(this IAttachment Attachment, DiscoDataContext Database)
|
||||||
|
{
|
||||||
|
DataStore.DeleteFiles(Attachment.RepositoryFilename(Database), Attachment.RepositoryThumbnailFilename(Database));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,11 +1,9 @@
|
|||||||
using System;
|
using Disco.Data.Configuration;
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
|
||||||
using Disco.Data.Repository;
|
using Disco.Data.Repository;
|
||||||
using Disco.Data.Configuration;
|
using System;
|
||||||
|
using System.IO;
|
||||||
|
|
||||||
namespace Disco.BI
|
namespace Disco.Services
|
||||||
{
|
{
|
||||||
public static class DataStore
|
public static class DataStore
|
||||||
{
|
{
|
||||||
@@ -14,6 +12,7 @@ namespace Disco.BI
|
|||||||
{
|
{
|
||||||
return CreateLocation(Database.DiscoConfiguration, SubLocation, SubSubLocationTimestamp);
|
return CreateLocation(Database.DiscoConfiguration, SubLocation, SubSubLocationTimestamp);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static string CreateLocation(SystemConfiguration DiscoConfiguration, string SubLocation, DateTime? SubSubLocationTimestamp = null)
|
public static string CreateLocation(SystemConfiguration DiscoConfiguration, string SubLocation, DateTime? SubSubLocationTimestamp = null)
|
||||||
{
|
{
|
||||||
string SubSubLocation = string.Empty;
|
string SubSubLocation = string.Empty;
|
||||||
@@ -27,5 +26,32 @@ namespace Disco.BI
|
|||||||
return storeDirectory;
|
return storeDirectory;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static void DeleteFile(string FilePath)
|
||||||
|
{
|
||||||
|
if (File.Exists(FilePath))
|
||||||
|
File.Delete(FilePath);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void DeleteFiles(params string[] FilePaths)
|
||||||
|
{
|
||||||
|
foreach (string filePath in FilePaths)
|
||||||
|
{
|
||||||
|
DeleteFile(filePath);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void WriteFile(string FilePath, Stream FileContent)
|
||||||
|
{
|
||||||
|
using (FileStream outStream = new FileStream(FilePath, FileMode.Create, FileAccess.Write, FileShare.None))
|
||||||
|
{
|
||||||
|
FileContent.CopyTo(outStream);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void WriteFile(string FilePath, byte[] FileContent)
|
||||||
|
{
|
||||||
|
File.WriteAllBytes(FilePath, FileContent);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,71 @@
|
|||||||
|
using Disco.Models.Repository;
|
||||||
|
using System;
|
||||||
|
using System.Drawing;
|
||||||
|
using System.IO;
|
||||||
|
|
||||||
|
namespace Disco.Services
|
||||||
|
{
|
||||||
|
public static class DeviceDataStoreExtensions
|
||||||
|
{
|
||||||
|
public static bool ImageImport(this DeviceModel deviceModel, Stream ImageStream)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
using (Bitmap inputBitmap = new Bitmap(ImageStream))
|
||||||
|
{
|
||||||
|
using (Image outputBitmap = inputBitmap.ResizeImage(256, 256))
|
||||||
|
{
|
||||||
|
using (MemoryStream ms = new MemoryStream())
|
||||||
|
{
|
||||||
|
outputBitmap.SavePng(ms);
|
||||||
|
ms.Position = 0;
|
||||||
|
|
||||||
|
var deviceModelImagePath = deviceModel.ImageFilePath();
|
||||||
|
|
||||||
|
|
||||||
|
using (var storeStream = new FileStream(deviceModelImagePath, FileMode.Create, FileAccess.Write, FileShare.None))
|
||||||
|
{
|
||||||
|
ms.CopyTo(storeStream);
|
||||||
|
}
|
||||||
|
//deviceModel.Image = ms.ToArray();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
catch (Exception)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static FileStream Image(this DeviceModel deviceModel)
|
||||||
|
{
|
||||||
|
var deviceModelImagePath = deviceModel.ImageFilePath();
|
||||||
|
|
||||||
|
if (File.Exists(deviceModelImagePath))
|
||||||
|
return new FileStream(deviceModelImagePath, FileMode.Open, FileAccess.Read, FileShare.Read);
|
||||||
|
else
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static string ImageFilePath(this DeviceModel deviceModel)
|
||||||
|
{
|
||||||
|
var configCache = new Disco.Data.Configuration.SystemConfiguration(null);
|
||||||
|
|
||||||
|
var deviceModelImagesDataStore = DataStore.CreateLocation(configCache, "DeviceModelImages");
|
||||||
|
|
||||||
|
return Path.Combine(deviceModelImagesDataStore, string.Format("{0}.png", deviceModel.Id));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static string ImageHash(this DeviceModel deviceModel)
|
||||||
|
{
|
||||||
|
var deviceModelImagePath = deviceModel.ImageFilePath();
|
||||||
|
|
||||||
|
if (File.Exists(deviceModelImagePath))
|
||||||
|
return File.GetLastWriteTimeUtc(deviceModelImagePath).ToBinary().ToString();
|
||||||
|
else
|
||||||
|
return "-1";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -70,6 +70,18 @@
|
|||||||
<Reference Include="Owin">
|
<Reference Include="Owin">
|
||||||
<HintPath>..\packages\Owin.1.0\lib\net40\Owin.dll</HintPath>
|
<HintPath>..\packages\Owin.1.0\lib\net40\Owin.dll</HintPath>
|
||||||
</Reference>
|
</Reference>
|
||||||
|
<Reference Include="PdfiumViewer, Version=2.10.0.0, Culture=neutral, PublicKeyToken=91e4789cfb0609e0, processorArchitecture=MSIL">
|
||||||
|
<HintPath>..\packages\PdfiumViewer.2.10.0.0\lib\net20\PdfiumViewer.dll</HintPath>
|
||||||
|
<Private>True</Private>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="PdfSharp, Version=1.32.3057.0, Culture=neutral, PublicKeyToken=f94615aa0424f9eb, processorArchitecture=MSIL">
|
||||||
|
<HintPath>..\packages\PDFsharp.1.32.3057.0\lib\net20\PdfSharp.dll</HintPath>
|
||||||
|
<Private>True</Private>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="PdfSharp.Charting, Version=1.32.3057.0, Culture=neutral, PublicKeyToken=f94615aa0424f9eb, processorArchitecture=MSIL">
|
||||||
|
<HintPath>..\packages\PDFsharp.1.32.3057.0\lib\net20\PdfSharp.Charting.dll</HintPath>
|
||||||
|
<Private>True</Private>
|
||||||
|
</Reference>
|
||||||
<Reference Include="Quartz">
|
<Reference Include="Quartz">
|
||||||
<HintPath>..\Resources\Libraries\Quartz\Quartz.dll</HintPath>
|
<HintPath>..\Resources\Libraries\Quartz\Quartz.dll</HintPath>
|
||||||
</Reference>
|
</Reference>
|
||||||
@@ -77,6 +89,9 @@
|
|||||||
<SpecificVersion>False</SpecificVersion>
|
<SpecificVersion>False</SpecificVersion>
|
||||||
<HintPath>..\packages\RazorGenerator.Mvc.2.2.3\lib\net40\RazorGenerator.Mvc.dll</HintPath>
|
<HintPath>..\packages\RazorGenerator.Mvc.2.2.3\lib\net40\RazorGenerator.Mvc.dll</HintPath>
|
||||||
</Reference>
|
</Reference>
|
||||||
|
<Reference Include="Spring.Core">
|
||||||
|
<HintPath>..\..\..\Resources\Libraries\Spring.NET\Spring.Core.dll</HintPath>
|
||||||
|
</Reference>
|
||||||
<Reference Include="System" />
|
<Reference Include="System" />
|
||||||
<Reference Include="System.ComponentModel.DataAnnotations" />
|
<Reference Include="System.ComponentModel.DataAnnotations" />
|
||||||
<Reference Include="System.Core" />
|
<Reference Include="System.Core" />
|
||||||
@@ -86,6 +101,7 @@
|
|||||||
<HintPath>..\packages\Microsoft.SqlServer.Compact.4.0.8876.1\lib\net40\System.Data.SqlServerCe.dll</HintPath>
|
<HintPath>..\packages\Microsoft.SqlServer.Compact.4.0.8876.1\lib\net40\System.Data.SqlServerCe.dll</HintPath>
|
||||||
</Reference>
|
</Reference>
|
||||||
<Reference Include="System.DirectoryServices" />
|
<Reference Include="System.DirectoryServices" />
|
||||||
|
<Reference Include="System.Drawing" />
|
||||||
<Reference Include="System.IO.Compression" />
|
<Reference Include="System.IO.Compression" />
|
||||||
<Reference Include="System.Net.Http" />
|
<Reference Include="System.Net.Http" />
|
||||||
<Reference Include="System.Net.Http.Extensions">
|
<Reference Include="System.Net.Http.Extensions">
|
||||||
@@ -146,9 +162,19 @@
|
|||||||
<SpecificVersion>False</SpecificVersion>
|
<SpecificVersion>False</SpecificVersion>
|
||||||
<HintPath>..\packages\WebActivatorEx.2.0.5\lib\net40\WebActivatorEx.dll</HintPath>
|
<HintPath>..\packages\WebActivatorEx.2.0.5\lib\net40\WebActivatorEx.dll</HintPath>
|
||||||
</Reference>
|
</Reference>
|
||||||
|
<Reference Include="zxing, Version=0.14.0.0, Culture=neutral, PublicKeyToken=4e88037ac681fe60, processorArchitecture=MSIL">
|
||||||
|
<HintPath>..\packages\ZXing.Net.0.14.0.1\lib\net40\zxing.dll</HintPath>
|
||||||
|
<Private>True</Private>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="zxing.presentation, Version=0.14.0.0, Culture=neutral, PublicKeyToken=4e88037ac681fe60, processorArchitecture=MSIL">
|
||||||
|
<HintPath>..\packages\ZXing.Net.0.14.0.1\lib\net40\zxing.presentation.dll</HintPath>
|
||||||
|
<Private>True</Private>
|
||||||
|
</Reference>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Compile Include="App_Start\RazorGeneratorMvcStart.cs" />
|
<Compile Include="App_Start\RazorGeneratorMvcStart.cs" />
|
||||||
|
<Compile Include="Attachments\AttachmentActionExtensions.cs" />
|
||||||
|
<Compile Include="Attachments\AttachmentDataStoreExtensions.cs" />
|
||||||
<Compile Include="Authorization\AccessDeniedException.cs" />
|
<Compile Include="Authorization\AccessDeniedException.cs" />
|
||||||
<Compile Include="Authorization\AuthorizationLog.cs" />
|
<Compile Include="Authorization\AuthorizationLog.cs" />
|
||||||
<Compile Include="Authorization\AuthorizationToken.cs" />
|
<Compile Include="Authorization\AuthorizationToken.cs" />
|
||||||
@@ -194,6 +220,8 @@
|
|||||||
<Compile Include="Authorization\Roles\RoleCache.cs" />
|
<Compile Include="Authorization\Roles\RoleCache.cs" />
|
||||||
<Compile Include="Authorization\Roles\RoleClaims.cs" />
|
<Compile Include="Authorization\Roles\RoleClaims.cs" />
|
||||||
<Compile Include="Authorization\Roles\RoleToken.cs" />
|
<Compile Include="Authorization\Roles\RoleToken.cs" />
|
||||||
|
<Compile Include="DataStore.cs" />
|
||||||
|
<Compile Include="Devices\DeviceDataStoreExtensions.cs" />
|
||||||
<Compile Include="Devices\Exporting\DeviceExport.cs" />
|
<Compile Include="Devices\Exporting\DeviceExport.cs" />
|
||||||
<Compile Include="Devices\Exporting\DeviceExportTask.cs" />
|
<Compile Include="Devices\Exporting\DeviceExportTask.cs" />
|
||||||
<Compile Include="Devices\Exporting\DeviceExportTaskContext.cs" />
|
<Compile Include="Devices\Exporting\DeviceExportTaskContext.cs" />
|
||||||
@@ -227,8 +255,37 @@
|
|||||||
<Compile Include="Devices\ManagedGroups\DeviceManagedGroups.cs" />
|
<Compile Include="Devices\ManagedGroups\DeviceManagedGroups.cs" />
|
||||||
<Compile Include="Devices\ManagedGroups\DeviceProfileAssignedUsersManagedGroup.cs" />
|
<Compile Include="Devices\ManagedGroups\DeviceProfileAssignedUsersManagedGroup.cs" />
|
||||||
<Compile Include="Devices\ManagedGroups\DeviceProfileDevicesManagedGroup.cs" />
|
<Compile Include="Devices\ManagedGroups\DeviceProfileDevicesManagedGroup.cs" />
|
||||||
|
<Compile Include="Documents\AttachmentImport\Importer.cs" />
|
||||||
|
<Compile Include="Documents\AttachmentImport\ImporterCleanCacheJob.cs" />
|
||||||
|
<Compile Include="Documents\AttachmentImport\ImporterJob.cs" />
|
||||||
|
<Compile Include="Documents\AttachmentImport\ImportDirectoryMonitor.cs" />
|
||||||
|
<Compile Include="Documents\AttachmentImport\ImportPage.cs" />
|
||||||
|
<Compile Include="Documents\DocumentsLog.cs" />
|
||||||
|
<Compile Include="Documents\DocumentTemplateActionExtensions.cs" />
|
||||||
|
<Compile Include="Documents\DocumentTemplateDataStoreExtensions.cs" />
|
||||||
|
<Compile Include="Documents\DocumentTemplateExpressionExtensions.cs" />
|
||||||
|
<Compile Include="Documents\DocumentUniqueIdentifier.cs" />
|
||||||
|
<Compile Include="Documents\DocumentUniqueIdentifierExtensions.cs" />
|
||||||
|
<Compile Include="Expressions\EvaluateExpressionParseException.cs" />
|
||||||
|
<Compile Include="Expressions\EvaluateExpressionPart.cs" />
|
||||||
|
<Compile Include="Expressions\Expression.cs" />
|
||||||
|
<Compile Include="Expressions\ExpressionCache.cs" />
|
||||||
|
<Compile Include="Expressions\ExpressionCachePreloadTask.cs" />
|
||||||
|
<Compile Include="Expressions\ExpressionTypeDescriptor.cs" />
|
||||||
|
<Compile Include="Expressions\ExpressionTypeMemberDescriptor.cs" />
|
||||||
|
<Compile Include="Expressions\Extensions\DataExt.cs" />
|
||||||
|
<Compile Include="Expressions\Extensions\DeviceExt.cs" />
|
||||||
|
<Compile Include="Expressions\Extensions\ImageExt.cs" />
|
||||||
|
<Compile Include="Expressions\Extensions\ImageResultImplementations\BaseImageExpressionResult.cs" />
|
||||||
|
<Compile Include="Expressions\Extensions\ImageResultImplementations\BitmapImageExpressionResult.cs" />
|
||||||
|
<Compile Include="Expressions\Extensions\ImageResultImplementations\FileImageExpressionResult.cs" />
|
||||||
|
<Compile Include="Expressions\Extensions\ImageResultImplementations\FileMontageImageExpressionResult.cs" />
|
||||||
|
<Compile Include="Expressions\Extensions\UserExt.cs" />
|
||||||
|
<Compile Include="Expressions\IExpressionPart.cs" />
|
||||||
|
<Compile Include="Expressions\TextExpressionPart.cs" />
|
||||||
<Compile Include="Extensions\DateTimeExtensions.cs" />
|
<Compile Include="Extensions\DateTimeExtensions.cs" />
|
||||||
<Compile Include="Extensions\EnumerableExtensions.cs" />
|
<Compile Include="Extensions\EnumerableExtensions.cs" />
|
||||||
|
<Compile Include="Extensions\ImagingExtensions.cs" />
|
||||||
<Compile Include="Extensions\RxExtensions.cs" />
|
<Compile Include="Extensions\RxExtensions.cs" />
|
||||||
<Compile Include="Extensions\StringExtensions.cs" />
|
<Compile Include="Extensions\StringExtensions.cs" />
|
||||||
<Compile Include="Extensions\UIHelpers.cs" />
|
<Compile Include="Extensions\UIHelpers.cs" />
|
||||||
@@ -257,6 +314,7 @@
|
|||||||
<Compile Include="Interop\DiscoServices\Jobs.cs" />
|
<Compile Include="Interop\DiscoServices\Jobs.cs" />
|
||||||
<Compile Include="Interop\DiscoServices\PluginLibrary.cs" />
|
<Compile Include="Interop\DiscoServices\PluginLibrary.cs" />
|
||||||
<Compile Include="Interop\DiscoServices\PluginLibraryUpdateTask.cs" />
|
<Compile Include="Interop\DiscoServices\PluginLibraryUpdateTask.cs" />
|
||||||
|
<Compile Include="Interop\MimeTypes.cs" />
|
||||||
<Compile Include="Interop\VicEduDept\VicSmart.cs" />
|
<Compile Include="Interop\VicEduDept\VicSmart.cs" />
|
||||||
<Compile Include="Interop\DiscoServices\UpdateQuery.cs" />
|
<Compile Include="Interop\DiscoServices\UpdateQuery.cs" />
|
||||||
<Compile Include="Interop\DiscoServices\UpdateQueryTask.cs" />
|
<Compile Include="Interop\DiscoServices\UpdateQueryTask.cs" />
|
||||||
@@ -322,6 +380,11 @@
|
|||||||
<Compile Include="Plugins\PluginWebViewPage.cs" />
|
<Compile Include="Plugins\PluginWebViewPage.cs" />
|
||||||
<Compile Include="Plugins\WebPageHelper.cs" />
|
<Compile Include="Plugins\WebPageHelper.cs" />
|
||||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||||
|
<Compile Include="Properties\Resources.Designer.cs">
|
||||||
|
<AutoGen>True</AutoGen>
|
||||||
|
<DesignTime>True</DesignTime>
|
||||||
|
<DependentUpon>Resources.resx</DependentUpon>
|
||||||
|
</Compile>
|
||||||
<Compile Include="Searching\Search.cs" />
|
<Compile Include="Searching\Search.cs" />
|
||||||
<Compile Include="Tasks\IScheduledTaskStatus.cs" />
|
<Compile Include="Tasks\IScheduledTaskStatus.cs" />
|
||||||
<Compile Include="Tasks\ScheduledTask.cs" />
|
<Compile Include="Tasks\ScheduledTask.cs" />
|
||||||
@@ -383,7 +446,25 @@
|
|||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Service Include="{508349B6-6B84-4DF5-91F0-309BEEBAD82D}" />
|
<Service Include="{508349B6-6B84-4DF5-91F0-309BEEBAD82D}" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup />
|
<ItemGroup>
|
||||||
|
<None Include="Resources\MimeType-doc48.png" />
|
||||||
|
<None Include="Resources\MimeType-img16.png" />
|
||||||
|
<None Include="Resources\MimeType-pdf16.png" />
|
||||||
|
<None Include="Resources\MimeType-pdf48.png" />
|
||||||
|
<None Include="Resources\MimeType-unknown48.png" />
|
||||||
|
<Content Include="x64\pdfium.dll">
|
||||||
|
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||||
|
</Content>
|
||||||
|
<Content Include="x86\pdfium.dll">
|
||||||
|
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||||
|
</Content>
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<EmbeddedResource Include="Properties\Resources.resx">
|
||||||
|
<Generator>ResXFileCodeGenerator</Generator>
|
||||||
|
<LastGenOutput>Resources.Designer.cs</LastGenOutput>
|
||||||
|
</EmbeddedResource>
|
||||||
|
</ItemGroup>
|
||||||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<PostBuildEvent>
|
<PostBuildEvent>
|
||||||
|
|||||||
@@ -0,0 +1,92 @@
|
|||||||
|
using Quartz;
|
||||||
|
using Quartz.Impl;
|
||||||
|
using Quartz.Impl.Triggers;
|
||||||
|
using System;
|
||||||
|
using System.IO;
|
||||||
|
|
||||||
|
namespace Disco.Services.Documents.AttachmentImport
|
||||||
|
{
|
||||||
|
public class ImportDirectoryMonitor : IDisposable
|
||||||
|
{
|
||||||
|
private FileSystemWatcher watcher;
|
||||||
|
|
||||||
|
public const string WatcherFilter = "*.pdf";
|
||||||
|
public string MonitorLocation { get; private set; }
|
||||||
|
public IScheduler Scheduler { get; private set; }
|
||||||
|
public int ImportDelay { get; private set; }
|
||||||
|
|
||||||
|
public ImportDirectoryMonitor(string MonitorLocation, IScheduler Scheduler, int ImportDelay)
|
||||||
|
{
|
||||||
|
if (MonitorLocation == null)
|
||||||
|
throw new ArgumentNullException(nameof(MonitorLocation));
|
||||||
|
if (Scheduler == null)
|
||||||
|
throw new ArgumentNullException(nameof(Scheduler));
|
||||||
|
|
||||||
|
this.MonitorLocation = MonitorLocation.EndsWith(@"\") ? MonitorLocation : $@"{MonitorLocation}\";
|
||||||
|
this.Scheduler = Scheduler;
|
||||||
|
this.ImportDelay = Math.Max(0, ImportDelay);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Start()
|
||||||
|
{
|
||||||
|
if (watcher == null)
|
||||||
|
{
|
||||||
|
if (!Directory.Exists(MonitorLocation))
|
||||||
|
{
|
||||||
|
Directory.CreateDirectory(MonitorLocation);
|
||||||
|
}
|
||||||
|
|
||||||
|
watcher = new FileSystemWatcher(MonitorLocation, WatcherFilter);
|
||||||
|
watcher.Created += OnFileCreated;
|
||||||
|
}
|
||||||
|
|
||||||
|
watcher.EnableRaisingEvents = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Stop()
|
||||||
|
{
|
||||||
|
if (watcher != null)
|
||||||
|
{
|
||||||
|
watcher.EnableRaisingEvents = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnFileCreated(object sender, FileSystemEventArgs e)
|
||||||
|
{
|
||||||
|
if (!e.ChangeType.HasFlag(WatcherChangeTypes.Deleted))
|
||||||
|
{
|
||||||
|
ScheduleImport(e.FullPath, ImportDelay);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ScheduleImport(string Filename, int ImportDelay)
|
||||||
|
{
|
||||||
|
var startTime = new DateTimeOffset(DateTime.Now.AddMilliseconds(ImportDelay));
|
||||||
|
var jobTrigger = new SimpleTriggerImpl(Guid.NewGuid().ToString(), startTime);
|
||||||
|
|
||||||
|
var jobDetails = new JobDetailImpl(Guid.NewGuid().ToString(), typeof(ImporterJob));
|
||||||
|
jobDetails.JobDataMap.Add("Filename", Filename);
|
||||||
|
jobDetails.JobDataMap.Add("RetryCount", 0);
|
||||||
|
|
||||||
|
Scheduler.ScheduleJob(jobDetails, jobTrigger);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void ScheduleCurrentFiles(int ImportDelay)
|
||||||
|
{
|
||||||
|
foreach (var filename in Directory.GetFiles(this.MonitorLocation, "*.pdf"))
|
||||||
|
{
|
||||||
|
ScheduleImport(filename, ImportDelay);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Dispose()
|
||||||
|
{
|
||||||
|
if (watcher != null)
|
||||||
|
{
|
||||||
|
watcher.EnableRaisingEvents = false;
|
||||||
|
watcher.Dispose();
|
||||||
|
watcher = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,317 @@
|
|||||||
|
using Disco.Data.Repository;
|
||||||
|
using PdfiumViewer;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Drawing;
|
||||||
|
using System.Drawing.Drawing2D;
|
||||||
|
using System.IO;
|
||||||
|
using System.Linq;
|
||||||
|
using ZXing;
|
||||||
|
using ZXing.Common;
|
||||||
|
using ZXing.Multi.QrCode;
|
||||||
|
|
||||||
|
namespace Disco.Services.Documents.AttachmentImport
|
||||||
|
{
|
||||||
|
internal class ImportPage : IDisposable
|
||||||
|
{
|
||||||
|
public DiscoDataContext Database { get; private set; }
|
||||||
|
public string SessionId { get; private set; }
|
||||||
|
public PdfDocument PdfiumDocument { get; private set; }
|
||||||
|
public int PageIndex { get; private set; }
|
||||||
|
|
||||||
|
public DocumentUniqueIdentifier Identifier { get; private set; }
|
||||||
|
|
||||||
|
private Result qrCodeResult;
|
||||||
|
private float qrCodeResultScale;
|
||||||
|
private Image renderedImage;
|
||||||
|
private Bitmap renderedThumbnail;
|
||||||
|
private RotateFlipType detectedRotation;
|
||||||
|
|
||||||
|
public ImportPage(DiscoDataContext Database, string SessionId, PdfDocument PdfiumDocument, int PageIndex)
|
||||||
|
{
|
||||||
|
this.Database = Database;
|
||||||
|
this.SessionId = SessionId;
|
||||||
|
this.PdfiumDocument = PdfiumDocument;
|
||||||
|
this.PageIndex = PageIndex;
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool IsDetected
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return Identifier != null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public Image Image
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return GetRenderedImage();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public Bitmap Thumbnail
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return GetRenderedThumbnail();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool IsValidAttachment
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return Identifier != null &&
|
||||||
|
Identifier.Creator != null &&
|
||||||
|
Identifier.Target != null &&
|
||||||
|
(Identifier.DocumentTemplate != null || Identifier.AttachmentType.HasValue);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public int Rotation
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
switch (detectedRotation)
|
||||||
|
{
|
||||||
|
case RotateFlipType.Rotate90FlipNone:
|
||||||
|
return 90;
|
||||||
|
case RotateFlipType.Rotate180FlipNone:
|
||||||
|
return 180;
|
||||||
|
case RotateFlipType.Rotate270FlipNone:
|
||||||
|
return 270;
|
||||||
|
default:
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void WriteThumbnailSessionCache()
|
||||||
|
{
|
||||||
|
var sessionCacheLocation = DataStore.CreateLocation(Database, "Cache\\DocumentDropBox_SessionPages");
|
||||||
|
var filename = Path.Combine(sessionCacheLocation, $"{SessionId}-{PageIndex + 1}");
|
||||||
|
|
||||||
|
Thumbnail.SavePng(filename);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void WriteUndetectedImages()
|
||||||
|
{
|
||||||
|
var undetectedLocation = DataStore.CreateLocation(Database, "DocumentDropBox_Unassigned");
|
||||||
|
var filename = Path.Combine(undetectedLocation, $"{SessionId}_{PageIndex + 1}_thumbnail.png");
|
||||||
|
Thumbnail.SavePng(filename);
|
||||||
|
|
||||||
|
using (var largePreview = Image.ResizeImage(700, 700))
|
||||||
|
{
|
||||||
|
filename = Path.Combine(undetectedLocation, $"{SessionId}_{PageIndex + 1}.jpg");
|
||||||
|
largePreview.SaveJpg(90, filename);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool DetectQRCode()
|
||||||
|
{
|
||||||
|
var qrReader = new QRCodeMultiReader();
|
||||||
|
|
||||||
|
var qrReaderHints = new Dictionary<DecodeHintType, object>() {
|
||||||
|
{ DecodeHintType.TRY_HARDER, true }
|
||||||
|
};
|
||||||
|
|
||||||
|
var qrImageSource = new BitmapLuminanceSource((Bitmap)Image);
|
||||||
|
|
||||||
|
var qrBinarizer = new HybridBinarizer(qrImageSource);
|
||||||
|
var qrBinaryBitmap = new BinaryBitmap(qrBinarizer);
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
qrCodeResult = qrReader.decodeMultiple(qrBinaryBitmap, qrReaderHints)?.FirstOrDefault();
|
||||||
|
qrCodeResultScale = 1F;
|
||||||
|
}
|
||||||
|
catch (ReaderException)
|
||||||
|
{
|
||||||
|
// QR Detection Failed
|
||||||
|
qrCodeResult = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (qrCodeResult == null)
|
||||||
|
{
|
||||||
|
var sizePoints = PdfiumDocument.PageSizes[PageIndex];
|
||||||
|
|
||||||
|
// Try at 175%
|
||||||
|
using (var image = PdfiumDocument.Render(PageIndex, (int)(sizePoints.Width * 1.75), (int)(sizePoints.Height * 1.75), 72F, 72F, false))
|
||||||
|
{
|
||||||
|
qrImageSource = new BitmapLuminanceSource((Bitmap)image);
|
||||||
|
|
||||||
|
// Try Entire Image
|
||||||
|
qrBinarizer = new HybridBinarizer(qrImageSource);
|
||||||
|
qrBinaryBitmap = new BinaryBitmap(qrBinarizer);
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
qrCodeResult = qrReader.decodeMultiple(qrBinaryBitmap, qrReaderHints)?.FirstOrDefault();
|
||||||
|
qrCodeResultScale = 1.75F;
|
||||||
|
}
|
||||||
|
catch (ReaderException)
|
||||||
|
{
|
||||||
|
// QR Detection Failed
|
||||||
|
qrCodeResult = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (qrCodeResult == null)
|
||||||
|
{
|
||||||
|
// Try at 200%
|
||||||
|
using (var image = PdfiumDocument.Render(PageIndex, (int)(sizePoints.Width * 2), (int)(sizePoints.Height * 2), 72F, 72F, false))
|
||||||
|
{
|
||||||
|
qrImageSource = new BitmapLuminanceSource((Bitmap)image);
|
||||||
|
|
||||||
|
// Try Entire Image
|
||||||
|
qrBinarizer = new HybridBinarizer(qrImageSource);
|
||||||
|
qrBinaryBitmap = new BinaryBitmap(qrBinarizer);
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
qrCodeResult = qrReader.decodeMultiple(qrBinaryBitmap, qrReaderHints)?.FirstOrDefault();
|
||||||
|
qrCodeResultScale = 2F;
|
||||||
|
}
|
||||||
|
catch (ReaderException)
|
||||||
|
{
|
||||||
|
// QR Detection Failed
|
||||||
|
qrCodeResult = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (qrCodeResult != null)
|
||||||
|
{
|
||||||
|
// Detect Rotation
|
||||||
|
var rotationAngle = Math.Atan2(
|
||||||
|
qrCodeResult.ResultPoints[2].Y - qrCodeResult.ResultPoints[1].Y,
|
||||||
|
qrCodeResult.ResultPoints[2].X - qrCodeResult.ResultPoints[1].X) * 180 / Math.PI;
|
||||||
|
if (rotationAngle <= 45 || rotationAngle > 315)
|
||||||
|
{
|
||||||
|
detectedRotation = RotateFlipType.RotateNoneFlipNone;
|
||||||
|
}
|
||||||
|
else if (rotationAngle <= 135)
|
||||||
|
{
|
||||||
|
detectedRotation = RotateFlipType.Rotate270FlipNone;
|
||||||
|
}
|
||||||
|
else if (rotationAngle <= 225)
|
||||||
|
{
|
||||||
|
detectedRotation = RotateFlipType.Rotate180FlipNone;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
detectedRotation = RotateFlipType.Rotate90FlipNone;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Reset Thumbnail
|
||||||
|
if (renderedThumbnail != null)
|
||||||
|
{
|
||||||
|
renderedThumbnail.Dispose();
|
||||||
|
renderedThumbnail = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Try binary encoding (from v2)
|
||||||
|
if (qrCodeResult.ResultMetadata.ContainsKey(ResultMetadataType.BYTE_SEGMENTS))
|
||||||
|
{
|
||||||
|
var byteSegments = (List<byte[]>)qrCodeResult.ResultMetadata[ResultMetadataType.BYTE_SEGMENTS];
|
||||||
|
var qrBytes = byteSegments[0];
|
||||||
|
if (DocumentUniqueIdentifier.IsDocumentUniqueIdentifier(qrBytes))
|
||||||
|
{
|
||||||
|
Identifier = DocumentUniqueIdentifier.Parse(Database, qrBytes);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Fall back to v1
|
||||||
|
if (Identifier == null)
|
||||||
|
{
|
||||||
|
Identifier = DocumentUniqueIdentifier.Parse(Database, qrCodeResult.Text);
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Bitmap GetAttachmentThumbnail()
|
||||||
|
{
|
||||||
|
var thumbnail = renderedImage.ResizeImage(48, 48, Brushes.White);
|
||||||
|
|
||||||
|
// Draw Rotation
|
||||||
|
if (detectedRotation != RotateFlipType.RotateNoneFlipNone)
|
||||||
|
{
|
||||||
|
thumbnail.RotateFlip(detectedRotation);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add PDF Icon overlay
|
||||||
|
using (Image mimeTypeIcon = Disco.Services.Properties.Resources.MimeType_pdf16)
|
||||||
|
{
|
||||||
|
thumbnail.EmbedIconOverlay(mimeTypeIcon);
|
||||||
|
}
|
||||||
|
|
||||||
|
return thumbnail;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Image GetRenderedImage()
|
||||||
|
{
|
||||||
|
if (renderedImage == null)
|
||||||
|
{
|
||||||
|
var pageSize = PdfiumDocument.PageSizes[PageIndex];
|
||||||
|
|
||||||
|
renderedImage = PdfiumDocument.Render(PageIndex, (int)pageSize.Width, (int)pageSize.Height, 72F, 72F, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
return renderedImage;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Bitmap GetRenderedThumbnail()
|
||||||
|
{
|
||||||
|
if (renderedThumbnail == null)
|
||||||
|
{
|
||||||
|
renderedThumbnail = GetRenderedImage().ResizeImage(256, 256, Brushes.White);
|
||||||
|
|
||||||
|
if (qrCodeResult != null && qrCodeResult.ResultPoints.Length == 4)
|
||||||
|
{
|
||||||
|
float thumbnailScale;
|
||||||
|
var thumbnailOffset = renderedImage.CalculateResize(renderedThumbnail.Width, renderedThumbnail.Height, out thumbnailScale);
|
||||||
|
thumbnailScale = thumbnailScale / qrCodeResultScale;
|
||||||
|
|
||||||
|
using (Graphics thumbnailGraphics = Graphics.FromImage(renderedThumbnail))
|
||||||
|
{
|
||||||
|
// Draw Square on QR Code
|
||||||
|
var linePoints = qrCodeResult.ResultPoints.Select(p => new Point((int)(thumbnailOffset.X + (p.X * thumbnailScale)), (int)(thumbnailOffset.Y + (p.Y * thumbnailScale)))).ToList();
|
||||||
|
using (GraphicsPath graphicsPath = new GraphicsPath())
|
||||||
|
{
|
||||||
|
for (int linePointIndex = 0; linePointIndex < (linePoints.Count - 1); linePointIndex++)
|
||||||
|
graphicsPath.AddLine(linePoints[linePointIndex], linePoints[linePointIndex + 1]);
|
||||||
|
|
||||||
|
graphicsPath.AddLine(linePoints[linePoints.Count - 1], linePoints[0]);
|
||||||
|
|
||||||
|
using (SolidBrush graphicsBrush = new SolidBrush(Color.FromArgb(128, 255, 0, 0)))
|
||||||
|
thumbnailGraphics.FillPath(graphicsBrush, graphicsPath);
|
||||||
|
|
||||||
|
using (Pen graphicsPen = new Pen(Color.FromArgb(200, 255, 0, 0), 2))
|
||||||
|
thumbnailGraphics.DrawPath(graphicsPen, graphicsPath);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Draw Rotation
|
||||||
|
if (detectedRotation != RotateFlipType.RotateNoneFlipNone)
|
||||||
|
{
|
||||||
|
renderedThumbnail.RotateFlip(detectedRotation);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return renderedThumbnail;
|
||||||
|
}
|
||||||
|
public void Dispose()
|
||||||
|
{
|
||||||
|
if (renderedImage != null)
|
||||||
|
renderedImage.Dispose();
|
||||||
|
if (renderedThumbnail != null)
|
||||||
|
renderedThumbnail.Dispose();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,244 @@
|
|||||||
|
using Disco.Data.Repository;
|
||||||
|
using Disco.Models.Repository;
|
||||||
|
using Disco.Services.Logging;
|
||||||
|
using Disco.Services.Users;
|
||||||
|
using PdfSharp.Pdf;
|
||||||
|
using PdfSharp.Pdf.IO;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Drawing;
|
||||||
|
using System.IO;
|
||||||
|
using System.Linq;
|
||||||
|
|
||||||
|
namespace Disco.Services.Documents.AttachmentImport
|
||||||
|
{
|
||||||
|
public static class Importer
|
||||||
|
{
|
||||||
|
public static void Import(DiscoDataContext Database, string SessionId, string Filename)
|
||||||
|
{
|
||||||
|
var dataStoreUnassignedLocation = DataStore.CreateLocation(Database, "DocumentDropBox_Unassigned");
|
||||||
|
var dataStoreSessionPagesCacheLocation = DataStore.CreateLocation(Database, "Cache\\DocumentDropBox_SessionPages");
|
||||||
|
var documentTemplates = Database.DocumentTemplates.ToArray();
|
||||||
|
|
||||||
|
if (!File.Exists(Filename))
|
||||||
|
{
|
||||||
|
DocumentsLog.LogImportWarning(SessionId, string.Format("File not found: {0}", Filename));
|
||||||
|
throw new FileNotFoundException("Document Not Found", Filename);
|
||||||
|
}
|
||||||
|
|
||||||
|
DocumentsLog.LogImportProgress(SessionId, 0, "Reading File");
|
||||||
|
|
||||||
|
List<ImportPage> pages = null;
|
||||||
|
List<ImportPage> assignedPages;
|
||||||
|
double progressInterval;
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
// Use Pdfium to Rasterize and Detect Pages
|
||||||
|
using (var importFileStream = new FileStream(Filename, FileMode.Open, FileAccess.ReadWrite, FileShare.None))
|
||||||
|
{
|
||||||
|
using (var pdfiumDocument = PdfiumViewer.PdfDocument.Load(importFileStream))
|
||||||
|
{
|
||||||
|
progressInterval = 70D / pdfiumDocument.PageCount;
|
||||||
|
pages = new List<ImportPage>(pdfiumDocument.PageCount);
|
||||||
|
assignedPages = new List<ImportPage>(pdfiumDocument.PageCount);
|
||||||
|
|
||||||
|
// Rasterize and Detect Pages
|
||||||
|
for (int pageIndex = 0; pageIndex < pdfiumDocument.PageCount; pageIndex++)
|
||||||
|
{
|
||||||
|
var pageNumber = pageIndex + 1;
|
||||||
|
|
||||||
|
DocumentsLog.LogImportProgress(SessionId, (int)(pageIndex * progressInterval), $"Processing Page {pageNumber} of {pdfiumDocument.PageCount}");
|
||||||
|
DocumentsLog.LogImportPageStarting(SessionId, pageNumber);
|
||||||
|
|
||||||
|
var page = new ImportPage(Database, SessionId, pdfiumDocument, pageIndex);
|
||||||
|
pages.Add(page);
|
||||||
|
|
||||||
|
// Write Session Thumbnail
|
||||||
|
page.WriteThumbnailSessionCache();
|
||||||
|
DocumentsLog.LogImportPageImageUpdate(SessionId, pageNumber);
|
||||||
|
|
||||||
|
// Detect Image
|
||||||
|
if (page.DetectQRCode())
|
||||||
|
{
|
||||||
|
// Write updated session thumbnail
|
||||||
|
page.WriteThumbnailSessionCache();
|
||||||
|
DocumentsLog.LogImportPageImageUpdate(SessionId, pageNumber);
|
||||||
|
var identifier = page.Identifier;
|
||||||
|
DocumentsLog.LogImportPageDetected(SessionId, pageNumber, identifier.DocumentTemplateId, identifier.DocumentTemplate.Description, identifier.DocumentTemplate.Scope, identifier.TargetId, identifier.Target.ToString());
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
page.WriteUndetectedImages();
|
||||||
|
DocumentsLog.LogImportPageUndetected(SessionId, pageNumber);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Use PdfSharp to Import and Build Documents
|
||||||
|
using (var importFileStream = new FileStream(Filename, FileMode.Open, FileAccess.ReadWrite, FileShare.None))
|
||||||
|
{
|
||||||
|
using (var pdfSharpDocument = PdfReader.Open(importFileStream, PdfDocumentOpenMode.Import))
|
||||||
|
{
|
||||||
|
// Assign Pages
|
||||||
|
var documents = pages
|
||||||
|
.Where(p => p.IsValidAttachment)
|
||||||
|
.GroupBy(p => p.Identifier.DocumentGroupingId)
|
||||||
|
.ToList();
|
||||||
|
|
||||||
|
if (documents.Count > 0)
|
||||||
|
{
|
||||||
|
progressInterval = 20D / documents.Count;
|
||||||
|
|
||||||
|
foreach (var document in documents)
|
||||||
|
{
|
||||||
|
var documentPages = document.OrderBy(p => p.Identifier.PageIndex).ToList();
|
||||||
|
var documentPageFirst = documentPages.First();
|
||||||
|
|
||||||
|
DocumentsLog.LogImportProgress(SessionId, (int)(70D + (documents.IndexOf(document) * progressInterval)), $"Importing Documents {documents.IndexOf(document) + 1} of {documents.Count}");
|
||||||
|
|
||||||
|
using (MemoryStream msBuilder = new MemoryStream())
|
||||||
|
{
|
||||||
|
using (var pdfSharpDocumentOutput = new PdfDocument())
|
||||||
|
{
|
||||||
|
foreach (var documentPage in documentPages)
|
||||||
|
{
|
||||||
|
var pdfSharpImportPage = pdfSharpDocument.Pages[documentPage.PageIndex];
|
||||||
|
var importedPage = pdfSharpDocumentOutput.AddPage(pdfSharpImportPage);
|
||||||
|
|
||||||
|
importedPage.Rotate = documentPage.Rotation;
|
||||||
|
}
|
||||||
|
|
||||||
|
pdfSharpDocumentOutput.Save(msBuilder, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
msBuilder.Position = 0;
|
||||||
|
using (var attachmentThumbnail = documentPageFirst.GetAttachmentThumbnail())
|
||||||
|
{
|
||||||
|
documentPageFirst.Identifier.ImportPdfAttachment(Database, msBuilder, attachmentThumbnail);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Write Unassigned Pages
|
||||||
|
var unassignedPages = pages
|
||||||
|
.Where(p => !p.IsValidAttachment)
|
||||||
|
.ToList();
|
||||||
|
|
||||||
|
if (unassignedPages.Count > 0)
|
||||||
|
{
|
||||||
|
progressInterval = 10D / unassignedPages.Count;
|
||||||
|
|
||||||
|
foreach (var documentPage in unassignedPages)
|
||||||
|
{
|
||||||
|
DocumentsLog.LogImportProgress(SessionId, (int)(90 + (unassignedPages.IndexOf(documentPage) * progressInterval)), string.Format("Processing Undetected Pages {0} of {1}", unassignedPages.IndexOf(documentPage) + 1, unassignedPages.Count));
|
||||||
|
|
||||||
|
using (var pdfSharpDocumentOutput = new PdfDocument())
|
||||||
|
{
|
||||||
|
var pdfSharpImportPage = pdfSharpDocument.Pages[documentPage.PageIndex];
|
||||||
|
pdfSharpDocumentOutput.AddPage(pdfSharpImportPage);
|
||||||
|
|
||||||
|
var filename = Path.Combine(dataStoreUnassignedLocation, $"{SessionId}_{documentPage.PageIndex + 1}.pdf");
|
||||||
|
|
||||||
|
pdfSharpDocumentOutput.Save(filename);
|
||||||
|
|
||||||
|
DocumentsLog.LogImportPageUndetectedStored(SessionId, documentPage.PageIndex + 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
// Dispose of pages
|
||||||
|
if (pages != null && pages.Count != 0)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < pages.Count; i++)
|
||||||
|
{
|
||||||
|
pages[i].Dispose();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static bool ImportPdfAttachment(this DocumentUniqueIdentifier Identifier, DiscoDataContext Database, string PdfFilename)
|
||||||
|
{
|
||||||
|
return ImportPdfAttachment(Identifier, Database, PdfFilename, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static bool ImportPdfAttachment(this DocumentUniqueIdentifier Identifier, DiscoDataContext Database, string PdfFilename, Image Thumbnail)
|
||||||
|
{
|
||||||
|
using (var pdfStream = File.OpenRead(PdfFilename))
|
||||||
|
{
|
||||||
|
return ImportPdfAttachment(Identifier, Database, pdfStream, Thumbnail);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static bool ImportPdfAttachment(this DocumentUniqueIdentifier Identifier, DiscoDataContext Database, Stream PdfContent)
|
||||||
|
{
|
||||||
|
return ImportPdfAttachment(Identifier, Database, PdfContent, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static bool ImportPdfAttachment(this DocumentUniqueIdentifier Identifier, DiscoDataContext Database, Stream PdfContent, Image Thumbnail)
|
||||||
|
{
|
||||||
|
string filename;
|
||||||
|
string comments;
|
||||||
|
IAttachment attachment;
|
||||||
|
|
||||||
|
if (Identifier.DocumentTemplate == null)
|
||||||
|
{
|
||||||
|
filename = $"{Identifier.Target.AttachmentReferenceId.Replace('\\', '_')}_{Identifier.TimeStamp:yyyyMMdd-HHmmss}.pdf";
|
||||||
|
comments = $"Uploaded: {Identifier.TimeStamp:s}";
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
filename = $"{Identifier.DocumentTemplateId}_{Identifier.TimeStamp:yyyyMMdd-HHmmss}.pdf";
|
||||||
|
comments = string.Format("Generated: {0:s}", Identifier.TimeStamp);
|
||||||
|
}
|
||||||
|
|
||||||
|
User creatorUser = UserService.GetUser(Identifier.CreatorId, Database);
|
||||||
|
if (creatorUser == null)
|
||||||
|
{
|
||||||
|
// No Creator User (or Username invalid)
|
||||||
|
creatorUser = UserService.CurrentUser;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (Identifier.AttachmentType)
|
||||||
|
{
|
||||||
|
case AttachmentTypes.Device:
|
||||||
|
Device d = (Device)Identifier.Target;
|
||||||
|
attachment = d.CreateAttachment(Database, creatorUser, filename, DocumentTemplate.PdfMimeType, comments, PdfContent, Identifier.DocumentTemplate, Thumbnail);
|
||||||
|
break;
|
||||||
|
case AttachmentTypes.Job:
|
||||||
|
Job j = (Job)Identifier.Target;
|
||||||
|
attachment = j.CreateAttachment(Database, creatorUser, filename, DocumentTemplate.PdfMimeType, comments, PdfContent, Identifier.DocumentTemplate, Thumbnail);
|
||||||
|
break;
|
||||||
|
case AttachmentTypes.User:
|
||||||
|
User u = (User)Identifier.Target;
|
||||||
|
attachment = u.CreateAttachment(Database, creatorUser, filename, DocumentTemplate.PdfMimeType, comments, PdfContent, Identifier.DocumentTemplate, Thumbnail);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Identifier.DocumentTemplate != null && !string.IsNullOrWhiteSpace(Identifier.DocumentTemplate.OnImportAttachmentExpression))
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var expressionResult = Identifier.DocumentTemplate.EvaluateOnAttachmentImportExpression(attachment, Database, creatorUser, Identifier.TimeStamp);
|
||||||
|
DocumentsLog.LogImportAttachmentExpressionEvaluated(Identifier.DocumentTemplate, Identifier.Target, attachment, expressionResult);
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
SystemLog.LogException("Document Importer - OnImportAttachmentExpression", ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
+13
-15
@@ -1,19 +1,20 @@
|
|||||||
using Disco.Data.Repository;
|
using Disco.Data.Repository;
|
||||||
using Disco.Services.Logging;
|
using Disco.Services.Logging;
|
||||||
using Quartz;
|
|
||||||
using Quartz.Impl;
|
|
||||||
using Disco.Services.Tasks;
|
using Disco.Services.Tasks;
|
||||||
|
using Quartz;
|
||||||
|
using System;
|
||||||
|
using System.IO;
|
||||||
|
|
||||||
namespace Disco.BI.DocumentTemplateBI.Importer
|
namespace Disco.Services.Documents.AttachmentImport
|
||||||
{
|
{
|
||||||
public class DocumentImporterCleanCacheJob : ScheduledTask
|
public class ImporterCleanCacheJob : ScheduledTask
|
||||||
{
|
{
|
||||||
public override string TaskName { get { return "Document Importer - Clean Cache Task"; } }
|
public override string TaskName { get { return "Document Importer - Clean Cache Task"; } }
|
||||||
|
|
||||||
public override bool SingleInstanceTask { get { return true; } }
|
public override bool SingleInstanceTask { get { return true; } }
|
||||||
public override bool CancelInitiallySupported { get { return false; } }
|
public override bool CancelInitiallySupported { get { return false; } }
|
||||||
public override bool LogExceptionsOnly { get { return true; } }
|
public override bool LogExceptionsOnly { get { return true; } }
|
||||||
|
|
||||||
public override void InitalizeScheduledTask(DiscoDataContext Database)
|
public override void InitalizeScheduledTask(DiscoDataContext Database)
|
||||||
{
|
{
|
||||||
// Trigger Daily @ 12:30am
|
// Trigger Daily @ 12:30am
|
||||||
@@ -27,21 +28,19 @@ namespace Disco.BI.DocumentTemplateBI.Importer
|
|||||||
string dataStoreLocation;
|
string dataStoreLocation;
|
||||||
using (DiscoDataContext database = new DiscoDataContext())
|
using (DiscoDataContext database = new DiscoDataContext())
|
||||||
{
|
{
|
||||||
dataStoreLocation = DataStore.CreateLocation(database, "Cache\\DocumentDropBox_SessionPages");
|
dataStoreLocation = DataStore.CreateLocation(database, @"Cache\DocumentDropBox_SessionPages");
|
||||||
}
|
}
|
||||||
|
|
||||||
int deleteCount = 0;
|
int deleteCount = 0;
|
||||||
int errorCount = 0;
|
int errorCount = 0;
|
||||||
|
|
||||||
System.IO.DirectoryInfo dataStoreInfo = new System.IO.DirectoryInfo(dataStoreLocation);
|
var dataStoreInfo = new DirectoryInfo(dataStoreLocation);
|
||||||
|
|
||||||
System.DateTime today = System.DateTime.Today;
|
foreach (var file in dataStoreInfo.GetFiles())
|
||||||
|
|
||||||
foreach (System.IO.FileInfo file in dataStoreInfo.GetFiles())
|
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
if (file.CreationTime < today)
|
if (file.CreationTime < DateTime.Today)
|
||||||
{
|
{
|
||||||
file.Delete();
|
file.Delete();
|
||||||
deleteCount++;
|
deleteCount++;
|
||||||
@@ -54,11 +53,10 @@ namespace Disco.BI.DocumentTemplateBI.Importer
|
|||||||
}
|
}
|
||||||
|
|
||||||
SystemLog.LogInformation(
|
SystemLog.LogInformation(
|
||||||
string.Format("Cleared DocumentDropBox_SessionPages Cache, Deleted {0} File/s, with {1} Error/s", deleteCount, errorCount),
|
$"Cleared DocumentDropBox_SessionPages Cache, Deleted {deleteCount} File/s, with {errorCount} Error/s",
|
||||||
deleteCount,
|
deleteCount,
|
||||||
errorCount
|
errorCount
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,92 @@
|
|||||||
|
using Disco.Data.Repository;
|
||||||
|
using Exceptionless;
|
||||||
|
using Quartz;
|
||||||
|
using Quartz.Impl.Triggers;
|
||||||
|
using System;
|
||||||
|
using System.IO;
|
||||||
|
|
||||||
|
namespace Disco.Services.Documents.AttachmentImport
|
||||||
|
{
|
||||||
|
[PersistJobDataAfterExecution]
|
||||||
|
public class ImporterJob : IJob
|
||||||
|
{
|
||||||
|
public void Execute(IJobExecutionContext context)
|
||||||
|
{
|
||||||
|
var sessionId = context.JobDetail.JobDataMap["SessionId"] as string;
|
||||||
|
if (sessionId == null)
|
||||||
|
{
|
||||||
|
sessionId = Guid.NewGuid().ToString();
|
||||||
|
context.JobDetail.JobDataMap["SessionId"] = sessionId;
|
||||||
|
}
|
||||||
|
|
||||||
|
var filename = context.JobDetail.JobDataMap["Filename"] as string;
|
||||||
|
var retryCount = (int)context.JobDetail.JobDataMap["RetryCount"];
|
||||||
|
|
||||||
|
using (DiscoDataContext database = new DiscoDataContext())
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
DocumentsLog.LogImportStarting(sessionId, Path.GetFileName(filename));
|
||||||
|
|
||||||
|
// Returns null if unrecoverable error (eg. Not matched document)
|
||||||
|
Importer.Import(database, sessionId, filename);
|
||||||
|
|
||||||
|
// Success - Delete File
|
||||||
|
if (File.Exists(filename))
|
||||||
|
File.Delete(filename);
|
||||||
|
|
||||||
|
DocumentsLog.LogImportFinished(sessionId);
|
||||||
|
|
||||||
|
// All Done - Delete job
|
||||||
|
context.Scheduler.DeleteJob(context.JobDetail.Key);
|
||||||
|
}
|
||||||
|
catch (FileNotFoundException)
|
||||||
|
{
|
||||||
|
// File not found - Delete job and don't reschedule
|
||||||
|
context.Scheduler.DeleteJob(context.JobDetail.Key);
|
||||||
|
DocumentsLog.LogImportFinished(sessionId);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
ex.ToExceptionless().Submit();
|
||||||
|
|
||||||
|
// Retry 18 times (for 3 minutes)
|
||||||
|
if (retryCount < 18)
|
||||||
|
{
|
||||||
|
context.JobDetail.JobDataMap["RetryCount"] = ++retryCount;
|
||||||
|
DocumentsLog.LogImportWarning(sessionId, string.Format("{0}; Will try again in 10 Seconds", ex.Message));
|
||||||
|
// Reschedule Job for 10 seconds
|
||||||
|
var trig = new SimpleTriggerImpl(Guid.NewGuid().ToString(), new DateTimeOffset(DateTime.Now.AddSeconds(10)));
|
||||||
|
context.Scheduler.RescheduleJob(context.Trigger.Key, trig);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// To Many Errors
|
||||||
|
DocumentsLog.LogImportError(sessionId, $"To many errors occurred trying to import (SessionId: {sessionId})");
|
||||||
|
// Move to Errors Folder
|
||||||
|
if (File.Exists(filename))
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var folderError = DataStore.CreateLocation(database, "DocumentDropBox_Errors");
|
||||||
|
var filenameError = Path.Combine(folderError, Path.GetFileName(filename));
|
||||||
|
var filenameErrorCount = 0;
|
||||||
|
while (File.Exists(filenameError))
|
||||||
|
{
|
||||||
|
filenameError = Path.Combine(folderError, $"{Path.GetFileNameWithoutExtension(filename)} ({++filenameErrorCount}){Path.GetExtension(filename)}");
|
||||||
|
}
|
||||||
|
File.Move(filename, filenameError);
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
// Ignore Errors
|
||||||
|
}
|
||||||
|
}
|
||||||
|
DocumentsLog.LogImportFinished(sessionId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace Disco.Services
|
||||||
|
{
|
||||||
|
public static class DocumentTemplateActionExtensions
|
||||||
|
{
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,24 @@
|
|||||||
|
using Disco.Data.Repository;
|
||||||
|
using Disco.Models.Repository;
|
||||||
|
using System.IO;
|
||||||
|
|
||||||
|
namespace Disco.Services
|
||||||
|
{
|
||||||
|
public static class DocumentTemplateDataStoreExtensions
|
||||||
|
{
|
||||||
|
public static string RepositoryFilename(this DocumentTemplate dt, DiscoDataContext Database)
|
||||||
|
{
|
||||||
|
return Path.Combine(DataStore.CreateLocation(Database, "DocumentTemplates"), string.Format("{0}.pdf", dt.Id));
|
||||||
|
}
|
||||||
|
public static string SavePdfTemplate(this DocumentTemplate dt, DiscoDataContext Database, Stream TemplateFile)
|
||||||
|
{
|
||||||
|
string filePath = dt.RepositoryFilename(Database);
|
||||||
|
using (FileStream fs = new FileStream(filePath, FileMode.Create, FileAccess.Write))
|
||||||
|
{
|
||||||
|
TemplateFile.CopyTo(fs);
|
||||||
|
}
|
||||||
|
Expressions.ExpressionCache.InvalidModule(string.Format(DocumentTemplateExpressionExtensions.CacheTemplate, dt.Id));
|
||||||
|
return filePath;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,111 @@
|
|||||||
|
using Disco.Data.Repository;
|
||||||
|
using Disco.Models.Repository;
|
||||||
|
using Disco.Models.Services.Documents;
|
||||||
|
using Disco.Services.Expressions;
|
||||||
|
using System;
|
||||||
|
|
||||||
|
namespace Disco.Services
|
||||||
|
{
|
||||||
|
public static class DocumentTemplateExpressionExtensions
|
||||||
|
{
|
||||||
|
internal const string CacheTemplate = "DocumentTemplate_{0}";
|
||||||
|
|
||||||
|
public static Expression FilterExpressionFromCache(this DocumentTemplate dt)
|
||||||
|
{
|
||||||
|
return ExpressionCache.GetValue("DocumentTemplate_FilterExpression", dt.Id, () => { return Expression.TokenizeSingleDynamic(null, dt.FilterExpression, 0); });
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void FilterExpressionInvalidateCache(this DocumentTemplate dt)
|
||||||
|
{
|
||||||
|
ExpressionCache.InvalidateKey("DocumentTemplate_FilterExpression", dt.Id);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static bool FilterExpressionMatches(this DocumentTemplate dt, object Data, DiscoDataContext Database, User User, System.DateTime TimeStamp, DocumentState State)
|
||||||
|
{
|
||||||
|
if (!string.IsNullOrEmpty(dt.FilterExpression))
|
||||||
|
{
|
||||||
|
Expression compiledExpression = dt.FilterExpressionFromCache();
|
||||||
|
System.Collections.IDictionary evaluatorVariables = Expression.StandardVariables(dt, Database, User, TimeStamp, State);
|
||||||
|
try
|
||||||
|
{
|
||||||
|
object er = compiledExpression.EvaluateFirst<object>(Data, evaluatorVariables);
|
||||||
|
if (er is bool)
|
||||||
|
{
|
||||||
|
return (bool)er;
|
||||||
|
}
|
||||||
|
bool erBool;
|
||||||
|
if (bool.TryParse(er.ToString(), out erBool))
|
||||||
|
{
|
||||||
|
return erBool;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Expression OnImportAttachmentExpressionFromCache(this DocumentTemplate dt)
|
||||||
|
{
|
||||||
|
return ExpressionCache.GetValue("DocumentTemplate_OnImportExpression", dt.Id, () => { return Expression.TokenizeSingleDynamic(null, dt.OnImportAttachmentExpression, 0); });
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void OnImportAttachmentExpressionInvalidateCache(this DocumentTemplate dt)
|
||||||
|
{
|
||||||
|
ExpressionCache.InvalidateKey("DocumentTemplate_OnImportExpression", dt.Id);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static string EvaluateOnAttachmentImportExpression(this DocumentTemplate dt, object Data, DiscoDataContext Database, User User, DateTime TimeStamp)
|
||||||
|
{
|
||||||
|
if (!string.IsNullOrEmpty(dt.OnImportAttachmentExpression))
|
||||||
|
{
|
||||||
|
Expression compiledExpression = dt.OnImportAttachmentExpressionFromCache();
|
||||||
|
System.Collections.IDictionary evaluatorVariables = Expression.StandardVariables(dt, Database, User, TimeStamp, null);
|
||||||
|
try
|
||||||
|
{
|
||||||
|
object result = compiledExpression.EvaluateFirst<object>(Data, evaluatorVariables);
|
||||||
|
if (result == null)
|
||||||
|
return null;
|
||||||
|
else
|
||||||
|
return result.ToString();
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Expression OnGenerateExpressionFromCache(this DocumentTemplate dt)
|
||||||
|
{
|
||||||
|
return ExpressionCache.GetValue("DocumentTemplate_OnGenerateExpression", dt.Id, () => { return Expression.TokenizeSingleDynamic(null, dt.OnGenerateExpression, 0); });
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void OnGenerateExpressionInvalidateCache(this DocumentTemplate dt)
|
||||||
|
{
|
||||||
|
ExpressionCache.InvalidateKey("DocumentTemplate_OnGenerateExpression", dt.Id);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static string EvaluateOnGenerateExpression(this DocumentTemplate dt, object Data, DiscoDataContext Database, User User, DateTime TimeStamp, DocumentState State)
|
||||||
|
{
|
||||||
|
if (!string.IsNullOrEmpty(dt.OnGenerateExpression))
|
||||||
|
{
|
||||||
|
Expression compiledExpression = dt.OnGenerateExpressionFromCache();
|
||||||
|
System.Collections.IDictionary evaluatorVariables = Expression.StandardVariables(dt, Database, User, TimeStamp, State);
|
||||||
|
try
|
||||||
|
{
|
||||||
|
object result = compiledExpression.EvaluateFirst<object>(Data, evaluatorVariables);
|
||||||
|
return result.ToString();
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,425 @@
|
|||||||
|
using Disco.Data.Repository;
|
||||||
|
using Disco.Models.Repository;
|
||||||
|
using Disco.Services.Interop.ActiveDirectory;
|
||||||
|
using Newtonsoft.Json;
|
||||||
|
using System;
|
||||||
|
using System.IO;
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
|
namespace Disco.Services.Documents
|
||||||
|
{
|
||||||
|
public class DocumentUniqueIdentifier
|
||||||
|
{
|
||||||
|
private const int CurrentVersion = 2;
|
||||||
|
private const byte MagicNumber = 0xC4;
|
||||||
|
private DiscoDataContext database;
|
||||||
|
|
||||||
|
public int Version { get; private set; }
|
||||||
|
public short DeploymentChecksum { get; private set; }
|
||||||
|
public string DocumentTemplateId { get; private set; }
|
||||||
|
public string TargetId { get; private set; }
|
||||||
|
public string CreatorId { get; private set; }
|
||||||
|
public DateTime TimeStamp { get; private set; }
|
||||||
|
public int PageIndex { get; private set; }
|
||||||
|
|
||||||
|
private DocumentTemplate documentTemplate;
|
||||||
|
private AttachmentTypes? attachmentType;
|
||||||
|
private IAttachmentTarget target;
|
||||||
|
private User creator;
|
||||||
|
|
||||||
|
public DocumentTemplate DocumentTemplate
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
if (documentTemplate == null && !string.IsNullOrWhiteSpace(DocumentTemplateId) && !DocumentTemplateId.StartsWith("--", StringComparison.Ordinal))
|
||||||
|
{
|
||||||
|
documentTemplate = database.DocumentTemplates.Find(DocumentTemplateId);
|
||||||
|
if (documentTemplate != null)
|
||||||
|
{
|
||||||
|
attachmentType = documentTemplate.AttachmentType;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return documentTemplate;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public string DocumentGroupingId
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
// Unique identifier to distinguish this document from others (but keep pages together)
|
||||||
|
return $"{TimeStamp.Ticks}|{TargetId}|{DocumentTemplateId}|{CreatorId}|{Version}|{DeploymentChecksum}";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public AttachmentTypes? AttachmentType
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
if (!attachmentType.HasValue)
|
||||||
|
{
|
||||||
|
if (DocumentTemplateId.StartsWith("--", StringComparison.Ordinal))
|
||||||
|
{
|
||||||
|
if (DocumentTemplateId.Equals("--DEVICE", StringComparison.Ordinal))
|
||||||
|
{
|
||||||
|
attachmentType = AttachmentTypes.Device;
|
||||||
|
}
|
||||||
|
else if (DocumentTemplateId.Equals("--JOB", StringComparison.Ordinal))
|
||||||
|
{
|
||||||
|
attachmentType = AttachmentTypes.Job;
|
||||||
|
}
|
||||||
|
else if (DocumentTemplateId.Equals("--USER", StringComparison.Ordinal))
|
||||||
|
{
|
||||||
|
attachmentType = AttachmentTypes.User;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
var dt = DocumentTemplate;
|
||||||
|
if (dt != null)
|
||||||
|
{
|
||||||
|
attachmentType = dt.AttachmentType;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return attachmentType;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public IAttachmentTarget Target
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
if (target == null)
|
||||||
|
{
|
||||||
|
switch (AttachmentType)
|
||||||
|
{
|
||||||
|
case AttachmentTypes.Device:
|
||||||
|
target = database.Devices.Find(TargetId);
|
||||||
|
break;
|
||||||
|
case AttachmentTypes.Job:
|
||||||
|
target = database.Jobs.Find(int.Parse(TargetId));
|
||||||
|
break;
|
||||||
|
case AttachmentTypes.User:
|
||||||
|
target = database.Users.Find(ActiveDirectory.ParseDomainAccountId(TargetId));
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw new ArgumentException("Unexpected Attachment Type", nameof(AttachmentType));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return target;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public User Creator
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
if (creator == null)
|
||||||
|
{
|
||||||
|
creator = database.Users.Find(ActiveDirectory.ParseDomainAccountId(CreatorId));
|
||||||
|
}
|
||||||
|
return creator;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private DocumentUniqueIdentifier(DiscoDataContext Database, int Version, short DeploymentChecksum, string DocumentTemplateId, string TargetId, string CreatorId, DateTime TimeStamp, int PageIndex, AttachmentTypes? AttachmentType)
|
||||||
|
{
|
||||||
|
this.database = Database;
|
||||||
|
this.Version = Version;
|
||||||
|
this.DeploymentChecksum = DeploymentChecksum;
|
||||||
|
this.DocumentTemplateId = DocumentTemplateId;
|
||||||
|
this.attachmentType = AttachmentType;
|
||||||
|
this.TargetId = TargetId;
|
||||||
|
this.CreatorId = ActiveDirectory.ParseDomainAccountId(CreatorId);
|
||||||
|
this.TimeStamp = TimeStamp;
|
||||||
|
this.PageIndex = PageIndex;
|
||||||
|
}
|
||||||
|
|
||||||
|
public string ToQRCodeString()
|
||||||
|
{
|
||||||
|
return $"Disco|1|{DocumentTemplate.Id}|{TargetId}|{CreatorId}|{TimeStamp:s}|{PageIndex}";
|
||||||
|
}
|
||||||
|
|
||||||
|
public string ToJson()
|
||||||
|
{
|
||||||
|
var builder = new StringBuilder();
|
||||||
|
using (var stringWriter = new StringWriter(builder))
|
||||||
|
{
|
||||||
|
using (var writer = new JsonTextWriter(stringWriter))
|
||||||
|
{
|
||||||
|
writer.Formatting = Formatting.Indented;
|
||||||
|
writer.WriteStartObject();
|
||||||
|
writer.WritePropertyName("version");
|
||||||
|
writer.WriteValue(CurrentVersion);
|
||||||
|
writer.WritePropertyName("attachmentType");
|
||||||
|
writer.WriteValue(AttachmentType.Value.ToString());
|
||||||
|
writer.WritePropertyName("documentTemplateId");
|
||||||
|
writer.WriteValue(DocumentTemplateId);
|
||||||
|
writer.WritePropertyName("targetId");
|
||||||
|
writer.WriteValue(TargetId);
|
||||||
|
writer.WritePropertyName("creatorId");
|
||||||
|
writer.WriteValue(CreatorId);
|
||||||
|
writer.WritePropertyName("timestamp");
|
||||||
|
writer.WriteValue(TimeStamp);
|
||||||
|
writer.WritePropertyName("pageIndex");
|
||||||
|
writer.WriteValue(PageIndex);
|
||||||
|
writer.WriteEndObject();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return builder.ToString();
|
||||||
|
}
|
||||||
|
|
||||||
|
public byte[] ToQRCodeBytes()
|
||||||
|
{
|
||||||
|
// Byte | Meaning
|
||||||
|
// 0 | magic number = 0x0D
|
||||||
|
// 1 | bits 0-3 = version; 4-7 = flags (1 = has document template id, 2 = device attachment,
|
||||||
|
// | 4 = job attachment, 8 = user attachment)
|
||||||
|
// 2-3 | deployment checksum (int16)
|
||||||
|
// 4-7 | timestamp (uint32 unix epoch)
|
||||||
|
// 8-9 | page index (uint16)
|
||||||
|
// 10 | creator id length
|
||||||
|
// 11-? | creator id (UTF8)
|
||||||
|
// ? | target id length
|
||||||
|
// ?-? | target id
|
||||||
|
// ? | document template id length (optional based on flag)
|
||||||
|
// ?-? | document template id (UTF8, optional based on flag)
|
||||||
|
|
||||||
|
var encoding = Encoding.UTF8;
|
||||||
|
byte flags = 0;
|
||||||
|
|
||||||
|
switch (AttachmentType)
|
||||||
|
{
|
||||||
|
case AttachmentTypes.Device:
|
||||||
|
flags = 2;
|
||||||
|
break;
|
||||||
|
case AttachmentTypes.Job:
|
||||||
|
flags = 4;
|
||||||
|
break;
|
||||||
|
case AttachmentTypes.User:
|
||||||
|
flags = 8;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
var deploymentChecksumBytes = BitConverter.GetBytes(DeploymentChecksum);
|
||||||
|
var timeStampEpochBytes = BitConverter.GetBytes((uint)(TimeStamp.ToUniversalTime().Subtract(DateTime.FromFileTimeUtc(116444736000000000L)).Ticks / TimeSpan.TicksPerSecond));
|
||||||
|
var pageIndexBytes = BitConverter.GetBytes((ushort)PageIndex);
|
||||||
|
|
||||||
|
|
||||||
|
// magic number (1) + version/flags (1) + deployment checksum (2) + timestamp (4) +
|
||||||
|
// page index (2) + creator id length (1) + target id length (1)
|
||||||
|
var requiredBytes = 12;
|
||||||
|
var creatorIdLength = encoding.GetByteCount(CreatorId);
|
||||||
|
var targetIdLength = encoding.GetByteCount(TargetId);
|
||||||
|
var documentTemplateIdLength = 0;
|
||||||
|
|
||||||
|
if (DocumentTemplateId != null)
|
||||||
|
{
|
||||||
|
flags |= 1;
|
||||||
|
requiredBytes++;
|
||||||
|
documentTemplateIdLength = encoding.GetByteCount(DocumentTemplateId);
|
||||||
|
}
|
||||||
|
|
||||||
|
int position = 0;
|
||||||
|
var result = new byte[requiredBytes];
|
||||||
|
|
||||||
|
// magic number
|
||||||
|
result[position++] = MagicNumber;
|
||||||
|
// version & flags
|
||||||
|
result[position++] = (byte)(2 | (flags << 4));
|
||||||
|
// deployment checksum
|
||||||
|
deploymentChecksumBytes.CopyTo(result, position);
|
||||||
|
position += 2;
|
||||||
|
// timestamp
|
||||||
|
timeStampEpochBytes.CopyTo(result, position);
|
||||||
|
position += 4;
|
||||||
|
// page index
|
||||||
|
pageIndexBytes.CopyTo(result, position);
|
||||||
|
position += 2;
|
||||||
|
// creator id length
|
||||||
|
result[position++] = (byte)creatorIdLength;
|
||||||
|
// creator id
|
||||||
|
position += encoding.GetBytes(CreatorId, 0, CreatorId.Length, result, position);
|
||||||
|
// target id length
|
||||||
|
result[position++] = (byte)targetIdLength;
|
||||||
|
// target id
|
||||||
|
position += encoding.GetBytes(TargetId, 0, TargetId.Length, result, position);
|
||||||
|
if (documentTemplateIdLength > 0)
|
||||||
|
{
|
||||||
|
// document template id length
|
||||||
|
result[position++] = (byte)documentTemplateIdLength;
|
||||||
|
// document template id
|
||||||
|
position += encoding.GetBytes(DocumentTemplateId, 0, DocumentTemplateId.Length, result, position);
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static DocumentUniqueIdentifier Create(DiscoDataContext Database, DocumentTemplate DocumentTemplate, IAttachmentTarget Target, User Creator, DateTime TimeStamp, int PageIndex)
|
||||||
|
{
|
||||||
|
var deploymentChecksum = Database.DiscoConfiguration.DeploymentChecksum;
|
||||||
|
var documentTemplateId = DocumentTemplate.Id;
|
||||||
|
var targetId = Target.AttachmentReferenceId;
|
||||||
|
var creatorId = Creator.UserId;
|
||||||
|
var attachmentType = DocumentTemplate.AttachmentType;
|
||||||
|
|
||||||
|
var identifier = new DocumentUniqueIdentifier(Database, CurrentVersion, deploymentChecksum, documentTemplateId, targetId, creatorId, TimeStamp, PageIndex, attachmentType);
|
||||||
|
|
||||||
|
identifier.documentTemplate = DocumentTemplate;
|
||||||
|
identifier.target = Target;
|
||||||
|
identifier.creator = Creator;
|
||||||
|
|
||||||
|
return identifier;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static DocumentUniqueIdentifier Create(DiscoDataContext Database, string DocumentTemplateId, string TargetId, string CreatorId, DateTime TimeStamp, int PageIndex)
|
||||||
|
{
|
||||||
|
var deploymentChecksum = Database.DiscoConfiguration.DeploymentChecksum;
|
||||||
|
|
||||||
|
return new DocumentUniqueIdentifier(Database, CurrentVersion, deploymentChecksum, DocumentTemplateId, TargetId, CreatorId, TimeStamp, PageIndex, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static DocumentUniqueIdentifier Parse(DiscoDataContext Database, byte[] UniqueIdentifier)
|
||||||
|
{
|
||||||
|
DocumentUniqueIdentifier identifier;
|
||||||
|
if (TryParse(Database, UniqueIdentifier, out identifier))
|
||||||
|
{
|
||||||
|
return identifier;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
throw new FormatException("Invalid Document Unique Identifier");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static DocumentUniqueIdentifier Parse(DiscoDataContext Database, string UniqueIdentifier)
|
||||||
|
{
|
||||||
|
DocumentUniqueIdentifier identifier;
|
||||||
|
if (TryParse(Database, UniqueIdentifier, out identifier))
|
||||||
|
{
|
||||||
|
return identifier;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
throw new FormatException("Invalid Document Unique Identifier");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static bool TryParse(DiscoDataContext Database, string UniqueIdentifier, out DocumentUniqueIdentifier Identifier)
|
||||||
|
{
|
||||||
|
if (IsDocumentUniqueIdentifier(UniqueIdentifier))
|
||||||
|
{
|
||||||
|
var components = UniqueIdentifier.Split('|');
|
||||||
|
|
||||||
|
// Version 0, Version 1 Handling
|
||||||
|
if ((components.Length == 7 || components.Length == 6) &&
|
||||||
|
(components[1].Equals("1", StringComparison.Ordinal) || components[1].Equals("AT", StringComparison.OrdinalIgnoreCase)))
|
||||||
|
{
|
||||||
|
var documentTemplateId = components[2];
|
||||||
|
var targetId = components[3];
|
||||||
|
var creatorId = components[4];
|
||||||
|
var timeStamp = DateTime.Parse(components[5]);
|
||||||
|
var page = 0;
|
||||||
|
if (components.Length == 7)
|
||||||
|
{
|
||||||
|
page = int.Parse(components[6]);
|
||||||
|
}
|
||||||
|
|
||||||
|
Identifier = new DocumentUniqueIdentifier(Database, 1, -1, documentTemplateId, targetId, creatorId, timeStamp, page, null);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Identifier = null;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static bool TryParse(DiscoDataContext Database, byte[] UniqueIdentifier, out DocumentUniqueIdentifier Identifier)
|
||||||
|
{
|
||||||
|
if (IsDocumentUniqueIdentifier(UniqueIdentifier))
|
||||||
|
{
|
||||||
|
// first 4 bit indicate version
|
||||||
|
var version = UniqueIdentifier[2] & 0x0F;
|
||||||
|
|
||||||
|
// Version 2
|
||||||
|
if (version == 2)
|
||||||
|
{
|
||||||
|
// Byte | Meaning
|
||||||
|
// 0 | magic number = 0x0D
|
||||||
|
// 1 | bits 0-3 = version; 4-7 = flags (1 = has document template id, 2 = device attachment,
|
||||||
|
// | 4 = job attachment, 8 = user attachment)
|
||||||
|
// 2-3 | deployment checksum (int16)
|
||||||
|
// 4-7 | timestamp (uint32 unix epoch)
|
||||||
|
// 8-9 | page index (uint16)
|
||||||
|
// 10 | creator id length
|
||||||
|
// 11-? | creator id (UTF8)
|
||||||
|
// ? | target id length
|
||||||
|
// ?-? | target id
|
||||||
|
// ? | document template id length (optional based on flag)
|
||||||
|
// ?-? | document template id (UTF8, optional based on flag)
|
||||||
|
var encoding = Encoding.UTF8;
|
||||||
|
var position = 2;
|
||||||
|
|
||||||
|
// next 4 bits are flags
|
||||||
|
var flags = UniqueIdentifier[position++] >> 4;
|
||||||
|
|
||||||
|
var deploymentChecksum = BitConverter.ToInt16(UniqueIdentifier, position);
|
||||||
|
position += 2;
|
||||||
|
|
||||||
|
var timeStampEpoch = BitConverter.ToUInt32(UniqueIdentifier, position);
|
||||||
|
position += 4;
|
||||||
|
|
||||||
|
var pageIndex = BitConverter.ToUInt16(UniqueIdentifier, position);
|
||||||
|
position += 2;
|
||||||
|
|
||||||
|
var creatorIdLength = UniqueIdentifier[position++];
|
||||||
|
var creatorId = encoding.GetString(UniqueIdentifier, position, creatorIdLength);
|
||||||
|
position += creatorIdLength;
|
||||||
|
|
||||||
|
var targetIdLength = UniqueIdentifier[position++];
|
||||||
|
var targetId = encoding.GetString(UniqueIdentifier, position, targetIdLength);
|
||||||
|
position += targetIdLength;
|
||||||
|
|
||||||
|
string documentTemplateId = null;
|
||||||
|
|
||||||
|
// Has document template id flag
|
||||||
|
if ((flags & 1) == 1)
|
||||||
|
{
|
||||||
|
var documentTemplateIdLength = UniqueIdentifier[position++];
|
||||||
|
documentTemplateId = encoding.GetString(UniqueIdentifier, position, documentTemplateIdLength);
|
||||||
|
}
|
||||||
|
|
||||||
|
AttachmentTypes? attachmentType = null;
|
||||||
|
if ((flags & 2) == 2)
|
||||||
|
attachmentType = AttachmentTypes.Device;
|
||||||
|
else if ((flags & 4) == 4)
|
||||||
|
attachmentType = AttachmentTypes.Job;
|
||||||
|
else if ((flags & 8) == 8)
|
||||||
|
attachmentType = AttachmentTypes.User;
|
||||||
|
|
||||||
|
var timeStamp = DateTime.FromFileTimeUtc(116444736000000000L).AddTicks(TimeSpan.TicksPerSecond * timeStampEpoch).ToLocalTime();
|
||||||
|
|
||||||
|
Identifier = new DocumentUniqueIdentifier(Database, version, deploymentChecksum, documentTemplateId, targetId, creatorId, timeStamp, pageIndex, attachmentType);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Identifier = null;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static bool IsDocumentUniqueIdentifier(string Identifier)
|
||||||
|
{
|
||||||
|
return Identifier != null && Identifier.StartsWith("Disco|", System.StringComparison.OrdinalIgnoreCase);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static bool IsDocumentUniqueIdentifier(byte[] Identifier)
|
||||||
|
{
|
||||||
|
// Identifier[0] = 0xC4; Magic number to identify Disco ICT QR Codes
|
||||||
|
return Identifier != null && Identifier.Length > 2 && Identifier[0] == MagicNumber;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,21 @@
|
|||||||
|
using Disco.Data.Repository;
|
||||||
|
using Disco.Models.Repository;
|
||||||
|
using Disco.Services.Documents;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace Disco.Services
|
||||||
|
{
|
||||||
|
public static class DocumentUniqueIdentifierExtensions
|
||||||
|
{
|
||||||
|
|
||||||
|
public static DocumentUniqueIdentifier CreateUniqueIdentifier(this DocumentTemplate Template, DiscoDataContext Database, IAttachmentTarget Target, User Creator, DateTime Timestamp, int PageIndex)
|
||||||
|
{
|
||||||
|
return DocumentUniqueIdentifier.Create(Database, Template, Target, Creator, Timestamp, PageIndex);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,441 @@
|
|||||||
|
using Disco.Models.Repository;
|
||||||
|
using Disco.Services.Logging;
|
||||||
|
using Disco.Services.Logging.Models;
|
||||||
|
|
||||||
|
namespace Disco.Services.Documents
|
||||||
|
{
|
||||||
|
public class DocumentsLog : LogBase
|
||||||
|
{
|
||||||
|
|
||||||
|
public enum EventTypeIds
|
||||||
|
{
|
||||||
|
ImportStarting = 10,
|
||||||
|
ImportProgress,
|
||||||
|
ImportFinished,
|
||||||
|
ImportWarning = 15,
|
||||||
|
ImportError,
|
||||||
|
ImportAttachmentExpressionEvaluated = 50,
|
||||||
|
ImportPageStarting = 100,
|
||||||
|
ImportPageImageUpdate = 104,
|
||||||
|
ImportPageProgress,
|
||||||
|
ImportPageDetected = 110,
|
||||||
|
ImportPageUndetected = 115,
|
||||||
|
ImportPageError = 120,
|
||||||
|
ImportPageUndetectedStored = 150,
|
||||||
|
DocumentGenerated = 500,
|
||||||
|
DocumentGeneratedWithExpression
|
||||||
|
}
|
||||||
|
|
||||||
|
private const int _ModuleId = 40;
|
||||||
|
|
||||||
|
public static DocumentsLog Current
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return (DocumentsLog)LogContext.LogModules[_ModuleId];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public override string ModuleDescription
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return "Documents";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public override int ModuleId
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return _ModuleId;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public override string ModuleName
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return "Documents";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
private static void Log(DocumentsLog.EventTypeIds EventTypeId, params object[] Args)
|
||||||
|
{
|
||||||
|
DocumentsLog.Current.Log((int)EventTypeId, Args);
|
||||||
|
}
|
||||||
|
public static void LogImportStarting(string SessionId, string DocumentName)
|
||||||
|
{
|
||||||
|
DocumentsLog.Log(DocumentsLog.EventTypeIds.ImportStarting, new object[]
|
||||||
|
{
|
||||||
|
SessionId,
|
||||||
|
DocumentName
|
||||||
|
});
|
||||||
|
}
|
||||||
|
public static void LogImportProgress(string SessionId, int? Progress, string Status)
|
||||||
|
{
|
||||||
|
DocumentsLog.Log(DocumentsLog.EventTypeIds.ImportProgress, new object[]
|
||||||
|
{
|
||||||
|
SessionId,
|
||||||
|
Progress,
|
||||||
|
Status
|
||||||
|
});
|
||||||
|
}
|
||||||
|
public static void LogImportFinished(string SessionId)
|
||||||
|
{
|
||||||
|
DocumentsLog.Log(DocumentsLog.EventTypeIds.ImportFinished, new object[]
|
||||||
|
{
|
||||||
|
SessionId
|
||||||
|
});
|
||||||
|
}
|
||||||
|
public static void LogImportWarning(string SessionId, string Message)
|
||||||
|
{
|
||||||
|
DocumentsLog.Log(DocumentsLog.EventTypeIds.ImportWarning, new object[]
|
||||||
|
{
|
||||||
|
SessionId,
|
||||||
|
Message
|
||||||
|
});
|
||||||
|
}
|
||||||
|
public static void LogImportError(string SessionId, string Message)
|
||||||
|
{
|
||||||
|
DocumentsLog.Log(DocumentsLog.EventTypeIds.ImportError, new object[]
|
||||||
|
{
|
||||||
|
SessionId,
|
||||||
|
Message
|
||||||
|
});
|
||||||
|
}
|
||||||
|
public static void LogImportAttachmentExpressionEvaluated(DocumentTemplate template, IAttachmentTarget target, IAttachment attachment, string Result)
|
||||||
|
{
|
||||||
|
DocumentsLog.Log(DocumentsLog.EventTypeIds.ImportAttachmentExpressionEvaluated, new object[]
|
||||||
|
{
|
||||||
|
template.Id,
|
||||||
|
target.AttachmentReferenceId,
|
||||||
|
attachment.Id,
|
||||||
|
Result
|
||||||
|
});
|
||||||
|
}
|
||||||
|
public static void LogImportPageStarting(string SessionId, int PageNumber)
|
||||||
|
{
|
||||||
|
DocumentsLog.Log(DocumentsLog.EventTypeIds.ImportPageStarting, new object[]
|
||||||
|
{
|
||||||
|
SessionId,
|
||||||
|
PageNumber
|
||||||
|
});
|
||||||
|
}
|
||||||
|
public static void LogImportPageImageUpdate(string SessionId, int PageNumber)
|
||||||
|
{
|
||||||
|
DocumentsLog.Log(DocumentsLog.EventTypeIds.ImportPageImageUpdate, new object[]
|
||||||
|
{
|
||||||
|
SessionId,
|
||||||
|
PageNumber
|
||||||
|
});
|
||||||
|
}
|
||||||
|
public static void LogImportPageProgress(string SessionId, int PageNumber, int? Progress, string Status)
|
||||||
|
{
|
||||||
|
DocumentsLog.Log(DocumentsLog.EventTypeIds.ImportPageProgress, new object[]
|
||||||
|
{
|
||||||
|
SessionId,
|
||||||
|
PageNumber,
|
||||||
|
Progress,
|
||||||
|
Status
|
||||||
|
});
|
||||||
|
}
|
||||||
|
public static void LogImportPageDetected(string SessionId, int PageNumber, string DocumentTypeId, string DocumentTypeName, string TargetType, string AssignedId, string AssignedName)
|
||||||
|
{
|
||||||
|
DocumentsLog.Log(DocumentsLog.EventTypeIds.ImportPageDetected, new object[]
|
||||||
|
{
|
||||||
|
SessionId,
|
||||||
|
PageNumber,
|
||||||
|
DocumentTypeId,
|
||||||
|
DocumentTypeName,
|
||||||
|
TargetType,
|
||||||
|
AssignedId,
|
||||||
|
AssignedName
|
||||||
|
});
|
||||||
|
}
|
||||||
|
public static void LogImportPageUndetected(string SessionId, int PageNumber)
|
||||||
|
{
|
||||||
|
DocumentsLog.Log(DocumentsLog.EventTypeIds.ImportPageUndetected, new object[]
|
||||||
|
{
|
||||||
|
SessionId,
|
||||||
|
PageNumber
|
||||||
|
});
|
||||||
|
}
|
||||||
|
public static void LogImportPageError(string SessionId, int PageNumber, string Message)
|
||||||
|
{
|
||||||
|
DocumentsLog.Log(DocumentsLog.EventTypeIds.ImportPageError, new object[]
|
||||||
|
{
|
||||||
|
SessionId,
|
||||||
|
PageNumber,
|
||||||
|
Message
|
||||||
|
});
|
||||||
|
}
|
||||||
|
public static void LogImportPageUndetectedStored(string SessionId, int PageNumber)
|
||||||
|
{
|
||||||
|
DocumentsLog.Log(DocumentsLog.EventTypeIds.ImportPageUndetectedStored, new object[]
|
||||||
|
{
|
||||||
|
SessionId,
|
||||||
|
PageNumber
|
||||||
|
});
|
||||||
|
}
|
||||||
|
public static void LogDocumentGenerated(DocumentTemplate Template, Device Device, User Author, string ExpressionResult)
|
||||||
|
{
|
||||||
|
DocumentsLog.Log(DocumentsLog.EventTypeIds.DocumentGeneratedWithExpression, new object[]
|
||||||
|
{
|
||||||
|
Template.Id,
|
||||||
|
Device.SerialNumber,
|
||||||
|
Author.UserId,
|
||||||
|
ExpressionResult
|
||||||
|
});
|
||||||
|
}
|
||||||
|
public static void LogDocumentGenerated(DocumentTemplate Template, Job Job, User Author, string ExpressionResult)
|
||||||
|
{
|
||||||
|
DocumentsLog.Log(DocumentsLog.EventTypeIds.DocumentGeneratedWithExpression, new object[]
|
||||||
|
{
|
||||||
|
Template.Id,
|
||||||
|
Job.Id,
|
||||||
|
Author.UserId,
|
||||||
|
ExpressionResult
|
||||||
|
});
|
||||||
|
}
|
||||||
|
public static void LogDocumentGenerated(DocumentTemplate Template, User User, User Author, string ExpressionResult)
|
||||||
|
{
|
||||||
|
DocumentsLog.Log(DocumentsLog.EventTypeIds.DocumentGeneratedWithExpression, new object[]
|
||||||
|
{
|
||||||
|
Template.Id,
|
||||||
|
User.UserId,
|
||||||
|
Author.UserId,
|
||||||
|
ExpressionResult
|
||||||
|
});
|
||||||
|
}
|
||||||
|
public static void LogDocumentGenerated(DocumentTemplate Template, IAttachmentTarget Data, User Author, string ExpressionResult)
|
||||||
|
{
|
||||||
|
if (Data is Job)
|
||||||
|
LogDocumentGenerated(Template, (Job)Data, Author, ExpressionResult);
|
||||||
|
else if (Data is User)
|
||||||
|
LogDocumentGenerated(Template, (User)Data, Author, ExpressionResult);
|
||||||
|
else if (Data is Device)
|
||||||
|
LogDocumentGenerated(Template, (Device)Data, Author, ExpressionResult);
|
||||||
|
else
|
||||||
|
DocumentsLog.Log(DocumentsLog.EventTypeIds.DocumentGeneratedWithExpression, new object[]
|
||||||
|
{
|
||||||
|
Template.Id,
|
||||||
|
"UNKNOWN",
|
||||||
|
Author.UserId,
|
||||||
|
ExpressionResult
|
||||||
|
});
|
||||||
|
}
|
||||||
|
public static void LogDocumentGenerated(DocumentTemplate Template, Device Device, User Author)
|
||||||
|
{
|
||||||
|
DocumentsLog.Log(DocumentsLog.EventTypeIds.DocumentGenerated, new object[]
|
||||||
|
{
|
||||||
|
Template.Id,
|
||||||
|
Device.SerialNumber,
|
||||||
|
Author.UserId
|
||||||
|
});
|
||||||
|
}
|
||||||
|
public static void LogDocumentGenerated(DocumentTemplate Template, Job Job, User Author)
|
||||||
|
{
|
||||||
|
DocumentsLog.Log(DocumentsLog.EventTypeIds.DocumentGenerated, new object[]
|
||||||
|
{
|
||||||
|
Template.Id,
|
||||||
|
Job.Id,
|
||||||
|
Author.UserId
|
||||||
|
});
|
||||||
|
}
|
||||||
|
public static void LogDocumentGenerated(DocumentTemplate Template, User User, User Author)
|
||||||
|
{
|
||||||
|
DocumentsLog.Log(DocumentsLog.EventTypeIds.DocumentGenerated, new object[]
|
||||||
|
{
|
||||||
|
Template.Id,
|
||||||
|
User.UserId,
|
||||||
|
Author.UserId
|
||||||
|
});
|
||||||
|
}
|
||||||
|
public static void LogDocumentGenerated(DocumentTemplate Template, object Data, User Author)
|
||||||
|
{
|
||||||
|
if (Data is Job)
|
||||||
|
LogDocumentGenerated(Template, (Job)Data, Author);
|
||||||
|
else if (Data is User)
|
||||||
|
LogDocumentGenerated(Template, (User)Data, Author);
|
||||||
|
else if (Data is Device)
|
||||||
|
LogDocumentGenerated(Template, (Device)Data, Author);
|
||||||
|
else
|
||||||
|
DocumentsLog.Log(DocumentsLog.EventTypeIds.DocumentGenerated, new object[]
|
||||||
|
{
|
||||||
|
Template.Id,
|
||||||
|
"UNKNOWN",
|
||||||
|
Author.UserId
|
||||||
|
});
|
||||||
|
}
|
||||||
|
protected override System.Collections.Generic.List<LogEventType> LoadEventTypes()
|
||||||
|
{
|
||||||
|
return new System.Collections.Generic.List<LogEventType>
|
||||||
|
{
|
||||||
|
new LogEventType
|
||||||
|
{
|
||||||
|
Id = (int)EventTypeIds.ImportStarting,
|
||||||
|
ModuleId = _ModuleId,
|
||||||
|
Name = "Import Starting",
|
||||||
|
Format = "Starting import of document: {1} (SessionId: {0})",
|
||||||
|
Severity = (int)LogEventType.Severities.Information,
|
||||||
|
UseLive = true,
|
||||||
|
UsePersist = true,
|
||||||
|
UseDisplay = true
|
||||||
|
},
|
||||||
|
new LogEventType
|
||||||
|
{
|
||||||
|
Id = (int)EventTypeIds.ImportProgress,
|
||||||
|
ModuleId = _ModuleId,
|
||||||
|
Name = "Import Progress",
|
||||||
|
Format = "Processing: {1}% Complete; Status: {2}",
|
||||||
|
Severity = (int)LogEventType.Severities.Information,
|
||||||
|
UseLive = true,
|
||||||
|
UsePersist = false,
|
||||||
|
UseDisplay = false
|
||||||
|
},
|
||||||
|
new LogEventType
|
||||||
|
{
|
||||||
|
Id = (int)EventTypeIds.ImportFinished,
|
||||||
|
ModuleId = _ModuleId,
|
||||||
|
Name = "Import Finished",
|
||||||
|
Format = "Import of document complete (SessionId: {0})",
|
||||||
|
Severity = (int)LogEventType.Severities.Information,
|
||||||
|
UseLive = true,
|
||||||
|
UsePersist = true,
|
||||||
|
UseDisplay = true
|
||||||
|
},
|
||||||
|
new LogEventType
|
||||||
|
{
|
||||||
|
Id = (int)EventTypeIds.ImportWarning,
|
||||||
|
ModuleId = _ModuleId,
|
||||||
|
Name = "Import Warning",
|
||||||
|
Format = "Import Warning: {1} (SessionId: {0})",
|
||||||
|
Severity = (int)LogEventType.Severities.Warning,
|
||||||
|
UseLive = true,
|
||||||
|
UsePersist = true,
|
||||||
|
UseDisplay = true
|
||||||
|
},
|
||||||
|
new LogEventType
|
||||||
|
{
|
||||||
|
Id = (int)EventTypeIds.ImportError,
|
||||||
|
ModuleId = _ModuleId,
|
||||||
|
Name = "Import Error",
|
||||||
|
Format = "Import Error: {1} (SessionId: {0})",
|
||||||
|
Severity = (int)LogEventType.Severities.Error,
|
||||||
|
UseLive = true,
|
||||||
|
UsePersist = true,
|
||||||
|
UseDisplay = true
|
||||||
|
},
|
||||||
|
new LogEventType
|
||||||
|
{
|
||||||
|
Id = (int)EventTypeIds.ImportAttachmentExpressionEvaluated,
|
||||||
|
ModuleId = _ModuleId,
|
||||||
|
Name = "Import Attachment Expression Evaluated",
|
||||||
|
Format = "The import attachment expression for '{0}' was evaluated for '{1}' (attachment id: {2}) with the result: {3}",
|
||||||
|
Severity = (int)LogEventType.Severities.Information,
|
||||||
|
UseLive = true,
|
||||||
|
UsePersist = true,
|
||||||
|
UseDisplay = true
|
||||||
|
},
|
||||||
|
new LogEventType
|
||||||
|
{
|
||||||
|
Id = (int)EventTypeIds.ImportPageStarting,
|
||||||
|
ModuleId = _ModuleId,
|
||||||
|
Name = "Import Page Starting",
|
||||||
|
Format = "Starting import of page: {1} (SessionId: {0})",
|
||||||
|
Severity = (int)LogEventType.Severities.Information,
|
||||||
|
UseLive = true,
|
||||||
|
UsePersist = true,
|
||||||
|
UseDisplay = true
|
||||||
|
},
|
||||||
|
new LogEventType
|
||||||
|
{
|
||||||
|
Id = (int)EventTypeIds.ImportPageImageUpdate,
|
||||||
|
ModuleId = _ModuleId,
|
||||||
|
Name = "Import Page Image Update",
|
||||||
|
Format = null,
|
||||||
|
Severity = (int)LogEventType.Severities.Information,
|
||||||
|
UseLive = true,
|
||||||
|
UsePersist = false,
|
||||||
|
UseDisplay = false
|
||||||
|
},
|
||||||
|
new LogEventType
|
||||||
|
{
|
||||||
|
Id = (int)EventTypeIds.ImportPageProgress,
|
||||||
|
ModuleId = _ModuleId,
|
||||||
|
Name = "Import Page Progress",
|
||||||
|
Format = "Processing: Page {1}; {2}% Complete; Status: {3}",
|
||||||
|
Severity = (int)LogEventType.Severities.Information,
|
||||||
|
UseLive = true,
|
||||||
|
UsePersist = false,
|
||||||
|
UseDisplay = false
|
||||||
|
},
|
||||||
|
new LogEventType
|
||||||
|
{
|
||||||
|
Id = (int)EventTypeIds.ImportPageDetected,
|
||||||
|
ModuleId = _ModuleId,
|
||||||
|
Name = "Import Page Assigned",
|
||||||
|
Format = "Page {1} of type '{3}' assigned to {4}: '{6}'",
|
||||||
|
Severity = (int)LogEventType.Severities.Information,
|
||||||
|
UseLive = true,
|
||||||
|
UsePersist = true,
|
||||||
|
UseDisplay = true
|
||||||
|
},
|
||||||
|
new LogEventType
|
||||||
|
{
|
||||||
|
Id = (int)EventTypeIds.ImportPageUndetected,
|
||||||
|
ModuleId = _ModuleId,
|
||||||
|
Name = "Import Page Undetected",
|
||||||
|
Format = "Page {1} not detected",
|
||||||
|
Severity = (int)LogEventType.Severities.Warning,
|
||||||
|
UseLive = true,
|
||||||
|
UsePersist = true,
|
||||||
|
UseDisplay = true
|
||||||
|
},
|
||||||
|
new LogEventType
|
||||||
|
{
|
||||||
|
Id = (int)EventTypeIds.ImportPageError,
|
||||||
|
ModuleId = _ModuleId,
|
||||||
|
Name = "Import Page Error",
|
||||||
|
Format = "Page {1}, Import Error: {2}",
|
||||||
|
Severity = (int)LogEventType.Severities.Error,
|
||||||
|
UseLive = true,
|
||||||
|
UsePersist = true,
|
||||||
|
UseDisplay = true
|
||||||
|
},
|
||||||
|
new LogEventType
|
||||||
|
{
|
||||||
|
Id = (int)EventTypeIds.ImportPageUndetectedStored,
|
||||||
|
ModuleId = _ModuleId,
|
||||||
|
Name = "Import Page Undetected Stored",
|
||||||
|
Format = null,
|
||||||
|
Severity = (int)LogEventType.Severities.Information,
|
||||||
|
UseLive = true,
|
||||||
|
UsePersist = false,
|
||||||
|
UseDisplay = false
|
||||||
|
},
|
||||||
|
new LogEventType
|
||||||
|
{
|
||||||
|
Id = (int)EventTypeIds.DocumentGenerated,
|
||||||
|
ModuleId = _ModuleId,
|
||||||
|
Name = "Document Generated",
|
||||||
|
Format = "A '{0}' document was generated for '{1}' by '{2}'",
|
||||||
|
Severity = (int)LogEventType.Severities.Information,
|
||||||
|
UseLive = true,
|
||||||
|
UsePersist = true,
|
||||||
|
UseDisplay = true
|
||||||
|
},
|
||||||
|
new LogEventType
|
||||||
|
{
|
||||||
|
Id = (int)EventTypeIds.DocumentGeneratedWithExpression,
|
||||||
|
ModuleId = _ModuleId,
|
||||||
|
Name = "Document Generated with Expression",
|
||||||
|
Format = "A '{0}' document was generated for '{1}' by '{2}'. The expression returned: {3}",
|
||||||
|
Severity = (int)LogEventType.Severities.Information,
|
||||||
|
UseLive = true,
|
||||||
|
UsePersist = true,
|
||||||
|
UseDisplay = true
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
+2
-6
@@ -1,10 +1,6 @@
|
|||||||
using System;
|
using Spring.Expressions.Parser.antlr;
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
|
||||||
using Spring.Expressions.Parser.antlr;
|
|
||||||
|
|
||||||
namespace Disco.BI.Expressions
|
namespace Disco.Services.Expressions
|
||||||
{
|
{
|
||||||
public class EvaluateExpressionParseException
|
public class EvaluateExpressionParseException
|
||||||
{
|
{
|
||||||
+3
-5
@@ -1,9 +1,7 @@
|
|||||||
using System;
|
|
||||||
using System.Collections;
|
|
||||||
using System.Runtime.CompilerServices;
|
|
||||||
using Spring.Expressions.Parser.antlr;
|
using Spring.Expressions.Parser.antlr;
|
||||||
|
using System.Collections;
|
||||||
|
|
||||||
namespace Disco.BI.Expressions
|
namespace Disco.Services.Expressions
|
||||||
{
|
{
|
||||||
public class EvaluateExpressionPart : IExpressionPart
|
public class EvaluateExpressionPart : IExpressionPart
|
||||||
{
|
{
|
||||||
@@ -71,7 +69,7 @@ namespace Disco.BI.Expressions
|
|||||||
this._ExpressionParseException = ex;
|
this._ExpressionParseException = ex;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
object IExpressionPart.Evaluate(object ExpressionContext, System.Collections.IDictionary Variables)
|
object IExpressionPart.Evaluate(object ExpressionContext, IDictionary Variables)
|
||||||
{
|
{
|
||||||
if (this._ExpressionParseException == null)
|
if (this._ExpressionParseException == null)
|
||||||
{
|
{
|
||||||
@@ -1,16 +1,17 @@
|
|||||||
using Disco.Data.Repository;
|
using Disco.Data.Repository;
|
||||||
using Disco.Models.BI.DocumentTemplates;
|
using Disco.Models.BI.Expressions;
|
||||||
using Disco.Models.Repository;
|
using Disco.Models.Repository;
|
||||||
|
using Disco.Models.Services.Documents;
|
||||||
|
using Spring.Core.TypeResolution;
|
||||||
|
using Spring.Expressions;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections;
|
using System.Collections;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Runtime.CompilerServices;
|
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using Disco.Models.BI.Expressions;
|
|
||||||
|
|
||||||
namespace Disco.BI.Expressions
|
namespace Disco.Services.Expressions
|
||||||
{
|
{
|
||||||
public sealed class Expression : System.Collections.Generic.List<IExpressionPart>
|
public sealed class Expression : List<IExpressionPart>
|
||||||
{
|
{
|
||||||
public string Name { get; private set; }
|
public string Name { get; private set; }
|
||||||
public string Source { get; private set; }
|
public string Source { get; private set; }
|
||||||
@@ -26,13 +27,13 @@ namespace Disco.BI.Expressions
|
|||||||
|
|
||||||
public static void InitializeExpressions()
|
public static void InitializeExpressions()
|
||||||
{
|
{
|
||||||
Spring.Core.TypeResolution.TypeRegistry.RegisterType("DataExt", typeof(Extensions.DataExt));
|
TypeRegistry.RegisterType("DataExt", typeof(Extensions.DataExt));
|
||||||
Spring.Core.TypeResolution.TypeRegistry.RegisterType("UserExt", typeof(Extensions.UserExt));
|
TypeRegistry.RegisterType("UserExt", typeof(Extensions.UserExt));
|
||||||
Spring.Core.TypeResolution.TypeRegistry.RegisterType("DeviceExt", typeof(Extensions.DeviceExt));
|
TypeRegistry.RegisterType("DeviceExt", typeof(Extensions.DeviceExt));
|
||||||
Spring.Core.TypeResolution.TypeRegistry.RegisterType("ImageExt", typeof(Extensions.ImageExt));
|
TypeRegistry.RegisterType("ImageExt", typeof(Extensions.ImageExt));
|
||||||
}
|
}
|
||||||
|
|
||||||
public T EvaluateFirst<T>(object ExpressionContext, System.Collections.IDictionary Variables)
|
public T EvaluateFirst<T>(object ExpressionContext, IDictionary Variables)
|
||||||
{
|
{
|
||||||
T result = default(T);
|
T result = default(T);
|
||||||
if (this.Count > 0)
|
if (this.Count > 0)
|
||||||
@@ -52,7 +53,7 @@ namespace Disco.BI.Expressions
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (System.Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
throw new InvalidOperationException("Expression evaluation resulted in an error", ex);
|
throw new InvalidOperationException("Expression evaluation resulted in an error", ex);
|
||||||
}
|
}
|
||||||
@@ -61,9 +62,14 @@ namespace Disco.BI.Expressions
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Tuple<string, bool, object> Evaluate(object ExpressionContext, System.Collections.IDictionary Variables)
|
internal static IExpression Parse(string source)
|
||||||
{
|
{
|
||||||
System.Text.StringBuilder resultValue = new System.Text.StringBuilder();
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Tuple<string, bool, object> Evaluate(object ExpressionContext, IDictionary Variables)
|
||||||
|
{
|
||||||
|
var resultValue = new StringBuilder();
|
||||||
object resultObject = null;
|
object resultObject = null;
|
||||||
bool resultError = false;
|
bool resultError = false;
|
||||||
foreach (var expressionPart in this)
|
foreach (var expressionPart in this)
|
||||||
@@ -80,7 +86,7 @@ namespace Disco.BI.Expressions
|
|||||||
resultValue.Append(partValue.ToString());
|
resultValue.Append(partValue.ToString());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (System.Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
if (!expressionPart.ErrorsAllowed)
|
if (!expressionPart.ErrorsAllowed)
|
||||||
{
|
{
|
||||||
@@ -95,7 +101,7 @@ namespace Disco.BI.Expressions
|
|||||||
}
|
}
|
||||||
public static Expression TokenizeSingleDynamic(string Name, string ExpressionSource, int Ordinal)
|
public static Expression TokenizeSingleDynamic(string Name, string ExpressionSource, int Ordinal)
|
||||||
{
|
{
|
||||||
Expression e = new Expression(Name, ExpressionSource, Ordinal);
|
var e = new Expression(Name, ExpressionSource, Ordinal);
|
||||||
if (ExpressionSource != null && !string.IsNullOrWhiteSpace(ExpressionSource))
|
if (ExpressionSource != null && !string.IsNullOrWhiteSpace(ExpressionSource))
|
||||||
e.Add(new EvaluateExpressionPart(ExpressionSource));
|
e.Add(new EvaluateExpressionPart(ExpressionSource));
|
||||||
e.IsDynamic = true;
|
e.IsDynamic = true;
|
||||||
@@ -103,14 +109,14 @@ namespace Disco.BI.Expressions
|
|||||||
}
|
}
|
||||||
public static Expression Tokenize(string Name, string ExpressionSource, int Ordinal)
|
public static Expression Tokenize(string Name, string ExpressionSource, int Ordinal)
|
||||||
{
|
{
|
||||||
Expression e = new Expression(Name, ExpressionSource, Ordinal);
|
var e = new Expression(Name, ExpressionSource, Ordinal);
|
||||||
if (!ExpressionSource.Contains("{") || !ExpressionSource.Contains("}"))
|
if (!ExpressionSource.Contains("{") || !ExpressionSource.Contains("}"))
|
||||||
{
|
{
|
||||||
e.Add(new TextExpressionPart(ExpressionSource));
|
e.Add(new TextExpressionPart(ExpressionSource));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
System.Text.StringBuilder token = new System.Text.StringBuilder();
|
var token = new StringBuilder();
|
||||||
bool tokenEval = false;
|
bool tokenEval = false;
|
||||||
int tokenEvalDepth = 0;
|
int tokenEvalDepth = 0;
|
||||||
foreach (char c in ExpressionSource)
|
foreach (char c in ExpressionSource)
|
||||||
@@ -124,7 +130,7 @@ namespace Disco.BI.Expressions
|
|||||||
if (token.Length > 0)
|
if (token.Length > 0)
|
||||||
{
|
{
|
||||||
e.Add(new TextExpressionPart(token.ToString()));
|
e.Add(new TextExpressionPart(token.ToString()));
|
||||||
token = new System.Text.StringBuilder();
|
token = new StringBuilder();
|
||||||
}
|
}
|
||||||
tokenEval = true;
|
tokenEval = true;
|
||||||
tokenEvalDepth = 0;
|
tokenEvalDepth = 0;
|
||||||
@@ -145,7 +151,7 @@ namespace Disco.BI.Expressions
|
|||||||
{
|
{
|
||||||
e.Add(new EvaluateExpressionPart(token.ToString()));
|
e.Add(new EvaluateExpressionPart(token.ToString()));
|
||||||
e.IsDynamic = true;
|
e.IsDynamic = true;
|
||||||
token = new System.Text.StringBuilder();
|
token = new StringBuilder();
|
||||||
}
|
}
|
||||||
tokenEval = false;
|
tokenEval = false;
|
||||||
}
|
}
|
||||||
+2
-6
@@ -1,10 +1,6 @@
|
|||||||
using System;
|
using System.Collections.Concurrent;
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
|
||||||
using System.Collections.Concurrent;
|
|
||||||
|
|
||||||
namespace Disco.BI.Expressions
|
namespace Disco.Services.Expressions
|
||||||
{
|
{
|
||||||
public static class ExpressionCache
|
public static class ExpressionCache
|
||||||
{
|
{
|
||||||
+2
-3
@@ -1,11 +1,10 @@
|
|||||||
using Disco.BI.Extensions;
|
using Disco.Data.Repository;
|
||||||
using Disco.Data.Repository;
|
|
||||||
using Disco.Services.Tasks;
|
using Disco.Services.Tasks;
|
||||||
using Quartz;
|
using Quartz;
|
||||||
using System;
|
using System;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
|
||||||
namespace Disco.BI.Expressions
|
namespace Disco.Services.Expressions
|
||||||
{
|
{
|
||||||
public class ExpressionCachePreloadTask : ScheduledTask
|
public class ExpressionCachePreloadTask : ScheduledTask
|
||||||
{
|
{
|
||||||
+9
-11
@@ -1,11 +1,9 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Diagnostics;
|
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
using System.Runtime.CompilerServices;
|
|
||||||
|
|
||||||
namespace Disco.BI.Expressions
|
namespace Disco.Services.Expressions
|
||||||
{
|
{
|
||||||
public class ExpressionTypeDescriptor
|
public class ExpressionTypeDescriptor
|
||||||
{
|
{
|
||||||
@@ -13,16 +11,16 @@ namespace Disco.BI.Expressions
|
|||||||
public string Name { get; set; }
|
public string Name { get; set; }
|
||||||
public List<ExpressionTypeMemberDescriptor> Members { get; set; }
|
public List<ExpressionTypeMemberDescriptor> Members { get; set; }
|
||||||
|
|
||||||
public static ExpressionTypeDescriptor Build(System.Type t, bool StaticDeclaredMembersOnly = true)
|
public static ExpressionTypeDescriptor Build(Type t, bool StaticDeclaredMembersOnly = true)
|
||||||
{
|
{
|
||||||
ExpressionTypeDescriptor i = new ExpressionTypeDescriptor
|
ExpressionTypeDescriptor i = new ExpressionTypeDescriptor
|
||||||
{
|
{
|
||||||
ExpressionType = t.AssemblyQualifiedName,
|
ExpressionType = t.AssemblyQualifiedName,
|
||||||
Name = t.Name
|
Name = t.Name
|
||||||
};
|
};
|
||||||
i.Members = new System.Collections.Generic.List<ExpressionTypeMemberDescriptor>();
|
i.Members = new List<ExpressionTypeMemberDescriptor>();
|
||||||
|
|
||||||
System.Reflection.MemberInfo[] members;
|
MemberInfo[] members;
|
||||||
if (StaticDeclaredMembersOnly)
|
if (StaticDeclaredMembersOnly)
|
||||||
members = t.GetMembers(BindingFlags.Public | BindingFlags.Static | BindingFlags.DeclaredOnly);
|
members = t.GetMembers(BindingFlags.Public | BindingFlags.Static | BindingFlags.DeclaredOnly);
|
||||||
else
|
else
|
||||||
@@ -30,18 +28,18 @@ namespace Disco.BI.Expressions
|
|||||||
|
|
||||||
for (int j = 0; j < members.Length; j++)
|
for (int j = 0; j < members.Length; j++)
|
||||||
{
|
{
|
||||||
System.Reflection.MemberInfo member = members[j];
|
MemberInfo member = members[j];
|
||||||
if (member is System.Reflection.PropertyInfo)
|
if (member is PropertyInfo)
|
||||||
{
|
{
|
||||||
System.Reflection.PropertyInfo pi = (System.Reflection.PropertyInfo)member;
|
PropertyInfo pi = (PropertyInfo)member;
|
||||||
if (!pi.IsSpecialName && pi.CanRead)
|
if (!pi.IsSpecialName && pi.CanRead)
|
||||||
{
|
{
|
||||||
i.Members.Add(ExpressionTypeMemberDescriptor.Build(pi));
|
i.Members.Add(ExpressionTypeMemberDescriptor.Build(pi));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (member is System.Reflection.MethodInfo)
|
if (member is MethodInfo)
|
||||||
{
|
{
|
||||||
System.Reflection.MethodInfo mi2 = (System.Reflection.MethodInfo)member;
|
MethodInfo mi2 = (MethodInfo)member;
|
||||||
if (!mi2.IsSpecialName)
|
if (!mi2.IsSpecialName)
|
||||||
{
|
{
|
||||||
i.Members.Add(ExpressionTypeMemberDescriptor.Build(mi2));
|
i.Members.Add(ExpressionTypeMemberDescriptor.Build(mi2));
|
||||||
@@ -0,0 +1,58 @@
|
|||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Reflection;
|
||||||
|
|
||||||
|
namespace Disco.Services.Expressions
|
||||||
|
{
|
||||||
|
public class ExpressionTypeMemberDescriptor
|
||||||
|
{
|
||||||
|
public const string FunctionKind = "function";
|
||||||
|
public const string PropertyKind = "property";
|
||||||
|
public const string ParameterKind = "parameter";
|
||||||
|
|
||||||
|
public string Kind { get; set; }
|
||||||
|
public string Name { get; set; }
|
||||||
|
public string ReturnType { get; set; }
|
||||||
|
public string ReturnExpressionType { get; set; }
|
||||||
|
public List<ExpressionTypeMemberDescriptor> Parameters { get; set; }
|
||||||
|
|
||||||
|
public static ExpressionTypeMemberDescriptor Build(MethodInfo m)
|
||||||
|
{
|
||||||
|
ExpressionTypeMemberDescriptor md = new ExpressionTypeMemberDescriptor
|
||||||
|
{
|
||||||
|
Kind = "function",
|
||||||
|
Name = m.Name,
|
||||||
|
ReturnType = m.ReturnType.Name,
|
||||||
|
ReturnExpressionType = m.ReturnType.AssemblyQualifiedName
|
||||||
|
};
|
||||||
|
md.Parameters = (
|
||||||
|
from mdp in m.GetParameters()
|
||||||
|
select Build(mdp)).ToList();
|
||||||
|
return md;
|
||||||
|
}
|
||||||
|
public static ExpressionTypeMemberDescriptor Build(PropertyInfo p)
|
||||||
|
{
|
||||||
|
ExpressionTypeMemberDescriptor md = new ExpressionTypeMemberDescriptor
|
||||||
|
{
|
||||||
|
Kind = "property",
|
||||||
|
Name = p.Name,
|
||||||
|
ReturnType = p.PropertyType.Name,
|
||||||
|
ReturnExpressionType = p.PropertyType.AssemblyQualifiedName
|
||||||
|
};
|
||||||
|
md.Parameters = (
|
||||||
|
from mdp in p.GetIndexParameters()
|
||||||
|
select Build(mdp)).ToList();
|
||||||
|
return md;
|
||||||
|
}
|
||||||
|
public static ExpressionTypeMemberDescriptor Build(ParameterInfo pi)
|
||||||
|
{
|
||||||
|
return new ExpressionTypeMemberDescriptor
|
||||||
|
{
|
||||||
|
Kind = "parameter",
|
||||||
|
Name = pi.Name,
|
||||||
|
ReturnType = pi.ParameterType.Name,
|
||||||
|
ReturnExpressionType = pi.ParameterType.AssemblyQualifiedName
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
+4
-7
@@ -1,13 +1,10 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
|
||||||
using System.Data;
|
|
||||||
using System.Data.SqlClient;
|
|
||||||
using System.Collections;
|
using System.Collections;
|
||||||
|
using System.Data;
|
||||||
using System.Data.Odbc;
|
using System.Data.Odbc;
|
||||||
|
using System.Data.SqlClient;
|
||||||
|
|
||||||
namespace Disco.BI.Expressions.Extensions
|
namespace Disco.Services.Expressions.Extensions
|
||||||
{
|
{
|
||||||
public static class DataExt
|
public static class DataExt
|
||||||
{
|
{
|
||||||
@@ -15,7 +12,7 @@ namespace Disco.BI.Expressions.Extensions
|
|||||||
|
|
||||||
private static SqlConnection BuildSqlConnection(string Server, string Database, string Username, string Password)
|
private static SqlConnection BuildSqlConnection(string Server, string Database, string Username, string Password)
|
||||||
{
|
{
|
||||||
SqlConnectionStringBuilder dbConnectionStringBuilder = new SqlConnectionStringBuilder();
|
var dbConnectionStringBuilder = new SqlConnectionStringBuilder();
|
||||||
dbConnectionStringBuilder.ApplicationName = "Disco";
|
dbConnectionStringBuilder.ApplicationName = "Disco";
|
||||||
dbConnectionStringBuilder.DataSource = Server;
|
dbConnectionStringBuilder.DataSource = Server;
|
||||||
dbConnectionStringBuilder.InitialCatalog = Database;
|
dbConnectionStringBuilder.InitialCatalog = Database;
|
||||||
+2
-4
@@ -1,10 +1,8 @@
|
|||||||
using Disco.BI.Extensions;
|
using Disco.Models.Repository;
|
||||||
using Disco.Models.Repository;
|
|
||||||
using Disco.Services.Interop.ActiveDirectory;
|
|
||||||
using System;
|
using System;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
|
||||||
namespace Disco.BI.Expressions.Extensions
|
namespace Disco.Services.Expressions.Extensions
|
||||||
{
|
{
|
||||||
public static class DeviceExt
|
public static class DeviceExt
|
||||||
{
|
{
|
||||||
+6
-14
@@ -1,17 +1,13 @@
|
|||||||
using System;
|
using Disco.Data.Repository;
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
|
||||||
using Disco.Models.BI.Expressions;
|
|
||||||
using Disco.BI.Expressions.Extensions.ImageResultImplementations;
|
|
||||||
using Disco.Models.Repository;
|
using Disco.Models.Repository;
|
||||||
using Disco.BI.Extensions;
|
using Disco.Services.Expressions.Extensions.ImageResultImplementations;
|
||||||
using Disco.Data.Repository;
|
using System;
|
||||||
using System.Collections;
|
using System.Collections;
|
||||||
using System.IO;
|
|
||||||
using System.Drawing;
|
using System.Drawing;
|
||||||
|
using System.IO;
|
||||||
|
using System.Linq;
|
||||||
|
|
||||||
namespace Disco.BI.Expressions.Extensions
|
namespace Disco.Services.Expressions.Extensions
|
||||||
{
|
{
|
||||||
public static class ImageExt
|
public static class ImageExt
|
||||||
{
|
{
|
||||||
@@ -119,10 +115,6 @@ namespace Disco.BI.Expressions.Extensions
|
|||||||
else
|
else
|
||||||
return ImageFromStream(deviceModelImage);
|
return ImageFromStream(deviceModelImage);
|
||||||
}
|
}
|
||||||
//if (DeviceModel.Image == null || DeviceModel.Image.Length == 0)
|
|
||||||
// return null;
|
|
||||||
|
|
||||||
//return ImageFromByteArray(DeviceModel.Image);
|
|
||||||
}
|
}
|
||||||
public static BitmapImageExpressionResult OrganisationLogo()
|
public static BitmapImageExpressionResult OrganisationLogo()
|
||||||
{
|
{
|
||||||
+4
-8
@@ -1,13 +1,9 @@
|
|||||||
using System;
|
using Disco.Models.BI.Expressions;
|
||||||
using System.Collections.Generic;
|
using System;
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
|
||||||
using Disco.Models.BI.Expressions;
|
|
||||||
using System.IO;
|
|
||||||
using System.Drawing;
|
using System.Drawing;
|
||||||
using Disco.BI.Extensions;
|
using System.IO;
|
||||||
|
|
||||||
namespace Disco.BI.Expressions.Extensions.ImageResultImplementations
|
namespace Disco.Services.Expressions.Extensions.ImageResultImplementations
|
||||||
{
|
{
|
||||||
public abstract class BaseImageExpressionResult : IImageExpressionResult
|
public abstract class BaseImageExpressionResult : IImageExpressionResult
|
||||||
{
|
{
|
||||||
+2
-5
@@ -1,11 +1,8 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
|
||||||
using System.IO;
|
|
||||||
using System.Drawing;
|
using System.Drawing;
|
||||||
|
using System.IO;
|
||||||
|
|
||||||
namespace Disco.BI.Expressions.Extensions.ImageResultImplementations
|
namespace Disco.Services.Expressions.Extensions.ImageResultImplementations
|
||||||
{
|
{
|
||||||
public class BitmapImageExpressionResult : BaseImageExpressionResult
|
public class BitmapImageExpressionResult : BaseImageExpressionResult
|
||||||
{
|
{
|
||||||
+2
-5
@@ -1,11 +1,8 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
|
||||||
using System.IO;
|
|
||||||
using System.Drawing;
|
using System.Drawing;
|
||||||
|
using System.IO;
|
||||||
|
|
||||||
namespace Disco.BI.Expressions.Extensions.ImageResultImplementations
|
namespace Disco.Services.Expressions.Extensions.ImageResultImplementations
|
||||||
{
|
{
|
||||||
public class FileImageExpressionResult : BaseImageExpressionResult
|
public class FileImageExpressionResult : BaseImageExpressionResult
|
||||||
{
|
{
|
||||||
+3
-5
@@ -1,13 +1,11 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
|
||||||
using System.IO;
|
|
||||||
using System.Drawing;
|
using System.Drawing;
|
||||||
using System.Drawing.Drawing2D;
|
using System.Drawing.Drawing2D;
|
||||||
using Disco.BI.Extensions;
|
using System.IO;
|
||||||
|
using System.Linq;
|
||||||
|
|
||||||
namespace Disco.BI.Expressions.Extensions.ImageResultImplementations
|
namespace Disco.Services.Expressions.Extensions.ImageResultImplementations
|
||||||
{
|
{
|
||||||
public class FileMontageImageExpressionResult : BaseImageExpressionResult
|
public class FileMontageImageExpressionResult : BaseImageExpressionResult
|
||||||
{
|
{
|
||||||
+2
-3
@@ -1,10 +1,9 @@
|
|||||||
using Disco.BI.Extensions;
|
using Disco.Models.Repository;
|
||||||
using Disco.Models.Repository;
|
|
||||||
using Disco.Services.Users;
|
using Disco.Services.Users;
|
||||||
using System;
|
using System;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
|
||||||
namespace Disco.BI.Expressions.Extensions
|
namespace Disco.Services.Expressions.Extensions
|
||||||
{
|
{
|
||||||
public static class UserExt
|
public static class UserExt
|
||||||
{
|
{
|
||||||
+2
-3
@@ -1,7 +1,6 @@
|
|||||||
using System;
|
|
||||||
using System.Collections;
|
using System.Collections;
|
||||||
|
|
||||||
namespace Disco.BI.Expressions
|
namespace Disco.Services.Expressions
|
||||||
{
|
{
|
||||||
public interface IExpressionPart
|
public interface IExpressionPart
|
||||||
{
|
{
|
||||||
@@ -11,6 +10,6 @@ namespace Disco.BI.Expressions
|
|||||||
bool ParseError { get; }
|
bool ParseError { get; }
|
||||||
string ParseErrorMessage { get; }
|
string ParseErrorMessage { get; }
|
||||||
bool IsDynamic { get; set; }
|
bool IsDynamic { get; set; }
|
||||||
object Evaluate(object ExpressionContext, System.Collections.IDictionary Variables);
|
object Evaluate(object ExpressionContext, IDictionary Variables);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
+1
-1
@@ -1,7 +1,7 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections;
|
using System.Collections;
|
||||||
|
|
||||||
namespace Disco.BI.Expressions
|
namespace Disco.Services.Expressions
|
||||||
{
|
{
|
||||||
public class TextExpressionPart : IExpressionPart
|
public class TextExpressionPart : IExpressionPart
|
||||||
{
|
{
|
||||||
@@ -0,0 +1,233 @@
|
|||||||
|
using System;
|
||||||
|
using System.Drawing;
|
||||||
|
using System.Drawing.Drawing2D;
|
||||||
|
using System.Drawing.Imaging;
|
||||||
|
using System.IO;
|
||||||
|
using System.Linq;
|
||||||
|
|
||||||
|
namespace Disco.Services
|
||||||
|
{
|
||||||
|
public static class ImagingExtensions
|
||||||
|
{
|
||||||
|
|
||||||
|
public static Bitmap RotateImage(this Image Source, float Angle, Brush BackgroundColor = null, bool ResizeIfOver45Deg = true)
|
||||||
|
{
|
||||||
|
var destWidth = Source.Width;
|
||||||
|
var destHeight = Source.Height;
|
||||||
|
var resizedDest = false;
|
||||||
|
|
||||||
|
if (ResizeIfOver45Deg && ((Angle > 45 && Angle < 135) || (Angle < -45 && Angle > -135)))
|
||||||
|
{
|
||||||
|
destWidth = Source.Height;
|
||||||
|
destHeight = Source.Width;
|
||||||
|
resizedDest = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
var destination = new Bitmap(destWidth, destHeight);
|
||||||
|
destination.SetResolution(Source.HorizontalResolution, Source.VerticalResolution);
|
||||||
|
|
||||||
|
using (Graphics destinationGraphics = Graphics.FromImage(destination))
|
||||||
|
{
|
||||||
|
destinationGraphics.CompositingQuality = CompositingQuality.HighQuality;
|
||||||
|
destinationGraphics.InterpolationMode = InterpolationMode.HighQualityBicubic;
|
||||||
|
destinationGraphics.SmoothingMode = SmoothingMode.HighQuality;
|
||||||
|
|
||||||
|
if (BackgroundColor != null)
|
||||||
|
destinationGraphics.FillRectangle(BackgroundColor, destinationGraphics.VisibleClipBounds);
|
||||||
|
|
||||||
|
float offsetWidth = destWidth / 2;
|
||||||
|
float offsetHeight = destHeight / 2;
|
||||||
|
|
||||||
|
destinationGraphics.TranslateTransform(offsetWidth, offsetHeight);
|
||||||
|
destinationGraphics.RotateTransform(Angle);
|
||||||
|
|
||||||
|
RectangleF destinationLocation;
|
||||||
|
|
||||||
|
if (resizedDest)
|
||||||
|
destinationLocation = new RectangleF(
|
||||||
|
offsetHeight * -1, offsetWidth * -1,
|
||||||
|
destHeight, destWidth);
|
||||||
|
else
|
||||||
|
destinationLocation = new RectangleF(
|
||||||
|
offsetWidth * -1, offsetHeight * -1,
|
||||||
|
destWidth, destHeight);
|
||||||
|
|
||||||
|
destinationGraphics.DrawImage(Source, destinationLocation, new RectangleF(0, 0, Source.Width, Source.Height), GraphicsUnit.Pixel);
|
||||||
|
}
|
||||||
|
return destination;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Bitmap ResizeImage(this Image Source, int TargetWidth, int TargetHeight, Brush BackgroundColor = null)
|
||||||
|
{
|
||||||
|
var destination = new Bitmap(TargetWidth, TargetHeight);
|
||||||
|
destination.SetResolution(72, 72);
|
||||||
|
using (Graphics destinationGraphics = Graphics.FromImage(destination))
|
||||||
|
{
|
||||||
|
destinationGraphics.CompositingQuality = CompositingQuality.HighQuality;
|
||||||
|
destinationGraphics.InterpolationMode = InterpolationMode.HighQualityBicubic;
|
||||||
|
destinationGraphics.SmoothingMode = SmoothingMode.HighQuality;
|
||||||
|
|
||||||
|
if (BackgroundColor != null)
|
||||||
|
destinationGraphics.FillRectangle(BackgroundColor, destinationGraphics.VisibleClipBounds);
|
||||||
|
|
||||||
|
destinationGraphics.DrawImageResized(Source);
|
||||||
|
}
|
||||||
|
|
||||||
|
return destination;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static RectangleF CalculateResize(int SourceWidth, int SourceHeight, int TargetWidth, int TargetHeight, out float scaleRatio)
|
||||||
|
{
|
||||||
|
scaleRatio = Math.Min((float)(TargetWidth) / SourceWidth, (float)(TargetHeight) / SourceHeight);
|
||||||
|
|
||||||
|
float width = SourceWidth * scaleRatio,
|
||||||
|
height = SourceHeight * scaleRatio,
|
||||||
|
x = 0,
|
||||||
|
y = 0;
|
||||||
|
|
||||||
|
if (width < TargetWidth)
|
||||||
|
x = (TargetWidth - width) / 2;
|
||||||
|
|
||||||
|
if (height < TargetHeight)
|
||||||
|
y = (TargetHeight - height) / 2;
|
||||||
|
|
||||||
|
return new RectangleF(x, y, width, height);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static RectangleF CalculateResize(int SourceWidth, int SourceHeight, int TargetWidth, int TargetHeight)
|
||||||
|
{
|
||||||
|
float scaleRatio;
|
||||||
|
|
||||||
|
return CalculateResize(SourceWidth, SourceHeight, TargetHeight, TargetHeight, out scaleRatio);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static RectangleF CalculateResize(this Image Source, int TargetWidth, int TargetHeight, out float scaleRatio)
|
||||||
|
{
|
||||||
|
return CalculateResize(Source.Width, Source.Height, TargetWidth, TargetHeight, out scaleRatio);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static RectangleF CalculateResize(this Image Source, int TargetWidth, int TargetHeight)
|
||||||
|
{
|
||||||
|
return CalculateResize(Source.Width, Source.Height, TargetHeight, TargetHeight);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void DrawImageResized(this Graphics graphics, Image SourceImage)
|
||||||
|
{
|
||||||
|
RectangleF clipBounds = graphics.VisibleClipBounds;
|
||||||
|
var resizeBounds = SourceImage.CalculateResize((int)clipBounds.Width, (int)clipBounds.Height);
|
||||||
|
|
||||||
|
graphics.DrawImage(SourceImage, resizeBounds, new RectangleF(0, 0, SourceImage.Width, SourceImage.Height), GraphicsUnit.Pixel);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void DrawImageResized(this Graphics graphics, Image SourceImage, float Scale, float LocationX, float LocationY)
|
||||||
|
{
|
||||||
|
RectangleF clipBounds = graphics.VisibleClipBounds;
|
||||||
|
|
||||||
|
float width = SourceImage.Width * Scale,
|
||||||
|
height = SourceImage.Height * Scale,
|
||||||
|
x = LocationX,
|
||||||
|
y = LocationY;
|
||||||
|
|
||||||
|
x += clipBounds.Left;
|
||||||
|
y += clipBounds.Top;
|
||||||
|
|
||||||
|
graphics.DrawImage(SourceImage, new RectangleF(x, y, width, height), new RectangleF(0, 0, SourceImage.Width, SourceImage.Height), GraphicsUnit.Pixel);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void EmbedIconOverlay(this Image Source, Image Icon)
|
||||||
|
{
|
||||||
|
int top = Math.Max(0, Source.Height - Icon.Height);
|
||||||
|
int left = Math.Max(0, Source.Width - Icon.Width);
|
||||||
|
|
||||||
|
using (Graphics sourceGraphics = Graphics.FromImage(Source))
|
||||||
|
{
|
||||||
|
sourceGraphics.DrawImage(Icon, left, top);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void SavePng(this Image Source, string Filename)
|
||||||
|
{
|
||||||
|
using (FileStream outStream = new FileStream(Filename, FileMode.Create, FileAccess.Write, FileShare.None))
|
||||||
|
{
|
||||||
|
SavePng(Source, outStream);
|
||||||
|
outStream.Flush();
|
||||||
|
outStream.Close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void SavePng(this Image Source, Stream OutStream)
|
||||||
|
{
|
||||||
|
Source.Save(OutStream, ImageFormat.Png);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Stream SavePng(this Image Source)
|
||||||
|
{
|
||||||
|
MemoryStream outStream = new MemoryStream();
|
||||||
|
Source.SavePng(outStream);
|
||||||
|
outStream.Position = 0;
|
||||||
|
return outStream;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Stream SaveJpg(this Image Source, int Quality)
|
||||||
|
{
|
||||||
|
MemoryStream outStream = new MemoryStream();
|
||||||
|
Source.SaveJpg(Quality, outStream);
|
||||||
|
outStream.Position = 0;
|
||||||
|
return outStream;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void SaveJpg(this Image Source, int Quality, string Filename)
|
||||||
|
{
|
||||||
|
using (FileStream outStream = new FileStream(Filename, FileMode.Create, FileAccess.Write, FileShare.None))
|
||||||
|
{
|
||||||
|
SaveJpg(Source, Quality, outStream);
|
||||||
|
outStream.Flush();
|
||||||
|
outStream.Close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void SaveJpg(this Image Source, int Quality, Stream OutStream)
|
||||||
|
{
|
||||||
|
ImageCodecInfo jpgCodec = ImageCodecInfo.GetImageEncoders().Where(c => c.MimeType.Equals("image/jpeg", StringComparison.OrdinalIgnoreCase)).FirstOrDefault();
|
||||||
|
if (jpgCodec != null)
|
||||||
|
{
|
||||||
|
if (Quality < 0 || Quality > 100)
|
||||||
|
throw new ArgumentOutOfRangeException("Quality", "Quality must be a positive integer <= 100");
|
||||||
|
using (EncoderParameters ep = new EncoderParameters(1))
|
||||||
|
{
|
||||||
|
ep.Param[0] = new EncoderParameter(Encoder.Quality, Quality);
|
||||||
|
Source.Save(OutStream, jpgCodec, ep);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Fallback
|
||||||
|
Source.Save(OutStream, ImageFormat.Jpeg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Color InterpolateColours(this Color Start, Color End, double Progress)
|
||||||
|
{
|
||||||
|
if (Progress > 1 || Progress < 0)
|
||||||
|
throw new ArgumentOutOfRangeException("Progress", "Progress must be >= 0 && <= 1");
|
||||||
|
|
||||||
|
return Color.FromArgb(
|
||||||
|
(byte)(Start.A * (1 - Progress) + (End.A * Progress)),
|
||||||
|
(byte)(Start.R * (1 - Progress) + (End.R * Progress)),
|
||||||
|
(byte)(Start.G * (1 - Progress) + (End.G * Progress)),
|
||||||
|
(byte)(Start.B * (1 - Progress) + (End.B * Progress))
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static RectangleF Multiply(this RectangleF Other, float Multiplier)
|
||||||
|
{
|
||||||
|
return new RectangleF(Other.X * Multiplier, Other.Y * Multiplier, Other.Width * Multiplier, Other.Height * Multiplier);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static RectangleF Divide(this RectangleF Other, float Divisor)
|
||||||
|
{
|
||||||
|
return new RectangleF(Other.X / Divisor, Other.Y / Divisor, Other.Width / Divisor, Other.Height / Divisor);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,13 +1,12 @@
|
|||||||
using System;
|
using Disco.Models.Repository;
|
||||||
|
using Disco.Services.Interop.ActiveDirectory;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.DirectoryServices;
|
using System.DirectoryServices;
|
||||||
using System.DirectoryServices.ActiveDirectory;
|
using System.DirectoryServices.ActiveDirectory;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Net.NetworkInformation;
|
using System.Net.NetworkInformation;
|
||||||
using System.Text;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
|
|
||||||
namespace Disco.Services.Interop.ActiveDirectory
|
namespace Disco.Services
|
||||||
{
|
{
|
||||||
public static class ActiveDirectoryExtensions
|
public static class ActiveDirectoryExtensions
|
||||||
{
|
{
|
||||||
@@ -98,6 +97,17 @@ namespace Disco.Services.Interop.ActiveDirectory
|
|||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
|
public static ADUserAccount ActiveDirectoryAccount(this User User, params string[] AdditionalProperties)
|
||||||
|
{
|
||||||
|
return ActiveDirectory.RetrieveADUserAccount(User.UserId, AdditionalProperties);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static ADMachineAccount ActiveDirectoryAccount(this Device Device, params string[] AdditionalProperties)
|
||||||
|
{
|
||||||
|
if (ActiveDirectory.IsValidDomainAccountId(Device.DeviceDomainId))
|
||||||
|
return ActiveDirectory.RetrieveADMachineAccount(Device.DeviceDomainId, AdditionalProperties: AdditionalProperties);
|
||||||
|
else
|
||||||
|
return null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,10 +1,6 @@
|
|||||||
using System;
|
using Microsoft.Win32;
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
|
||||||
using Microsoft.Win32;
|
|
||||||
|
|
||||||
namespace Disco.BI.Interop
|
namespace Disco.Services.Interop
|
||||||
{
|
{
|
||||||
public static class MimeTypes
|
public static class MimeTypes
|
||||||
{
|
{
|
||||||
+113
@@ -0,0 +1,113 @@
|
|||||||
|
//------------------------------------------------------------------------------
|
||||||
|
// <auto-generated>
|
||||||
|
// This code was generated by a tool.
|
||||||
|
// Runtime Version:4.0.30319.42000
|
||||||
|
//
|
||||||
|
// Changes to this file may cause incorrect behavior and will be lost if
|
||||||
|
// the code is regenerated.
|
||||||
|
// </auto-generated>
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
namespace Disco.Services.Properties {
|
||||||
|
using System;
|
||||||
|
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// A strongly-typed resource class, for looking up localized strings, etc.
|
||||||
|
/// </summary>
|
||||||
|
// This class was auto-generated by the StronglyTypedResourceBuilder
|
||||||
|
// class via a tool like ResGen or Visual Studio.
|
||||||
|
// To add or remove a member, edit your .ResX file then rerun ResGen
|
||||||
|
// with the /str option, or rebuild your VS project.
|
||||||
|
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")]
|
||||||
|
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
|
||||||
|
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
|
||||||
|
internal class Resources {
|
||||||
|
|
||||||
|
private static global::System.Resources.ResourceManager resourceMan;
|
||||||
|
|
||||||
|
private static global::System.Globalization.CultureInfo resourceCulture;
|
||||||
|
|
||||||
|
[global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
|
||||||
|
internal Resources() {
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns the cached ResourceManager instance used by this class.
|
||||||
|
/// </summary>
|
||||||
|
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
|
||||||
|
internal static global::System.Resources.ResourceManager ResourceManager {
|
||||||
|
get {
|
||||||
|
if (object.ReferenceEquals(resourceMan, null)) {
|
||||||
|
global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("Disco.Services.Properties.Resources", typeof(Resources).Assembly);
|
||||||
|
resourceMan = temp;
|
||||||
|
}
|
||||||
|
return resourceMan;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Overrides the current thread's CurrentUICulture property for all
|
||||||
|
/// resource lookups using this strongly typed resource class.
|
||||||
|
/// </summary>
|
||||||
|
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
|
||||||
|
internal static global::System.Globalization.CultureInfo Culture {
|
||||||
|
get {
|
||||||
|
return resourceCulture;
|
||||||
|
}
|
||||||
|
set {
|
||||||
|
resourceCulture = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Looks up a localized resource of type System.Drawing.Bitmap.
|
||||||
|
/// </summary>
|
||||||
|
internal static System.Drawing.Bitmap MimeType_doc48 {
|
||||||
|
get {
|
||||||
|
object obj = ResourceManager.GetObject("MimeType_doc48", resourceCulture);
|
||||||
|
return ((System.Drawing.Bitmap)(obj));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Looks up a localized resource of type System.Drawing.Bitmap.
|
||||||
|
/// </summary>
|
||||||
|
internal static System.Drawing.Bitmap MimeType_img16 {
|
||||||
|
get {
|
||||||
|
object obj = ResourceManager.GetObject("MimeType_img16", resourceCulture);
|
||||||
|
return ((System.Drawing.Bitmap)(obj));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Looks up a localized resource of type System.Drawing.Bitmap.
|
||||||
|
/// </summary>
|
||||||
|
internal static System.Drawing.Bitmap MimeType_pdf16 {
|
||||||
|
get {
|
||||||
|
object obj = ResourceManager.GetObject("MimeType_pdf16", resourceCulture);
|
||||||
|
return ((System.Drawing.Bitmap)(obj));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Looks up a localized resource of type System.Drawing.Bitmap.
|
||||||
|
/// </summary>
|
||||||
|
internal static System.Drawing.Bitmap MimeType_pdf48 {
|
||||||
|
get {
|
||||||
|
object obj = ResourceManager.GetObject("MimeType_pdf48", resourceCulture);
|
||||||
|
return ((System.Drawing.Bitmap)(obj));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Looks up a localized resource of type System.Drawing.Bitmap.
|
||||||
|
/// </summary>
|
||||||
|
internal static System.Drawing.Bitmap MimeType_unknown48 {
|
||||||
|
get {
|
||||||
|
object obj = ResourceManager.GetObject("MimeType_unknown48", resourceCulture);
|
||||||
|
return ((System.Drawing.Bitmap)(obj));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,136 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<root>
|
||||||
|
<!--
|
||||||
|
Microsoft ResX Schema
|
||||||
|
|
||||||
|
Version 2.0
|
||||||
|
|
||||||
|
The primary goals of this format is to allow a simple XML format
|
||||||
|
that is mostly human readable. The generation and parsing of the
|
||||||
|
various data types are done through the TypeConverter classes
|
||||||
|
associated with the data types.
|
||||||
|
|
||||||
|
Example:
|
||||||
|
|
||||||
|
... ado.net/XML headers & schema ...
|
||||||
|
<resheader name="resmimetype">text/microsoft-resx</resheader>
|
||||||
|
<resheader name="version">2.0</resheader>
|
||||||
|
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
|
||||||
|
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
|
||||||
|
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
|
||||||
|
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
|
||||||
|
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
|
||||||
|
<value>[base64 mime encoded serialized .NET Framework object]</value>
|
||||||
|
</data>
|
||||||
|
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||||
|
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
|
||||||
|
<comment>This is a comment</comment>
|
||||||
|
</data>
|
||||||
|
|
||||||
|
There are any number of "resheader" rows that contain simple
|
||||||
|
name/value pairs.
|
||||||
|
|
||||||
|
Each data row contains a name, and value. The row also contains a
|
||||||
|
type or mimetype. Type corresponds to a .NET class that support
|
||||||
|
text/value conversion through the TypeConverter architecture.
|
||||||
|
Classes that don't support this are serialized and stored with the
|
||||||
|
mimetype set.
|
||||||
|
|
||||||
|
The mimetype is used for serialized objects, and tells the
|
||||||
|
ResXResourceReader how to depersist the object. This is currently not
|
||||||
|
extensible. For a given mimetype the value must be set accordingly:
|
||||||
|
|
||||||
|
Note - application/x-microsoft.net.object.binary.base64 is the format
|
||||||
|
that the ResXResourceWriter will generate, however the reader can
|
||||||
|
read any of the formats listed below.
|
||||||
|
|
||||||
|
mimetype: application/x-microsoft.net.object.binary.base64
|
||||||
|
value : The object must be serialized with
|
||||||
|
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
|
||||||
|
: and then encoded with base64 encoding.
|
||||||
|
|
||||||
|
mimetype: application/x-microsoft.net.object.soap.base64
|
||||||
|
value : The object must be serialized with
|
||||||
|
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
|
||||||
|
: and then encoded with base64 encoding.
|
||||||
|
|
||||||
|
mimetype: application/x-microsoft.net.object.bytearray.base64
|
||||||
|
value : The object must be serialized into a byte array
|
||||||
|
: using a System.ComponentModel.TypeConverter
|
||||||
|
: and then encoded with base64 encoding.
|
||||||
|
-->
|
||||||
|
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
|
||||||
|
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
|
||||||
|
<xsd:element name="root" msdata:IsDataSet="true">
|
||||||
|
<xsd:complexType>
|
||||||
|
<xsd:choice maxOccurs="unbounded">
|
||||||
|
<xsd:element name="metadata">
|
||||||
|
<xsd:complexType>
|
||||||
|
<xsd:sequence>
|
||||||
|
<xsd:element name="value" type="xsd:string" minOccurs="0" />
|
||||||
|
</xsd:sequence>
|
||||||
|
<xsd:attribute name="name" use="required" type="xsd:string" />
|
||||||
|
<xsd:attribute name="type" type="xsd:string" />
|
||||||
|
<xsd:attribute name="mimetype" type="xsd:string" />
|
||||||
|
<xsd:attribute ref="xml:space" />
|
||||||
|
</xsd:complexType>
|
||||||
|
</xsd:element>
|
||||||
|
<xsd:element name="assembly">
|
||||||
|
<xsd:complexType>
|
||||||
|
<xsd:attribute name="alias" type="xsd:string" />
|
||||||
|
<xsd:attribute name="name" type="xsd:string" />
|
||||||
|
</xsd:complexType>
|
||||||
|
</xsd:element>
|
||||||
|
<xsd:element name="data">
|
||||||
|
<xsd:complexType>
|
||||||
|
<xsd:sequence>
|
||||||
|
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||||
|
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
|
||||||
|
</xsd:sequence>
|
||||||
|
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
|
||||||
|
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
|
||||||
|
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
|
||||||
|
<xsd:attribute ref="xml:space" />
|
||||||
|
</xsd:complexType>
|
||||||
|
</xsd:element>
|
||||||
|
<xsd:element name="resheader">
|
||||||
|
<xsd:complexType>
|
||||||
|
<xsd:sequence>
|
||||||
|
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||||
|
</xsd:sequence>
|
||||||
|
<xsd:attribute name="name" type="xsd:string" use="required" />
|
||||||
|
</xsd:complexType>
|
||||||
|
</xsd:element>
|
||||||
|
</xsd:choice>
|
||||||
|
</xsd:complexType>
|
||||||
|
</xsd:element>
|
||||||
|
</xsd:schema>
|
||||||
|
<resheader name="resmimetype">
|
||||||
|
<value>text/microsoft-resx</value>
|
||||||
|
</resheader>
|
||||||
|
<resheader name="version">
|
||||||
|
<value>2.0</value>
|
||||||
|
</resheader>
|
||||||
|
<resheader name="reader">
|
||||||
|
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||||
|
</resheader>
|
||||||
|
<resheader name="writer">
|
||||||
|
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||||
|
</resheader>
|
||||||
|
<assembly alias="System.Windows.Forms" name="System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />
|
||||||
|
<data name="MimeType_doc48" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
||||||
|
<value>..\resources\mimetype-doc48.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
|
||||||
|
</data>
|
||||||
|
<data name="MimeType_img16" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
||||||
|
<value>..\resources\mimetype-img16.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
|
||||||
|
</data>
|
||||||
|
<data name="MimeType_pdf16" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
||||||
|
<value>..\resources\mimetype-pdf16.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
|
||||||
|
</data>
|
||||||
|
<data name="MimeType_pdf48" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
||||||
|
<value>..\resources\mimetype-pdf48.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
|
||||||
|
</data>
|
||||||
|
<data name="MimeType_unknown48" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
||||||
|
<value>..\resources\mimetype-unknown48.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
|
||||||
|
</data>
|
||||||
|
</root>
|
||||||
Binary file not shown.
|
After Width: | Height: | Size: 5.7 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 3.1 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 3.2 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 5.1 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 4.2 KiB |
@@ -16,6 +16,8 @@
|
|||||||
<package id="Microsoft.Web.Infrastructure" version="1.0.0.0" targetFramework="net40" />
|
<package id="Microsoft.Web.Infrastructure" version="1.0.0.0" targetFramework="net40" />
|
||||||
<package id="Newtonsoft.Json" version="6.0.3" targetFramework="net45" />
|
<package id="Newtonsoft.Json" version="6.0.3" targetFramework="net45" />
|
||||||
<package id="Owin" version="1.0" targetFramework="net45" />
|
<package id="Owin" version="1.0" targetFramework="net45" />
|
||||||
|
<package id="PdfiumViewer" version="2.10.0.0" targetFramework="net45" />
|
||||||
|
<package id="PDFsharp" version="1.32.3057.0" targetFramework="net45" />
|
||||||
<package id="RazorGenerator.Mvc" version="2.2.3" targetFramework="net45" />
|
<package id="RazorGenerator.Mvc" version="2.2.3" targetFramework="net45" />
|
||||||
<package id="Rx-Core" version="2.2.5" targetFramework="net45" />
|
<package id="Rx-Core" version="2.2.5" targetFramework="net45" />
|
||||||
<package id="Rx-Interfaces" version="2.2.5" targetFramework="net45" />
|
<package id="Rx-Interfaces" version="2.2.5" targetFramework="net45" />
|
||||||
@@ -24,4 +26,5 @@
|
|||||||
<package id="Rx-PlatformServices" version="2.2.5" targetFramework="net45" />
|
<package id="Rx-PlatformServices" version="2.2.5" targetFramework="net45" />
|
||||||
<package id="SqlServerCompact" version="4.0.8854.1" targetFramework="net40" />
|
<package id="SqlServerCompact" version="4.0.8854.1" targetFramework="net40" />
|
||||||
<package id="WebActivatorEx" version="2.0.5" targetFramework="net45" />
|
<package id="WebActivatorEx" version="2.0.5" targetFramework="net45" />
|
||||||
|
<package id="ZXing.Net" version="0.14.0.1" targetFramework="net45" />
|
||||||
</packages>
|
</packages>
|
||||||
Binary file not shown.
@@ -1,10 +1,10 @@
|
|||||||
using Disco.Data.Repository;
|
using Disco.Data.Repository;
|
||||||
|
using Disco.Services;
|
||||||
using Disco.Services.Interop.DiscoServices;
|
using Disco.Services.Interop.DiscoServices;
|
||||||
using Exceptionless;
|
using Exceptionless;
|
||||||
using Exceptionless.Configuration;
|
using Exceptionless.Configuration;
|
||||||
using System;
|
using System;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Web;
|
|
||||||
|
|
||||||
[assembly: Exceptionless("https://errors.discoict.com.au", "c81e644582374f68aaf1fb546e3db0cd")]
|
[assembly: Exceptionless("https://errors.discoict.com.au", "c81e644582374f68aaf1fb546e3db0cd")]
|
||||||
|
|
||||||
@@ -67,7 +67,7 @@ namespace Disco.Web
|
|||||||
InitalizeCoreEnvironment(Database);
|
InitalizeCoreEnvironment(Database);
|
||||||
|
|
||||||
// Initialize Expressions
|
// Initialize Expressions
|
||||||
BI.Expressions.Expression.InitializeExpressions();
|
Disco.Services.Expressions.Expression.InitializeExpressions();
|
||||||
|
|
||||||
// Initialize Job Queues
|
// Initialize Job Queues
|
||||||
Disco.Services.Jobs.JobQueues.JobQueueService.Initialize(Database);
|
Disco.Services.Jobs.JobQueues.JobQueueService.Initialize(Database);
|
||||||
@@ -93,10 +93,11 @@ namespace Disco.Web
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Setup Attachment Monitor
|
// Setup Attachment Monitor
|
||||||
DiscoApplication.DocumentDropBoxMonitor = new BI.DocumentTemplateBI.Importer.DocumentDropBoxMonitor(Database, DiscoApplication.SchedulerFactory, HttpContext.Current.Cache);
|
var dropboxLocation = DataStore.CreateLocation(Database, "DocumentDropBox");
|
||||||
|
DiscoApplication.DocumentDropBoxMonitor = new Services.Documents.AttachmentImport.ImportDirectoryMonitor(dropboxLocation, DiscoApplication.SchedulerFactory.GetScheduler(), 5000);
|
||||||
|
|
||||||
DiscoApplication.DocumentDropBoxMonitor.StartWatching();
|
DiscoApplication.DocumentDropBoxMonitor.Start();
|
||||||
DiscoApplication.DocumentDropBoxMonitor.ScheduleCurrentFiles(10);
|
DiscoApplication.DocumentDropBoxMonitor.ScheduleCurrentFiles(10000); // 10 Second Delay
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void InitializeUpdateEnvironment(DiscoDataContext Database, Version PreviousVersion)
|
public static void InitializeUpdateEnvironment(DiscoDataContext Database, Version PreviousVersion)
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
using Disco.BI.Extensions;
|
using Disco.BI.Extensions;
|
||||||
using Disco.Models.Repository;
|
using Disco.Models.Repository;
|
||||||
|
using Disco.Services;
|
||||||
using Disco.Services.Authorization;
|
using Disco.Services.Authorization;
|
||||||
using Disco.Services.Devices.ManagedGroups;
|
using Disco.Services.Devices.ManagedGroups;
|
||||||
using Disco.Services.Interop.ActiveDirectory;
|
using Disco.Services.Interop.ActiveDirectory;
|
||||||
|
|||||||
@@ -1,9 +1,12 @@
|
|||||||
using Disco.BI.Extensions;
|
using Disco.BI.Extensions;
|
||||||
using Disco.Models.Repository;
|
using Disco.Models.Repository;
|
||||||
using Disco.Models.Services.Devices.Importing;
|
using Disco.Models.Services.Devices.Importing;
|
||||||
|
using Disco.Models.Services.Documents;
|
||||||
|
using Disco.Services;
|
||||||
using Disco.Services.Authorization;
|
using Disco.Services.Authorization;
|
||||||
using Disco.Services.Devices.Exporting;
|
using Disco.Services.Devices.Exporting;
|
||||||
using Disco.Services.Devices.Importing;
|
using Disco.Services.Devices.Importing;
|
||||||
|
using Disco.Services.Interop;
|
||||||
using Disco.Services.Interop.ActiveDirectory;
|
using Disco.Services.Interop.ActiveDirectory;
|
||||||
using Disco.Services.Users;
|
using Disco.Services.Users;
|
||||||
using Disco.Services.Web;
|
using Disco.Services.Web;
|
||||||
@@ -388,7 +391,7 @@ namespace Disco.Web.Areas.API.Controllers
|
|||||||
{
|
{
|
||||||
var timeStamp = DateTime.Now;
|
var timeStamp = DateTime.Now;
|
||||||
Stream pdf;
|
Stream pdf;
|
||||||
using (var generationState = Disco.Models.BI.DocumentTemplates.DocumentState.DefaultState())
|
using (var generationState = DocumentState.DefaultState())
|
||||||
{
|
{
|
||||||
pdf = documentTemplate.GeneratePdf(Database, device, UserService.CurrentUser, timeStamp, generationState);
|
pdf = documentTemplate.GeneratePdf(Database, device, UserService.CurrentUser, timeStamp, generationState);
|
||||||
}
|
}
|
||||||
@@ -485,7 +488,7 @@ namespace Disco.Web.Areas.API.Controllers
|
|||||||
{
|
{
|
||||||
var contentType = file.ContentType;
|
var contentType = file.ContentType;
|
||||||
if (string.IsNullOrEmpty(contentType) || contentType.Equals("unknown/unknown", StringComparison.OrdinalIgnoreCase))
|
if (string.IsNullOrEmpty(contentType) || contentType.Equals("unknown/unknown", StringComparison.OrdinalIgnoreCase))
|
||||||
contentType = BI.Interop.MimeTypes.ResolveMimeType(file.FileName);
|
contentType = MimeTypes.ResolveMimeType(file.FileName);
|
||||||
|
|
||||||
var da = new DeviceAttachment()
|
var da = new DeviceAttachment()
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
using Disco.BI.Extensions;
|
using Disco.BI.Extensions;
|
||||||
using Disco.Models.Repository;
|
using Disco.Models.Repository;
|
||||||
|
using Disco.Services;
|
||||||
using Disco.Services.Authorization;
|
using Disco.Services.Authorization;
|
||||||
using Disco.Services.Plugins;
|
using Disco.Services.Plugins;
|
||||||
using Disco.Services.Plugins.Features.RepairProvider;
|
using Disco.Services.Plugins.Features.RepairProvider;
|
||||||
|
|||||||
@@ -2,7 +2,9 @@
|
|||||||
using Disco.BI.DocumentTemplateBI.ManagedGroups;
|
using Disco.BI.DocumentTemplateBI.ManagedGroups;
|
||||||
using Disco.BI.Extensions;
|
using Disco.BI.Extensions;
|
||||||
using Disco.Models.Repository;
|
using Disco.Models.Repository;
|
||||||
|
using Disco.Services;
|
||||||
using Disco.Services.Authorization;
|
using Disco.Services.Authorization;
|
||||||
|
using Disco.Services.Documents;
|
||||||
using Disco.Services.Interop.ActiveDirectory;
|
using Disco.Services.Interop.ActiveDirectory;
|
||||||
using Disco.Services.Tasks;
|
using Disco.Services.Tasks;
|
||||||
using Disco.Services.Users;
|
using Disco.Services.Users;
|
||||||
@@ -558,7 +560,9 @@ namespace Disco.Web.Areas.API.Controllers
|
|||||||
{
|
{
|
||||||
var undetectedLocation = DataStore.CreateLocation(Database, "DocumentDropBox_Unassigned");
|
var undetectedLocation = DataStore.CreateLocation(Database, "DocumentDropBox_Unassigned");
|
||||||
var filename = System.IO.Path.Combine(undetectedLocation, string.Concat(id, ".pdf"));
|
var filename = System.IO.Path.Combine(undetectedLocation, string.Concat(id, ".pdf"));
|
||||||
if (BI.Interop.Pdf.PdfImporter.ProcessPdfAttachment(filename, Database, DocumentTemplateId, DataId, UserService.CurrentUser.UserId, DateTime.Now))
|
var identifier = DocumentUniqueIdentifier.Create(Database, DocumentTemplateId, DataId, UserService.CurrentUser.UserId, DateTime.Now, 0);
|
||||||
|
|
||||||
|
if (Disco.Services.Documents.AttachmentImport.Importer.ImportPdfAttachment(identifier, Database, filename))
|
||||||
{
|
{
|
||||||
// Delete File
|
// Delete File
|
||||||
System.IO.File.Delete(filename);
|
System.IO.File.Delete(filename);
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
using Disco.Services.Authorization;
|
using Disco.Services.Authorization;
|
||||||
|
using Disco.Services.Expressions;
|
||||||
using Disco.Services.Web;
|
using Disco.Services.Web;
|
||||||
using System.Web.Mvc;
|
using System.Web.Mvc;
|
||||||
|
|
||||||
@@ -9,7 +10,7 @@ namespace Disco.Web.Areas.API.Controllers
|
|||||||
{
|
{
|
||||||
public virtual ActionResult ValidateExpression(string Expression)
|
public virtual ActionResult ValidateExpression(string Expression)
|
||||||
{
|
{
|
||||||
var part = new BI.Expressions.EvaluateExpressionPart(Expression);
|
var part = new EvaluateExpressionPart(Expression);
|
||||||
return Json(Models.Expressions.ValidateExpressionModel.FromEvaluateExpressionPart(part), JsonRequestBehavior.AllowGet);
|
return Json(Models.Expressions.ValidateExpressionModel.FromEvaluateExpressionPart(part), JsonRequestBehavior.AllowGet);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,8 +1,10 @@
|
|||||||
using Disco.BI.Extensions;
|
using Disco.BI.Extensions;
|
||||||
using Disco.Models.Repository;
|
using Disco.Models.Repository;
|
||||||
|
using Disco.Models.Services.Documents;
|
||||||
using Disco.Models.Services.Jobs.JobLists;
|
using Disco.Models.Services.Jobs.JobLists;
|
||||||
using Disco.Services;
|
using Disco.Services;
|
||||||
using Disco.Services.Authorization;
|
using Disco.Services.Authorization;
|
||||||
|
using Disco.Services.Interop;
|
||||||
using Disco.Services.Jobs.JobLists;
|
using Disco.Services.Jobs.JobLists;
|
||||||
using Disco.Services.Users;
|
using Disco.Services.Users;
|
||||||
using Disco.Services.Web;
|
using Disco.Services.Web;
|
||||||
@@ -1920,9 +1922,9 @@ namespace Disco.Web.Areas.API.Controllers
|
|||||||
{
|
{
|
||||||
var contentType = file.ContentType;
|
var contentType = file.ContentType;
|
||||||
if (string.IsNullOrEmpty(contentType) || contentType.Equals("unknown/unknown", StringComparison.OrdinalIgnoreCase))
|
if (string.IsNullOrEmpty(contentType) || contentType.Equals("unknown/unknown", StringComparison.OrdinalIgnoreCase))
|
||||||
contentType = BI.Interop.MimeTypes.ResolveMimeType(file.FileName);
|
contentType = MimeTypes.ResolveMimeType(file.FileName);
|
||||||
|
|
||||||
var ja = new Disco.Models.Repository.JobAttachment()
|
var ja = new JobAttachment()
|
||||||
{
|
{
|
||||||
JobId = j.Id,
|
JobId = j.Id,
|
||||||
TechUserId = CurrentUser.UserId,
|
TechUserId = CurrentUser.UserId,
|
||||||
@@ -2096,7 +2098,7 @@ namespace Disco.Web.Areas.API.Controllers
|
|||||||
{
|
{
|
||||||
var timeStamp = DateTime.Now;
|
var timeStamp = DateTime.Now;
|
||||||
Stream pdf;
|
Stream pdf;
|
||||||
using (var generationState = Disco.Models.BI.DocumentTemplates.DocumentState.DefaultState())
|
using (var generationState = DocumentState.DefaultState())
|
||||||
{
|
{
|
||||||
pdf = documentTemplate.GeneratePdf(Database, job, CurrentUser, timeStamp, generationState);
|
pdf = documentTemplate.GeneratePdf(Database, job, CurrentUser, timeStamp, generationState);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
using Disco.BI.Extensions;
|
using Disco.BI.Extensions;
|
||||||
using Disco.Data.Configuration;
|
using Disco.Data.Configuration;
|
||||||
|
using Disco.Services;
|
||||||
using Disco.Services.Authorization;
|
using Disco.Services.Authorization;
|
||||||
using Disco.Services.Interop.ActiveDirectory;
|
using Disco.Services.Interop.ActiveDirectory;
|
||||||
using Disco.Services.Interop.DiscoServices;
|
using Disco.Services.Interop.DiscoServices;
|
||||||
|
|||||||
@@ -1,5 +1,8 @@
|
|||||||
using Disco.BI.Extensions;
|
using Disco.BI.Extensions;
|
||||||
|
using Disco.Models.Services.Documents;
|
||||||
|
using Disco.Services;
|
||||||
using Disco.Services.Authorization;
|
using Disco.Services.Authorization;
|
||||||
|
using Disco.Services.Interop;
|
||||||
using Disco.Services.Interop.ActiveDirectory;
|
using Disco.Services.Interop.ActiveDirectory;
|
||||||
using Disco.Services.Users;
|
using Disco.Services.Users;
|
||||||
using Disco.Services.Web;
|
using Disco.Services.Web;
|
||||||
@@ -70,7 +73,7 @@ namespace Disco.Web.Areas.API.Controllers
|
|||||||
{
|
{
|
||||||
var contentType = file.ContentType;
|
var contentType = file.ContentType;
|
||||||
if (string.IsNullOrEmpty(contentType) || contentType.Equals("unknown/unknown", StringComparison.OrdinalIgnoreCase))
|
if (string.IsNullOrEmpty(contentType) || contentType.Equals("unknown/unknown", StringComparison.OrdinalIgnoreCase))
|
||||||
contentType = BI.Interop.MimeTypes.ResolveMimeType(file.FileName);
|
contentType = MimeTypes.ResolveMimeType(file.FileName);
|
||||||
|
|
||||||
var ua = new Disco.Models.Repository.UserAttachment()
|
var ua = new Disco.Models.Repository.UserAttachment()
|
||||||
{
|
{
|
||||||
@@ -171,7 +174,7 @@ namespace Disco.Web.Areas.API.Controllers
|
|||||||
{
|
{
|
||||||
var timeStamp = DateTime.Now;
|
var timeStamp = DateTime.Now;
|
||||||
Stream pdf;
|
Stream pdf;
|
||||||
using (var generationState = Disco.Models.BI.DocumentTemplates.DocumentState.DefaultState())
|
using (var generationState = DocumentState.DefaultState())
|
||||||
{
|
{
|
||||||
pdf = documentTemplate.GeneratePdf(Database, user, UserService.CurrentUser, timeStamp, generationState);
|
pdf = documentTemplate.GeneratePdf(Database, user, UserService.CurrentUser, timeStamp, generationState);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,8 +1,5 @@
|
|||||||
using System;
|
using Disco.Services.Expressions;
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Web;
|
using System.Web;
|
||||||
using Disco.BI.Expressions;
|
|
||||||
|
|
||||||
namespace Disco.Web.Areas.API.Models.Expressions
|
namespace Disco.Web.Areas.API.Models.Expressions
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,7 +1,9 @@
|
|||||||
using Disco.BI.DocumentTemplateBI.ManagedGroups;
|
using Disco.BI.DocumentTemplateBI.ManagedGroups;
|
||||||
using Disco.BI.Extensions;
|
using Disco.BI.Extensions;
|
||||||
using Disco.Models.UI.Config.DocumentTemplate;
|
using Disco.Models.UI.Config.DocumentTemplate;
|
||||||
|
using Disco.Services;
|
||||||
using Disco.Services.Authorization;
|
using Disco.Services.Authorization;
|
||||||
|
using Disco.Services.Expressions;
|
||||||
using Disco.Services.Plugins.Features.UIExtension;
|
using Disco.Services.Plugins.Features.UIExtension;
|
||||||
using Disco.Services.Web;
|
using Disco.Services.Web;
|
||||||
using System;
|
using System;
|
||||||
@@ -137,8 +139,8 @@ namespace Disco.Web.Areas.Config.Controllers
|
|||||||
DeviceType = typeof(Disco.Models.Repository.Device).AssemblyQualifiedName,
|
DeviceType = typeof(Disco.Models.Repository.Device).AssemblyQualifiedName,
|
||||||
JobType = typeof(Disco.Models.Repository.Job).AssemblyQualifiedName,
|
JobType = typeof(Disco.Models.Repository.Job).AssemblyQualifiedName,
|
||||||
UserType = typeof(Disco.Models.Repository.User).AssemblyQualifiedName,
|
UserType = typeof(Disco.Models.Repository.User).AssemblyQualifiedName,
|
||||||
Variables = BI.Expressions.Expression.StandardVariableTypes(),
|
Variables = Expression.StandardVariableTypes(),
|
||||||
ExtensionLibraries = BI.Expressions.Expression.ExtensionLibraryTypes()
|
ExtensionLibraries = Expression.ExtensionLibraryTypes()
|
||||||
};
|
};
|
||||||
|
|
||||||
// UI Extensions
|
// UI Extensions
|
||||||
@@ -151,7 +153,7 @@ namespace Disco.Web.Areas.Config.Controllers
|
|||||||
var t = Type.GetType(type);
|
var t = Type.GetType(type);
|
||||||
if (t != null)
|
if (t != null)
|
||||||
{
|
{
|
||||||
return Json(BI.Expressions.ExpressionTypeDescriptor.Build(t, StaticDeclaredMembersOnly), JsonRequestBehavior.AllowGet);
|
return Json(ExpressionTypeDescriptor.Build(t, StaticDeclaredMembersOnly), JsonRequestBehavior.AllowGet);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,11 +1,10 @@
|
|||||||
using System;
|
using Disco.BI.DocumentTemplateBI.ManagedGroups;
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Web;
|
|
||||||
using Disco.Data.Repository;
|
using Disco.Data.Repository;
|
||||||
using Disco.Models.Repository;
|
using Disco.Models.Repository;
|
||||||
using Disco.Models.UI.Config.DocumentTemplate;
|
using Disco.Models.UI.Config.DocumentTemplate;
|
||||||
using Disco.BI.DocumentTemplateBI.ManagedGroups;
|
using Disco.Services.Expressions;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
|
||||||
namespace Disco.Web.Areas.Config.Models.DocumentTemplate
|
namespace Disco.Web.Areas.Config.Models.DocumentTemplate
|
||||||
{
|
{
|
||||||
@@ -15,9 +14,9 @@ namespace Disco.Web.Areas.Config.Models.DocumentTemplate
|
|||||||
|
|
||||||
public int StoredInstanceCount { get; set; }
|
public int StoredInstanceCount { get; set; }
|
||||||
|
|
||||||
public List<Disco.BI.Expressions.Expression> TemplateExpressions { get; set; }
|
public List<Expression> TemplateExpressions { get; set; }
|
||||||
|
|
||||||
public List<Disco.Models.Repository.JobType> JobTypes { get; set; }
|
public List<JobType> JobTypes { get; set; }
|
||||||
|
|
||||||
public List<string> Scopes
|
public List<string> Scopes
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -306,7 +306,7 @@
|
|||||||
logHub = $.connection.logNotifications;
|
logHub = $.connection.logNotifications;
|
||||||
logHub.client.receiveLog = parseLog
|
logHub.client.receiveLog = parseLog
|
||||||
|
|
||||||
$.connection.hub.qs = { LogModules: '@(Disco.BI.DocumentTemplateBI.DocumentsLog.Current.LiveLogGroupName)' };
|
$.connection.hub.qs = { LogModules: '@(Disco.Services.Documents.DocumentsLog.Current.LiveLogGroupName)' };
|
||||||
$.connection.hub.error(onHubFailed);
|
$.connection.hub.error(onHubFailed);
|
||||||
|
|
||||||
$.connection.hub.start()
|
$.connection.hub.start()
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
// <auto-generated>
|
// <auto-generated>
|
||||||
// This code was generated by a tool.
|
// This code was generated by a tool.
|
||||||
// Runtime Version:4.0.30319.34014
|
// Runtime Version:4.0.30319.42000
|
||||||
//
|
//
|
||||||
// Changes to this file may cause incorrect behavior and will be lost if
|
// Changes to this file may cause incorrect behavior and will be lost if
|
||||||
// the code is regenerated.
|
// the code is regenerated.
|
||||||
@@ -466,7 +466,7 @@ WriteLiteral(@"',
|
|||||||
|
|
||||||
|
|
||||||
#line 309 "..\..\Areas\Config\Views\DocumentTemplate\ImportStatus.cshtml"
|
#line 309 "..\..\Areas\Config\Views\DocumentTemplate\ImportStatus.cshtml"
|
||||||
Write(Disco.BI.DocumentTemplateBI.DocumentsLog.Current.LiveLogGroupName);
|
Write(Disco.Services.Documents.DocumentsLog.Current.LiveLogGroupName);
|
||||||
|
|
||||||
|
|
||||||
#line default
|
#line default
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
@model IEnumerable<Disco.BI.Expressions.Expression>
|
@model IEnumerable<Disco.Services.Expressions.Expression>
|
||||||
@{
|
@{
|
||||||
Authorization.Require(Claims.Config.DocumentTemplate.Show);
|
Authorization.Require(Claims.Config.DocumentTemplate.Show);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
// <auto-generated>
|
// <auto-generated>
|
||||||
// This code was generated by a tool.
|
// This code was generated by a tool.
|
||||||
// Runtime Version:4.0.30319.34014
|
// Runtime Version:4.0.30319.42000
|
||||||
//
|
//
|
||||||
// Changes to this file may cause incorrect behavior and will be lost if
|
// Changes to this file may cause incorrect behavior and will be lost if
|
||||||
// the code is regenerated.
|
// the code is regenerated.
|
||||||
@@ -37,9 +37,9 @@ namespace Disco.Web.Areas.Config.Views.DocumentTemplate
|
|||||||
|
|
||||||
[System.CodeDom.Compiler.GeneratedCodeAttribute("RazorGenerator", "2.0.0.0")]
|
[System.CodeDom.Compiler.GeneratedCodeAttribute("RazorGenerator", "2.0.0.0")]
|
||||||
[System.Web.WebPages.PageVirtualPathAttribute("~/Areas/Config/Views/DocumentTemplate/_ExpressionsTable.cshtml")]
|
[System.Web.WebPages.PageVirtualPathAttribute("~/Areas/Config/Views/DocumentTemplate/_ExpressionsTable.cshtml")]
|
||||||
public partial class ExpressionsTable : Disco.Services.Web.WebViewPage<IEnumerable<Disco.BI.Expressions.Expression>>
|
public partial class _ExpressionsTable : Disco.Services.Web.WebViewPage<IEnumerable<Disco.Services.Expressions.Expression>>
|
||||||
{
|
{
|
||||||
public ExpressionsTable()
|
public _ExpressionsTable()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
public override void Execute()
|
public override void Execute()
|
||||||
@@ -107,14 +107,14 @@ WriteLiteral(@">
|
|||||||
#line hidden
|
#line hidden
|
||||||
WriteLiteral(" <tr>\r\n <td");
|
WriteLiteral(" <tr>\r\n <td");
|
||||||
|
|
||||||
WriteAttribute("rowspan", Tuple.Create(" rowspan=\"", 719), Tuple.Create("\"", 754)
|
WriteAttribute("rowspan", Tuple.Create(" rowspan=\"", 725), Tuple.Create("\"", 760)
|
||||||
|
|
||||||
#line 24 "..\..\Areas\Config\Views\DocumentTemplate\_ExpressionsTable.cshtml"
|
#line 24 "..\..\Areas\Config\Views\DocumentTemplate\_ExpressionsTable.cshtml"
|
||||||
, Tuple.Create(Tuple.Create("", 729), Tuple.Create<System.Object, System.Int32>(expressionParts.Length
|
, Tuple.Create(Tuple.Create("", 735), Tuple.Create<System.Object, System.Int32>(expressionParts.Length
|
||||||
|
|
||||||
#line default
|
#line default
|
||||||
#line hidden
|
#line hidden
|
||||||
, 729), false)
|
, 735), false)
|
||||||
);
|
);
|
||||||
|
|
||||||
WriteLiteral(">\r\n");
|
WriteLiteral(">\r\n");
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ using System.Web.Mvc;
|
|||||||
using Disco.Services.Plugins;
|
using Disco.Services.Plugins;
|
||||||
using Disco.Services.Authorization;
|
using Disco.Services.Authorization;
|
||||||
using Disco.Services.Users;
|
using Disco.Services.Users;
|
||||||
|
using Disco.Services.Interop;
|
||||||
|
|
||||||
namespace Disco.Web.Controllers
|
namespace Disco.Web.Controllers
|
||||||
{
|
{
|
||||||
@@ -57,7 +58,7 @@ namespace Disco.Web.Controllers
|
|||||||
|
|
||||||
var pluginResourcePath = pluginResource.Item1;
|
var pluginResourcePath = pluginResource.Item1;
|
||||||
|
|
||||||
var mimeType = Disco.BI.Interop.MimeTypes.ResolveMimeType(pluginResourcePath);
|
var mimeType = MimeTypes.ResolveMimeType(pluginResourcePath);
|
||||||
if (Download.HasValue && Download.Value)
|
if (Download.HasValue && Download.Value)
|
||||||
return File(pluginResourcePath, mimeType, Path.GetFileName(pluginResourcePath));
|
return File(pluginResourcePath, mimeType, Path.GetFileName(pluginResourcePath));
|
||||||
else
|
else
|
||||||
|
|||||||
@@ -211,7 +211,7 @@ namespace Disco.Web
|
|||||||
}
|
}
|
||||||
#endregion
|
#endregion
|
||||||
#region Dropbox Monitor
|
#region Dropbox Monitor
|
||||||
public static BI.DocumentTemplateBI.Importer.DocumentDropBoxMonitor DocumentDropBoxMonitor { get; set; }
|
public static Disco.Services.Documents.AttachmentImport.ImportDirectoryMonitor DocumentDropBoxMonitor { get; set; }
|
||||||
#endregion
|
#endregion
|
||||||
#region Global Error Logging
|
#region Global Error Logging
|
||||||
void DiscoApplication_Error(object sender, EventArgs e)
|
void DiscoApplication_Error(object sender, EventArgs e)
|
||||||
|
|||||||
Reference in New Issue
Block a user