|
@@ -0,0 +1,385 @@
|
|
|
+using InABox.Clients;
|
|
|
+using InABox.Core;
|
|
|
+using InABox.Database;
|
|
|
+using InABox.DynamicGrid;
|
|
|
+using InABox.WPF;
|
|
|
+using Microsoft.CodeAnalysis.CSharp.Syntax;
|
|
|
+using Newtonsoft.Json.Linq;
|
|
|
+using NPOI.POIFS.FileSystem;
|
|
|
+using PRSClasses;
|
|
|
+using Syncfusion.Data.Extensions;
|
|
|
+using Syncfusion.DocIO.DLS;
|
|
|
+using System;
|
|
|
+using System.Collections.Generic;
|
|
|
+using System.Drawing;
|
|
|
+using System.Globalization;
|
|
|
+using System.Linq;
|
|
|
+using System.Text;
|
|
|
+using System.Threading.Tasks;
|
|
|
+using System.Windows.Interop;
|
|
|
+using System.Windows.Media.Imaging;
|
|
|
+using System.Windows.Navigation;
|
|
|
+
|
|
|
+namespace PRS.Shared
|
|
|
+{
|
|
|
+ public class Update_7_34 : DatabaseUpdateScript
|
|
|
+ {
|
|
|
+ public override VersionNumber Version => new VersionNumber(7, 34);
|
|
|
+
|
|
|
+ public override bool Update()
|
|
|
+ {
|
|
|
+ Logger.Send(LogType.Information, "", "Updating form data");
|
|
|
+ var fnc = typeof(Update_7_34).GetMethod("UpdateForm", System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.NonPublic)!;
|
|
|
+ FormUpdater.UpdateAllForms((_, vars) => vars.Count == 0, UpdateForm);
|
|
|
+ Logger.Send(LogType.Information, "", "Updating form data complete");
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+
|
|
|
+ private Guid SaveDocument(byte[] data)
|
|
|
+ {
|
|
|
+ var id = Guid.NewGuid();
|
|
|
+ var document = new Document
|
|
|
+ {
|
|
|
+ FileName = $"{id}.formdocument",
|
|
|
+ Data = data
|
|
|
+ };
|
|
|
+ DbFactory.Provider.Save(document);
|
|
|
+ return document.ID;
|
|
|
+ }
|
|
|
+
|
|
|
+ private DFLayoutEmbeddedMediaValue ConvertImage(byte[] data)
|
|
|
+ {
|
|
|
+ var thumbnail = ImageUtils.BitmapImageFromBytes(data)?.Resize(200, 200).ToArray<BmpBitmapEncoder>();
|
|
|
+
|
|
|
+ return new DFLayoutEmbeddedMediaValue
|
|
|
+ {
|
|
|
+ ID = SaveDocument(data),
|
|
|
+ Thumbnail = thumbnail,
|
|
|
+ Data = data
|
|
|
+ };
|
|
|
+ }
|
|
|
+
|
|
|
+ private DFLayoutEmbeddedMediaValue ConvertVideo(byte[] data)
|
|
|
+ {
|
|
|
+ var thumbnail = ImageUtils.BitmapImageFromBytes(data)?.Resize(200, 200).ToArray<BmpBitmapEncoder>();
|
|
|
+ return new DFLayoutEmbeddedMediaValue
|
|
|
+ {
|
|
|
+ ID = SaveDocument(data),
|
|
|
+ Thumbnail = new Bitmap(256, 256).WatermarkImage("Video Data", Color.Gray).AsBitmapImage().ToArray<BmpBitmapEncoder>(),
|
|
|
+ Data = data
|
|
|
+ };
|
|
|
+ }
|
|
|
+
|
|
|
+ private DFLayoutLookupValue ConvertLookup(DigitalFormVariable variable, Guid lookupID)
|
|
|
+ {
|
|
|
+ if(lookupID == Guid.Empty)
|
|
|
+ {
|
|
|
+ return new DFLayoutLookupValue();
|
|
|
+ }
|
|
|
+ var properties = (variable.GetProperties() as DFLayoutLookupFieldProperties)!;
|
|
|
+
|
|
|
+ if (!CoreUtils.TryGetEntity(properties.LookupType, out var type))
|
|
|
+ {
|
|
|
+ Logger.Send(LogType.Error, "", $"Invalid lookup type {properties.LookupType}");
|
|
|
+ return new DFLayoutLookupValue { ID = lookupID };
|
|
|
+ }
|
|
|
+ var client = ClientFactory.CreateClient(type);
|
|
|
+ var columns = LookupFactory.DefineColumns(type);
|
|
|
+ foreach (var property in properties.AdditionalPropertiesList)
|
|
|
+ {
|
|
|
+ columns.Add(property);
|
|
|
+ }
|
|
|
+
|
|
|
+ var filter = Filter.Create(type, "ID").IsEqualTo(lookupID);
|
|
|
+
|
|
|
+ var row = client.Query(
|
|
|
+ filter,
|
|
|
+ columns,
|
|
|
+ LookupFactory.DefineSort(type)
|
|
|
+ ).Rows.FirstOrDefault();
|
|
|
+ if (row is null)
|
|
|
+ {
|
|
|
+ return new DFLayoutLookupValue { ID = lookupID };
|
|
|
+ }
|
|
|
+ var value = new DFLayoutLookupValue
|
|
|
+ {
|
|
|
+ ID = lookupID,
|
|
|
+ Values = row.ToDictionary(new[] { "ID" })
|
|
|
+ };
|
|
|
+ value.Text = LookupFactory.FormatLookup(type, value.Values, Enumerable.Empty<string>());
|
|
|
+ return value;
|
|
|
+ }
|
|
|
+
|
|
|
+ private object? Deserialize(DigitalFormVariable variable, Type fieldType, DFLoadStorage values)
|
|
|
+ {
|
|
|
+ var value = values.GetValue(variable.Code);
|
|
|
+ if (fieldType == typeof(DFLayoutBooleanField))
|
|
|
+ {
|
|
|
+ if (value is bool b)
|
|
|
+ {
|
|
|
+ return b;
|
|
|
+ }
|
|
|
+ else if (bool.TryParse(value as string, out var result))
|
|
|
+ {
|
|
|
+ return result;
|
|
|
+ }
|
|
|
+ else if (value is string str)
|
|
|
+ {
|
|
|
+ var properties = (variable.GetProperties() as DFLayoutBooleanFieldProperties)!;
|
|
|
+ if (str == properties.TrueValue)
|
|
|
+ return true;
|
|
|
+ if (str == properties.FalseValue)
|
|
|
+ return false;
|
|
|
+ throw new Exception($"Invalid boolean value {str}");
|
|
|
+ }
|
|
|
+ return variable.Deserialize(values.GetEntry(variable.Code));
|
|
|
+ }
|
|
|
+ else if(fieldType == typeof(DFLayoutDateField))
|
|
|
+ {
|
|
|
+ if (value is DateTime date)
|
|
|
+ return date;
|
|
|
+ if (DateTime.TryParseExact(value as string, "dd-MM-yyyy", CultureInfo.InvariantCulture, DateTimeStyles.None, out var result))
|
|
|
+ return result;
|
|
|
+ if (DateTime.TryParse(value as string, out result))
|
|
|
+ return result;
|
|
|
+ return variable.Deserialize(values.GetEntry(variable.Code));
|
|
|
+ }
|
|
|
+ else if (fieldType == typeof(DFLayoutDoubleField))
|
|
|
+ {
|
|
|
+ if (value is double d)
|
|
|
+ return d;
|
|
|
+ if (double.TryParse(value as string, out var result))
|
|
|
+ return result;
|
|
|
+ if(value is not null)
|
|
|
+ {
|
|
|
+ throw new Exception($"Invalid double '{value}'");
|
|
|
+ }
|
|
|
+ return variable.Deserialize(values.GetEntry(variable.Code));
|
|
|
+ }
|
|
|
+ else if (fieldType == typeof(DFLayoutEmbeddedImage))
|
|
|
+ {
|
|
|
+ if (value is byte[] b)
|
|
|
+ return ConvertImage(b);
|
|
|
+ else if(value is string str)
|
|
|
+ {
|
|
|
+ if (Guid.TryParse(str, out var id))
|
|
|
+ return variable.Deserialize(values.GetEntry(variable.Code));
|
|
|
+ try
|
|
|
+ {
|
|
|
+ var tuple = Serialization.Deserialize<Tuple<Guid, byte[]>>(str, true);
|
|
|
+ if(tuple != null)
|
|
|
+ {
|
|
|
+ return new DFLayoutEmbeddedMediaValue
|
|
|
+ {
|
|
|
+ ID = tuple.Item1,
|
|
|
+ Thumbnail = tuple.Item2,
|
|
|
+ };
|
|
|
+ }
|
|
|
+ }
|
|
|
+ catch
|
|
|
+ {
|
|
|
+ }
|
|
|
+ try
|
|
|
+ {
|
|
|
+ return ConvertImage(System.Convert.FromBase64String(str));
|
|
|
+ }
|
|
|
+ catch(Exception e)
|
|
|
+ {
|
|
|
+ throw new Exception($"Error in image data; invalid Base-64: {e.Message}");
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return variable.Deserialize(values.GetEntry(variable.Code));
|
|
|
+ }
|
|
|
+ else if (fieldType == typeof(DFLayoutIntegerField))
|
|
|
+ {
|
|
|
+ if (value is null)
|
|
|
+ return variable.Deserialize(values.GetEntry(variable.Code));
|
|
|
+
|
|
|
+ if (value.GetType().IsNumeric())
|
|
|
+ {
|
|
|
+ return System.Convert.ToInt32(value);
|
|
|
+ }
|
|
|
+ if (int.TryParse(value as string, out var result))
|
|
|
+ return result;
|
|
|
+ if(value != null)
|
|
|
+ {
|
|
|
+ throw new Exception($"Invalid integer '{value}'");
|
|
|
+ }
|
|
|
+ return variable.Deserialize(values.GetEntry(variable.Code));
|
|
|
+ }
|
|
|
+ else if(fieldType == typeof(DFLayoutLookupField))
|
|
|
+ {
|
|
|
+ if(value is string str && Guid.TryParse(str, out var id))
|
|
|
+ {
|
|
|
+ return ConvertLookup(variable, id);
|
|
|
+ }
|
|
|
+ return variable.Deserialize(values.GetEntry(variable.Code));
|
|
|
+ }
|
|
|
+ else if(fieldType == typeof(DFLayoutMultiImage))
|
|
|
+ {
|
|
|
+ string[]? imgs;
|
|
|
+ try
|
|
|
+ {
|
|
|
+ imgs = values.GetValue<string[]?>(variable.Code);
|
|
|
+ }
|
|
|
+ catch
|
|
|
+ {
|
|
|
+ var data = values.GetValue<byte[]>(variable.Code);
|
|
|
+ if(data != null)
|
|
|
+ {
|
|
|
+ var newValueList = new DFLayoutEmbeddedMediaValues();
|
|
|
+ newValueList.Add(ConvertImage(data));
|
|
|
+ return newValueList;
|
|
|
+ }
|
|
|
+ return variable.Deserialize(values.GetEntry(variable.Code));
|
|
|
+ }
|
|
|
+ if (imgs is null)
|
|
|
+ {
|
|
|
+ return variable.Deserialize(values.GetEntry(variable.Code));
|
|
|
+ }
|
|
|
+
|
|
|
+ var valueList = new DFLayoutEmbeddedMediaValues();
|
|
|
+ foreach (string s in imgs)
|
|
|
+ {
|
|
|
+ if (!s.IsNullOrWhiteSpace())
|
|
|
+ {
|
|
|
+ try
|
|
|
+ {
|
|
|
+ var externaldata = Serialization.Deserialize<(Guid, byte[])>(s, strict: true);
|
|
|
+ if (externaldata.Item1 != Guid.Empty)
|
|
|
+ {
|
|
|
+ valueList.Add(new DFLayoutEmbeddedMediaValue()
|
|
|
+ {
|
|
|
+ ID = externaldata.Item1,
|
|
|
+ Thumbnail = externaldata.Item2
|
|
|
+ });
|
|
|
+ }
|
|
|
+ }
|
|
|
+ catch
|
|
|
+ {
|
|
|
+ try
|
|
|
+ {
|
|
|
+ var data = System.Convert.FromBase64String(s);
|
|
|
+ valueList.Add(ConvertImage(data));
|
|
|
+ }
|
|
|
+ catch
|
|
|
+ {
|
|
|
+ throw new Exception($"Could not convert multi-image");
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return valueList;
|
|
|
+ }
|
|
|
+ else if(fieldType == typeof(DFLayoutMultiSignaturePad))
|
|
|
+ {
|
|
|
+ return variable.Deserialize(values.GetEntry(variable.Code));
|
|
|
+ }
|
|
|
+ else if(fieldType == typeof(DFLayoutOptionField))
|
|
|
+ {
|
|
|
+ return variable.Deserialize(values.GetEntry(variable.Code));
|
|
|
+ }
|
|
|
+ else if (fieldType == typeof(DFLayoutSignaturePad))
|
|
|
+ {
|
|
|
+ return variable.Deserialize(values.GetEntry(variable.Code));
|
|
|
+ }
|
|
|
+ else if (fieldType == typeof(DFLayoutStringField))
|
|
|
+ {
|
|
|
+ return variable.Deserialize(values.GetEntry(variable.Code));
|
|
|
+ }
|
|
|
+ else if (fieldType == typeof(DFLayoutTimeField))
|
|
|
+ {
|
|
|
+ if (value is TimeSpan time)
|
|
|
+ return time;
|
|
|
+ if (TimeSpan.TryParseExact(value as string, "c", CultureInfo.InvariantCulture, TimeSpanStyles.None, out var result))
|
|
|
+ return result;
|
|
|
+ if (TimeSpan.TryParse(value as string, out result))
|
|
|
+ return result;
|
|
|
+ return variable.Deserialize(values.GetEntry(variable.Code));
|
|
|
+ }
|
|
|
+ else if (fieldType == typeof(DFLayoutVideoField))
|
|
|
+ {
|
|
|
+ if (value is byte[] b)
|
|
|
+ return ConvertVideo(b);
|
|
|
+ else if (value is string str)
|
|
|
+ {
|
|
|
+ if (Guid.TryParse(str, out var id))
|
|
|
+ return variable.Deserialize(values.GetEntry(variable.Code));
|
|
|
+ try
|
|
|
+ {
|
|
|
+ var tuple = Serialization.Deserialize<Tuple<Guid, byte[]>>(str, true);
|
|
|
+ if (tuple != null)
|
|
|
+ {
|
|
|
+ return new DFLayoutEmbeddedMediaValue
|
|
|
+ {
|
|
|
+ ID = tuple.Item1,
|
|
|
+ Thumbnail = tuple.Item2,
|
|
|
+ };
|
|
|
+ }
|
|
|
+ }
|
|
|
+ catch
|
|
|
+ {
|
|
|
+ }
|
|
|
+ try
|
|
|
+ {
|
|
|
+ return ConvertVideo(System.Convert.FromBase64String(str));
|
|
|
+ }
|
|
|
+ catch (Exception e)
|
|
|
+ {
|
|
|
+ throw new Exception($"Error in video data; invalid Base-64: {e.Message}");
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return variable.Deserialize(values.GetEntry(variable.Code));
|
|
|
+ }
|
|
|
+ else if(fieldType == typeof(DFLayoutAddTaskField))
|
|
|
+ {
|
|
|
+ return value?.ToString();
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ throw new Exception($"Unhandled variable type {fieldType}")
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ private bool UpdateForm(Type formType, IDigitalFormInstance instance, DigitalForm form, IList<DigitalFormVariable> variables)
|
|
|
+ {
|
|
|
+ var values = DigitalForm.DeserializeFormData(instance);
|
|
|
+ if(values is null)
|
|
|
+ {
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+
|
|
|
+ var save = new DFSaveStorage();
|
|
|
+ foreach(var variable in variables)
|
|
|
+ {
|
|
|
+ try
|
|
|
+ {
|
|
|
+ var value = Deserialize(variable, variable.FieldType(), values);
|
|
|
+ variable.Serialize(save.GetEntry(variable.Code), value);
|
|
|
+ }
|
|
|
+ catch(Exception e)
|
|
|
+ {
|
|
|
+ Logger.Send(LogType.Error, "", $"Error in data for {variable.Code} ({instance.ID}): {e.Message}");
|
|
|
+ save.FormData[variable.Code] = values.GetValue(variable.Code);
|
|
|
+ foreach(var (k, v) in values.GetEntry(variable.Code).SubItems())
|
|
|
+ {
|
|
|
+ save.FormData[$"{variable.Code}.{k}"] = v;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ foreach(var (k, v) in values.Items())
|
|
|
+ {
|
|
|
+ if(!save.FormData.ContainsKey(k) && !k.Contains('.') && !variables.Any(x => x.Code == k))
|
|
|
+ {
|
|
|
+ save.FormData[k] = v;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ DigitalForm.SerializeFormData(instance, variables, save);
|
|
|
+
|
|
|
+
|
|
|
+ return instance.IsChanged();
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|