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.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.NewProvider(Logger.Main).Save(document); return id; } private DFLayoutEmbeddedMediaValue ConvertImage(byte[] data) { var thumbnail = ImageUtils.BitmapImageFromBytes(data)?.Resize(200, 200).ToArray(); return new DFLayoutEmbeddedMediaValue { ID = SaveDocument(data), Thumbnail = thumbnail, Data = data }; } private DFLayoutEmbeddedMediaValue ConvertVideo(byte[] data) { var thumbnail = ImageUtils.BitmapImageFromBytes(data)?.Resize(200, 200).ToArray(); return new DFLayoutEmbeddedMediaValue { ID = SaveDocument(data), Thumbnail = new Bitmap(256, 256).WatermarkImage("Video Data", Color.Gray).AsBitmapImage().ToArray(), 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()); 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>(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(variable.Code); } catch { var data = values.GetValue(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>(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 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(); } } }