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:
Gary Sharp
2016-08-26 09:46:35 +10:00
parent 44f6d325db
commit 5ea9a814d6
98 changed files with 3168 additions and 3202 deletions
-102
View File
@@ -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;
+19 -57
View File
@@ -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));
+7 -39
View File
@@ -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")
+5 -42
View File
@@ -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)
{ {
+1 -235
View File
@@ -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
} }
} }
+13 -12
View File
@@ -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);
-977
View File
@@ -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 &lt;= y &lt; 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 &lt;= left &lt; Width.</param>
/// <param name="top">The top coordinate, 0 &lt;= top &lt;= 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 };
}
}
}
-34
View File
@@ -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
+7 -2
View File
@@ -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; }
}
}
+11 -5
View File
@@ -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";
+12 -1
View File
@@ -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";
+7 -4
View File
@@ -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 -1
View File
@@ -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,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
{ {
+5 -1
View File
@@ -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";
}
}
}
+82 -1
View File
@@ -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;
}
}
}
@@ -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);
}
}
}
+441
View File
@@ -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
}
};
}
}
}
@@ -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
{ {
@@ -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;
} }
@@ -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
{ {
@@ -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
{ {
@@ -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
};
}
}
}
@@ -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;
@@ -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
{ {
@@ -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()
{ {
@@ -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
{ {
@@ -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
{ {
@@ -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
{ {
@@ -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
{ {
@@ -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
{ {
@@ -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,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
View File
@@ -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));
}
}
}
}
+136
View File
@@ -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

+3
View File
@@ -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.
+6 -5
View File
@@ -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
+1 -1
View File
@@ -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)