123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425 |
- using Comal.Classes;
- using InABox.Clients;
- using InABox.Configuration;
- using InABox.Core;
- using InABox.DynamicGrid;
- using InABox.WPF;
- using Syncfusion.Pdf;
- using System;
- using System.Collections.Generic;
- using System.IO;
- using System.Linq;
- using System.Windows;
- using System.Windows.Media.Imaging;
- namespace PRSDesktop;
- public class DataEntryCachedDocument : ICachedDocument
- {
- public DateTime TimeStamp { get; set; }
- public Document? Document { get; set; }
- public Guid ID => Document?.ID ?? Guid.Empty;
- public DataEntryCachedDocument() { }
- public DataEntryCachedDocument(Document document)
- {
- Document = document;
- TimeStamp = document.TimeStamp;
- }
- public void DeserializeBinary(CoreBinaryReader reader, bool full)
- {
- TimeStamp = reader.ReadDateTime();
- if (full)
- {
- Document = reader.ReadObject<Document>();
- }
- }
- public void SerializeBinary(CoreBinaryWriter writer)
- {
- writer.Write(TimeStamp);
- if (Document is null)
- {
- throw new Exception("Cannot serialize incomplete CachedDocument");
- }
- writer.WriteObject(Document);
- }
- }
- public class DataEntryCache : DocumentCache<DataEntryCachedDocument>
- {
- public override TimeSpan MaxAge => TimeSpan.FromDays(new UserConfiguration<DataEntryPanelSettings>().Load().CacheAge);
- private static DataEntryCache? _cache;
- public static DataEntryCache Cache
- {
- get
- {
- _cache ??= DocumentCaches.GetOrRegister<DataEntryCache>();
- return _cache;
- }
- }
- public DataEntryCache(): base(nameof(DataEntryCache)) { }
- protected override DataEntryCachedDocument? LoadDocument(Guid id)
- {
- var document = Client.Query(new Filter<Document>(x => x.ID).IsEqualTo(id))
- .ToObjects<Document>().FirstOrDefault();
- if(document is not null)
- {
- return new DataEntryCachedDocument(document);
- }
- else
- {
- return null;
- }
- }
-
- /// <summary>
- /// Fetch a bunch of documents from the cache or the database, optionally checking against the timestamp listed in the database.
- /// </summary>
- /// <param name="ids"></param>
- /// <param name="checkTimestamp">
- /// If <see langword="true"/>, then loads <see cref="Document.TimeStamp"/> from the database for all cached documents,
- /// and if they are older, updates the cache.
- /// </param>
- public IEnumerable<Document> LoadDocuments(IEnumerable<Guid> ids, bool checkTimestamp = false)
- {
- var cached = new List<Guid>();
- var toLoad = new List<Guid>();
- foreach (var docID in ids)
- {
- if (Has(docID))
- {
- cached.Add(docID);
- }
- else
- {
- toLoad.Add(docID);
- }
- }
- var loadedCached = new List<Document>();
- if (cached.Count > 0)
- {
- var docs = Client.Query(
- new Filter<Document>(x => x.ID).InList(cached.ToArray()),
- new Columns<Document>(x => x.TimeStamp, x => x.ID));
- foreach (var doc in docs.ToObjects<Document>())
- {
- try
- {
- var timestamp = GetHeader(doc.ID).Document.TimeStamp;
- if (doc.TimeStamp > timestamp)
- {
- toLoad.Add(doc.ID);
- }
- else
- {
- loadedCached.Add(GetFull(doc.ID).Document.Document!);
- }
- }
- catch (Exception e)
- {
- CoreUtils.LogException("", e, "Error loading cached file");
- toLoad.Add(doc.ID);
- }
- }
- }
- if (toLoad.Count > 0)
- {
- var loaded = Client.Query(new Filter<Document>(x => x.ID).InList(toLoad.ToArray()))
- .ToObjects<Document>().ToList();
- foreach (var loadedDoc in loaded)
- {
- Add(new DataEntryCachedDocument(loadedDoc));
- }
- return loaded.Concat(loadedCached);
- }
- else
- {
- return loadedCached;
- }
- }
- }
- public class DataEntryGrid : DynamicDataGrid<DataEntryDocument>
- {
- private List<DataEntryTag>? _tags;
-
- public DataEntryGrid()
- {
- HiddenColumns.Add(x => x.Tag.ID);
- HiddenColumns.Add(x => x.Tag.AppliesTo);
- HiddenColumns.Add(x => x.Document.ID);
- HiddenColumns.Add(x => x.EntityID);
- HiddenColumns.Add(x => x.Archived);
-
- ActionColumns.Add(new DynamicImageColumn(LinkedImage) { Position = DynamicActionColumnPosition.Start });
- var tagFilter = new Filter<DataEntryDocument>(x => x.Tag.ID).InList(GetVisibleTags().Select(x => x.ID).ToArray());
- if (Security.IsAllowed<CanSetupDataEntryTags>())
- {
- tagFilter.Or(x => x.Tag.ID).IsEqualTo(Guid.Empty);
- }
- var docs = Client.Query(
- new Filter<DataEntryDocument>(x => x.Archived).IsEqualTo(DateTime.MinValue)
- .And(tagFilter),
- new Columns<DataEntryDocument>(x => x.Document.ID));
- DataEntryCache.Cache.ClearOld();
- DataEntryCache.Cache.EnsureStrict(docs.Rows.Select(x => x.Get<DataEntryDocument, Guid>(x => x.Document.ID)).ToArray());
- }
- private static readonly BitmapImage link = PRSDesktop.Resources.link.AsBitmapImage();
-
- private BitmapImage? LinkedImage(CoreRow? arg)
- {
- return arg == null
- ? link
- : arg.Get<DataEntryDocument, Guid>(x => x.EntityID) != Guid.Empty
- ? link
- : null;
- }
- protected override void DoReconfigure(FluentList<DynamicGridOption> options)
- {
- base.DoReconfigure(options);
- options.BeginUpdate()
- .Clear()
- .Add(DynamicGridOption.MultiSelect)
- .Add(DynamicGridOption.DragSource)
- .Add(DynamicGridOption.DragTarget)
- .Add(DynamicGridOption.SelectColumns)
- .EndUpdate();
- }
-
- public static List<DataEntryTag> GetVisibleTagList()
- {
- var tags = new Client<DataEntryTag>().Query().ToObjects<DataEntryTag>().ToList();
- var tagsList = new List<DataEntryTag>();
- foreach (var tag in tags)
- {
- var entity = CoreUtils.GetEntityOrNull(tag.AppliesTo);
- if (entity is null || Security.CanView(entity))
- {
- var tagHasEmployee = new Client<DataEntryTagDistributionEmployee>()
- .Query(
- new Filter<DataEntryTagDistributionEmployee>(x => x.Tag.ID).IsEqualTo(tag.ID)
- .And(x => x.Employee.ID).IsEqualTo(App.EmployeeID),
- new Columns<DataEntryTagDistributionEmployee>(x => x.ID))
- .Rows.Any();
- if (tagHasEmployee)
- {
- tagsList.Add(tag);
- }
- }
- }
- return tagsList;
- }
- private List<DataEntryTag> GetVisibleTags()
- {
- _tags ??= GetVisibleTagList();
- return _tags;
- }
-
- public void DoExplode()
- {
- Guid tagID = Guid.Empty;
- foreach (var row in SelectedRows)
- {
- var rowTag = row.Get<DataEntryDocument, Guid>(x => x.Tag.ID);
- if (tagID == Guid.Empty)
- {
- tagID = rowTag;
- }
- else if (rowTag != tagID)
- {
- tagID = Guid.Empty;
- break;
- }
- }
- var docIDs = SelectedRows.Select(r => r.Get<DataEntryDocument, Guid>(c => c.Document.ID)).ToArray();
- var docs = new Client<Document>()
- .Query(
- new Filter<Document>(x => x.ID).InList(docIDs),
- new Columns<Document>(x => x.ID).Add(x => x.Data).Add(x => x.FileName))
- .ToObjects<Document>().ToDictionary(x => x.ID, x => x);
- var pages = new List<DataEntryReGroupWindow.Page>();
- string filename = "";
- foreach (var docID in docIDs)
- {
- if (docs.TryGetValue(docID, out var doc))
- {
- filename = doc.FileName;
- var ms = new MemoryStream(doc.Data);
- var pdfDoc = DataEntryReGroupWindow.RenderToPDF(doc.FileName, ms);
- foreach (var page in DataEntryReGroupWindow.SplitIntoPages(doc.FileName, pdfDoc))
- {
- pages.Add(page);
- }
- }
- }
- if (ShowDocumentWindow(pages, filename, tagID))
- {
- // ShowDocumentWindow already saves new scans, so we just need to get rid of the old ones.
- DeleteItems(SelectedRows);
- Refresh(false,true);
- }
- }
-
- public void DoRemove()
- {
- var updates = SelectedRows.Select(x => x.ToObject<DataEntryDocument>()).ToArray();
- foreach (var update in updates)
- {
- update.Archived = DateTime.Now;
- DataEntryCache.Cache.Remove(update.Document.ID);
- }
- new Client<DataEntryDocument>().Save(updates,"Removed from Data Entry Panel");
- Refresh(false,true);
- }
- public void DoChangeTags(Guid tagid)
- {
- var updates = SelectedRows.Select(x => x.ToObject<DataEntryDocument>()).ToArray();
- foreach (var update in updates)
- {
- if (update.Tag.ID != tagid)
- {
- update.Tag.ID = tagid;
- update.EntityID = Guid.Empty;
- }
- }
- new Client<DataEntryDocument>().Save(updates.Where(x=>x.IsChanged()),"Updated Tags on Data Entry Panel");
- Refresh(false,true);
- }
-
- protected override DragDropEffects OnRowsDragStart(CoreRow[] rows)
- {
- var table = new CoreTable();
- table.Columns.Add(new CoreColumn { ColumnName = "ID", DataType = typeof(Guid) });
- foreach(var row in rows)
- {
- var newRow = table.NewRow();
- newRow.Set<Document, Guid>(x => x.ID, row.Get<DataEntryDocument, Guid>(x => x.Document.ID));
- table.Rows.Add(newRow);
- }
- return DragTable(typeof(Document), table);
- }
- public void UploadDocument(string filename, byte[] data, Guid tagID)
- {
- var document = new Document
- {
- FileName = filename,
- CRC = CoreUtils.CalculateCRC(data),
- TimeStamp = DateTime.Now,
- Data = data
- };
- new Client<Document>().Save(document, "");
- var dataentry = new DataEntryDocument
- {
- Document =
- {
- ID = document.ID
- },
- Tag =
- {
- ID = tagID
- },
- Employee =
- {
- ID = App.EmployeeID
- }
- };
- if(Path.GetExtension(filename) == ".pdf")
- {
- dataentry.Thumbnail = ImageUtils.GetPDFThumbnail(data, 256, 256);
- }
- new Client<DataEntryDocument>().Save(dataentry, "");
- DataEntryCache.Cache.Add(new DataEntryCachedDocument(document));
- Dispatcher.Invoke(() =>
- {
- Refresh(false, true);
- });
- }
- private static PdfDocumentBase CombinePages(IEnumerable<DataEntryReGroupWindow.Page> pages)
- {
- var document = new PdfDocument();
- foreach (var page in pages)
- {
- document.ImportPage(page.Pdf, page.PageIndex);
- }
- return document;
- }
- public bool ShowDocumentWindow(List<DataEntryReGroupWindow.Page> pages, string filename, Guid tagID)
- {
- var window = new DataEntryReGroupWindow(pages, filename, tagID);
- if (window.ShowDialog() == true)
- {
- Progress.ShowModal("Uploading Files", (progress) =>
- {
- foreach (var group in window.Groups)
- {
- progress.Report($"Uploading '{group.FileName}'");
- var doc = CombinePages(group.Pages);
- byte[] data;
- using (var ms = new MemoryStream())
- {
- doc.Save(ms);
- data = ms.ToArray();
- }
- UploadDocument(group.FileName, data, group.TagID);
- }
- });
- return true;
- }
- return false;
- }
-
- protected override void GenerateColumns(DynamicGridColumns columns)
- {
- columns.Add<DataEntryDocument, string>(x => x.Document.FileName, 0, "Filename", "", Alignment.MiddleLeft);
- columns.Add<DataEntryDocument, string>(x => x.Tag.Name, 100, "Tag", "", Alignment.MiddleLeft);
- }
- protected override void Reload(Filters<DataEntryDocument> criteria, Columns<DataEntryDocument> columns, ref SortOrder<DataEntryDocument>? sort, Action<CoreTable?, Exception?> action)
- {
- criteria.Add(new Filter<DataEntryDocument>(x => x.Archived).IsEqualTo(DateTime.MinValue));
- var tagFilter = new Filter<DataEntryDocument>(x => x.Tag.ID).InList(GetVisibleTags().Select(x => x.ID).ToArray());
- if (Security.IsAllowed<CanSetupDataEntryTags>())
- {
- tagFilter.Or(x => x.Tag.ID).IsEqualTo(Guid.Empty);
- }
- criteria.Add(tagFilter);
- base.Reload(criteria, columns, ref sort, action);
- }
- }
|