Update_7_34.cs 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383
  1. using InABox.Clients;
  2. using InABox.Core;
  3. using InABox.Database;
  4. using InABox.DynamicGrid;
  5. using InABox.WPF;
  6. using Microsoft.CodeAnalysis.CSharp.Syntax;
  7. using NPOI.POIFS.FileSystem;
  8. using PRSClasses;
  9. using Syncfusion.Data.Extensions;
  10. using Syncfusion.DocIO.DLS;
  11. using System.Collections.Generic;
  12. using System.Drawing;
  13. using System.Globalization;
  14. using System.Linq;
  15. using System.Text;
  16. using System.Threading.Tasks;
  17. using System.Windows.Interop;
  18. using System.Windows.Media.Imaging;
  19. using System.Windows.Navigation;
  20. namespace PRS.Shared
  21. {
  22. public class Update_7_34 : DatabaseUpdateScript
  23. {
  24. public override VersionNumber Version => new VersionNumber(7, 34);
  25. public override bool Update()
  26. {
  27. Logger.Send(LogType.Information, "", "Updating form data");
  28. var fnc = typeof(Update_7_34).GetMethod("UpdateForm", System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.NonPublic)!;
  29. FormUpdater.UpdateAllForms((_, vars) => vars.Count == 0, UpdateForm);
  30. Logger.Send(LogType.Information, "", "Updating form data complete");
  31. return true;
  32. }
  33. private Guid SaveDocument(byte[] data)
  34. {
  35. var id = Guid.NewGuid();
  36. var document = new Document
  37. {
  38. FileName = $"{id}.formdocument",
  39. Data = data
  40. };
  41. DbFactory.NewProvider(Logger.Main).Save(document);
  42. return id;
  43. }
  44. private DFLayoutEmbeddedMediaValue ConvertImage(byte[] data)
  45. {
  46. var thumbnail = ImageUtils.BitmapImageFromBytes(data)?.Resize(200, 200).ToArray<BmpBitmapEncoder>();
  47. return new DFLayoutEmbeddedMediaValue
  48. {
  49. ID = SaveDocument(data),
  50. Thumbnail = thumbnail,
  51. Data = data
  52. };
  53. }
  54. private DFLayoutEmbeddedMediaValue ConvertVideo(byte[] data)
  55. {
  56. var thumbnail = ImageUtils.BitmapImageFromBytes(data)?.Resize(200, 200).ToArray<BmpBitmapEncoder>();
  57. return new DFLayoutEmbeddedMediaValue
  58. {
  59. ID = SaveDocument(data),
  60. Thumbnail = new Bitmap(256, 256).WatermarkImage("Video Data", Color.Gray).AsBitmapImage().ToArray<BmpBitmapEncoder>(),
  61. Data = data
  62. };
  63. }
  64. private DFLayoutLookupValue ConvertLookup(DigitalFormVariable variable, Guid lookupID)
  65. {
  66. if(lookupID == Guid.Empty)
  67. {
  68. return new DFLayoutLookupValue();
  69. }
  70. var properties = (variable.GetProperties() as DFLayoutLookupFieldProperties)!;
  71. if (!CoreUtils.TryGetEntity(properties.LookupType, out var type))
  72. {
  73. Logger.Send(LogType.Error, "", $"Invalid lookup type {properties.LookupType}");
  74. return new DFLayoutLookupValue { ID = lookupID };
  75. }
  76. var client = ClientFactory.CreateClient(type);
  77. var columns = LookupFactory.DefineColumns(type);
  78. foreach (var property in properties.AdditionalPropertiesList)
  79. {
  80. columns.Add(property);
  81. }
  82. var filter = Filter.Create(type, "ID").IsEqualTo(lookupID);
  83. var row = client.Query(
  84. filter,
  85. columns,
  86. LookupFactory.DefineSort(type)
  87. ).Rows.FirstOrDefault();
  88. if (row is null)
  89. {
  90. return new DFLayoutLookupValue { ID = lookupID };
  91. }
  92. var value = new DFLayoutLookupValue
  93. {
  94. ID = lookupID,
  95. Values = row.ToDictionary(new[] { "ID" })
  96. };
  97. value.Text = LookupFactory.FormatLookup(type, value.Values, Enumerable.Empty<string>());
  98. return value;
  99. }
  100. private object? Deserialize(DigitalFormVariable variable, Type fieldType, DFLoadStorage values)
  101. {
  102. var value = values.GetValue(variable.Code);
  103. if (fieldType == typeof(DFLayoutBooleanField))
  104. {
  105. if (value is bool b)
  106. {
  107. return b;
  108. }
  109. else if (bool.TryParse(value as string, out var result))
  110. {
  111. return result;
  112. }
  113. else if (value is string str)
  114. {
  115. var properties = (variable.GetProperties() as DFLayoutBooleanFieldProperties)!;
  116. if (str == properties.TrueValue)
  117. return true;
  118. if (str == properties.FalseValue)
  119. return false;
  120. throw new Exception($"Invalid boolean value {str}");
  121. }
  122. return variable.Deserialize(values.GetEntry(variable.Code));
  123. }
  124. else if(fieldType == typeof(DFLayoutDateField))
  125. {
  126. if (value is DateTime date)
  127. return date;
  128. if (DateTime.TryParseExact(value as string, "dd-MM-yyyy", CultureInfo.InvariantCulture, DateTimeStyles.None, out var result))
  129. return result;
  130. if (DateTime.TryParse(value as string, out result))
  131. return result;
  132. return variable.Deserialize(values.GetEntry(variable.Code));
  133. }
  134. else if (fieldType == typeof(DFLayoutDoubleField))
  135. {
  136. if (value is double d)
  137. return d;
  138. if (double.TryParse(value as string, out var result))
  139. return result;
  140. if(value is not null)
  141. {
  142. throw new Exception($"Invalid double '{value}'");
  143. }
  144. return variable.Deserialize(values.GetEntry(variable.Code));
  145. }
  146. else if (fieldType == typeof(DFLayoutEmbeddedImage))
  147. {
  148. if (value is byte[] b)
  149. return ConvertImage(b);
  150. else if(value is string str)
  151. {
  152. if (Guid.TryParse(str, out var id))
  153. return variable.Deserialize(values.GetEntry(variable.Code));
  154. try
  155. {
  156. var tuple = Serialization.Deserialize<Tuple<Guid, byte[]>>(str, true);
  157. if(tuple != null)
  158. {
  159. return new DFLayoutEmbeddedMediaValue
  160. {
  161. ID = tuple.Item1,
  162. Thumbnail = tuple.Item2,
  163. };
  164. }
  165. }
  166. catch
  167. {
  168. }
  169. try
  170. {
  171. return ConvertImage(System.Convert.FromBase64String(str));
  172. }
  173. catch(Exception e)
  174. {
  175. throw new Exception($"Error in image data; invalid Base-64: {e.Message}");
  176. }
  177. }
  178. return variable.Deserialize(values.GetEntry(variable.Code));
  179. }
  180. else if (fieldType == typeof(DFLayoutIntegerField))
  181. {
  182. if (value is null)
  183. return variable.Deserialize(values.GetEntry(variable.Code));
  184. if (value.GetType().IsNumeric())
  185. {
  186. return System.Convert.ToInt32(value);
  187. }
  188. if (int.TryParse(value as string, out var result))
  189. return result;
  190. if(value != null)
  191. {
  192. throw new Exception($"Invalid integer '{value}'");
  193. }
  194. return variable.Deserialize(values.GetEntry(variable.Code));
  195. }
  196. else if(fieldType == typeof(DFLayoutLookupField))
  197. {
  198. if(value is string str && Guid.TryParse(str, out var id))
  199. {
  200. return ConvertLookup(variable, id);
  201. }
  202. return variable.Deserialize(values.GetEntry(variable.Code));
  203. }
  204. else if(fieldType == typeof(DFLayoutMultiImage))
  205. {
  206. string[]? imgs;
  207. try
  208. {
  209. imgs = values.GetValue<string[]?>(variable.Code);
  210. }
  211. catch
  212. {
  213. var data = values.GetValue<byte[]>(variable.Code);
  214. if(data != null)
  215. {
  216. var newValueList = new DFLayoutEmbeddedMediaValues();
  217. newValueList.Add(ConvertImage(data));
  218. return newValueList;
  219. }
  220. return variable.Deserialize(values.GetEntry(variable.Code));
  221. }
  222. if (imgs is null)
  223. {
  224. return variable.Deserialize(values.GetEntry(variable.Code));
  225. }
  226. var valueList = new DFLayoutEmbeddedMediaValues();
  227. foreach (string s in imgs)
  228. {
  229. if (!s.IsNullOrWhiteSpace())
  230. {
  231. try
  232. {
  233. var externaldata = Serialization.Deserialize<(Guid, byte[])>(s, strict: true);
  234. if (externaldata.Item1 != Guid.Empty)
  235. {
  236. valueList.Add(new DFLayoutEmbeddedMediaValue()
  237. {
  238. ID = externaldata.Item1,
  239. Thumbnail = externaldata.Item2
  240. });
  241. }
  242. }
  243. catch
  244. {
  245. try
  246. {
  247. var data = System.Convert.FromBase64String(s);
  248. valueList.Add(ConvertImage(data));
  249. }
  250. catch
  251. {
  252. throw new Exception($"Could not convert multi-image");
  253. }
  254. }
  255. }
  256. }
  257. return valueList;
  258. }
  259. else if(fieldType == typeof(DFLayoutMultiSignaturePad))
  260. {
  261. return variable.Deserialize(values.GetEntry(variable.Code));
  262. }
  263. else if(fieldType == typeof(DFLayoutOptionField))
  264. {
  265. return variable.Deserialize(values.GetEntry(variable.Code));
  266. }
  267. else if (fieldType == typeof(DFLayoutSignaturePad))
  268. {
  269. return variable.Deserialize(values.GetEntry(variable.Code));
  270. }
  271. else if (fieldType == typeof(DFLayoutStringField))
  272. {
  273. return variable.Deserialize(values.GetEntry(variable.Code));
  274. }
  275. else if (fieldType == typeof(DFLayoutTimeField))
  276. {
  277. if (value is TimeSpan time)
  278. return time;
  279. if (TimeSpan.TryParseExact(value as string, "c", CultureInfo.InvariantCulture, TimeSpanStyles.None, out var result))
  280. return result;
  281. if (TimeSpan.TryParse(value as string, out result))
  282. return result;
  283. return variable.Deserialize(values.GetEntry(variable.Code));
  284. }
  285. else if (fieldType == typeof(DFLayoutVideoField))
  286. {
  287. if (value is byte[] b)
  288. return ConvertVideo(b);
  289. else if (value is string str)
  290. {
  291. if (Guid.TryParse(str, out var id))
  292. return variable.Deserialize(values.GetEntry(variable.Code));
  293. try
  294. {
  295. var tuple = Serialization.Deserialize<Tuple<Guid, byte[]>>(str, true);
  296. if (tuple != null)
  297. {
  298. return new DFLayoutEmbeddedMediaValue
  299. {
  300. ID = tuple.Item1,
  301. Thumbnail = tuple.Item2,
  302. };
  303. }
  304. }
  305. catch
  306. {
  307. }
  308. try
  309. {
  310. return ConvertVideo(System.Convert.FromBase64String(str));
  311. }
  312. catch (Exception e)
  313. {
  314. throw new Exception($"Error in video data; invalid Base-64: {e.Message}");
  315. }
  316. }
  317. return variable.Deserialize(values.GetEntry(variable.Code));
  318. }
  319. else if(fieldType == typeof(DFLayoutAddTaskField))
  320. {
  321. return value?.ToString();
  322. }
  323. else
  324. {
  325. throw new Exception($"Unhandled variable type {fieldType}");
  326. }
  327. }
  328. private bool UpdateForm(Type formType, IDigitalFormInstance instance, DigitalForm form, IList<DigitalFormVariable> variables)
  329. {
  330. var values = DigitalForm.DeserializeFormData(instance);
  331. if(values is null)
  332. {
  333. return false;
  334. }
  335. var save = new DFSaveStorage();
  336. foreach(var variable in variables)
  337. {
  338. try
  339. {
  340. var value = Deserialize(variable, variable.FieldType(), values);
  341. variable.Serialize(save.GetEntry(variable.Code), value);
  342. }
  343. catch(Exception e)
  344. {
  345. Logger.Send(LogType.Error, "", $"Error in data for {variable.Code} ({instance.ID}): {e.Message}");
  346. save.FormData[variable.Code] = values.GetValue(variable.Code);
  347. foreach(var (k, v) in values.GetEntry(variable.Code).SubItems())
  348. {
  349. save.FormData[$"{variable.Code}.{k}"] = v;
  350. }
  351. }
  352. }
  353. foreach(var (k, v) in values.Items())
  354. {
  355. if(!save.FormData.ContainsKey(k) && !k.Contains('.') && !variables.Any(x => x.Code == k))
  356. {
  357. save.FormData[k] = v;
  358. }
  359. }
  360. DigitalForm.SerializeFormData(instance, variables, save);
  361. return instance.IsChanged();
  362. }
  363. }
  364. }