PageRenderTime 37ms CodeModel.GetById 25ms RepoModel.GetById 0ms app.codeStats 0ms

/Serenity.Web/Upload/MultipleImageUploadBehavior.cs

https://gitlab.com/pgksunilkumar/Serenity
C# | 201 lines | 157 code | 44 blank | 0 comment | 33 complexity | 41395e6728ce0d79cbc9deb4234a42ef MD5 | raw file
  1. using Serenity.ComponentModel;
  2. using Serenity.Data;
  3. using Serenity.Web;
  4. using System;
  5. using System.Linq;
  6. using System.IO;
  7. namespace Serenity.Services
  8. {
  9. public class MultipleImageUploadBehavior : BaseSaveDeleteBehavior, IImplicitBehavior, IFieldBehavior
  10. {
  11. public Field Target { get; set; }
  12. private ImageUploadEditorAttribute attr;
  13. private string fileNameFormat;
  14. private const string SplittedFormat = "{1:00000}/{0:00000000}_{2}";
  15. private UploadHelper uploadHelper;
  16. public bool ActivateFor(Row row)
  17. {
  18. if (ReferenceEquals(null, Target))
  19. return false;
  20. attr = Target.GetAttribute<ImageUploadEditorAttribute>();
  21. if (attr == null || attr.DisableDefaultBehavior || attr.EditorType != "MultipleImageUpload")
  22. return false;
  23. if (!(Target is StringField))
  24. throw new ArgumentException(String.Format(
  25. "Field '{0}' on row type '{1}' has a UploadEditor attribute but it is not a String field!",
  26. Target.PropertyName ?? Target.Name, row.GetType().FullName));
  27. if (!(row is IIdRow))
  28. throw new ArgumentException(String.Format(
  29. "Field '{0}' on row type '{1}' has a UploadEditor attribute but Row type doesn't implement IIdRow!",
  30. Target.PropertyName ?? Target.Name, row.GetType().FullName));
  31. var format = attr.FilenameFormat;
  32. if (format == null)
  33. {
  34. format = row.GetType().Name;
  35. if (format.EndsWith("Row"))
  36. format = format.Substring(0, format.Length - 3);
  37. format += "/~";
  38. }
  39. this.fileNameFormat = format.Replace("~", SplittedFormat);
  40. this.uploadHelper = new UploadHelper((attr.SubFolder.IsEmptyOrNull() ? "" : (attr.SubFolder + "/")) + (this.fileNameFormat));
  41. return true;
  42. }
  43. private class UploadedFile
  44. {
  45. public string Filename { get; set; }
  46. public string OriginalName { get; set; }
  47. }
  48. private UploadedFile[] ParseAndValidate(string json, string key)
  49. {
  50. json = json.TrimToNull();
  51. if (json != null && (!json.StartsWith("[") || !json.EndsWith("]")))
  52. throw new ArgumentOutOfRangeException(key);
  53. var list = JSON.Parse<UploadedFile[]>(json ?? "[]");
  54. if (list.Any(x => string.IsNullOrEmpty(x.Filename)) ||
  55. list.GroupBy(x => x.Filename.Trim()).SelectMany(x => x.Skip(1)).Any())
  56. throw new ArgumentOutOfRangeException(key);
  57. return list;
  58. }
  59. public override void OnBeforeSave(ISaveRequestHandler handler)
  60. {
  61. var field = (StringField)Target;
  62. if (!handler.Row.IsAssigned(field))
  63. return;
  64. var oldFilesJSON = (handler.IsCreate ? null : field[handler.Old]).TrimToNull();
  65. var newFilesJSON = field[handler.Row] = field[handler.Row].TrimToNull();
  66. if (oldFilesJSON.IsTrimmedSame(newFilesJSON))
  67. {
  68. field[handler.Row] = oldFilesJSON;
  69. return;
  70. }
  71. var oldFileList = ParseAndValidate(oldFilesJSON, "oldFiles");
  72. var newFileList = ParseAndValidate(newFilesJSON, "newFiles");
  73. var filesToDelete = new FilesToDelete();
  74. UploadHelper.RegisterFilesToDelete(handler.UnitOfWork, filesToDelete);
  75. handler.StateBag[this.GetType().FullName + "_" + Target.Name + "_FilesToDelete"] = filesToDelete;
  76. foreach (var file in oldFileList)
  77. {
  78. var filename = file.Filename.Trim();
  79. if (newFileList.Any(x => String.Compare(x.Filename.Trim(), filename, StringComparison.OrdinalIgnoreCase) == 0))
  80. continue;
  81. DeleteOldFile(filesToDelete, filename);
  82. }
  83. if (newFileList.IsEmptyOrNull())
  84. {
  85. field[handler.Row] = null;
  86. return;
  87. }
  88. if (handler.IsUpdate)
  89. field[handler.Row] = CopyTemporaryFiles(handler, oldFileList, newFileList, filesToDelete);
  90. }
  91. private void DeleteOldFile(FilesToDelete filesToDelete, string oldFilename)
  92. {
  93. if (!oldFilename.IsEmptyOrNull())
  94. {
  95. var actualOldFile = (attr.SubFolder.IsEmptyOrNull() ? "" : (attr.SubFolder + "/")) + oldFilename;
  96. filesToDelete.RegisterOldFile(actualOldFile);
  97. if (attr.CopyToHistory)
  98. {
  99. var oldFilePath = UploadHelper.ToPath(actualOldFile);
  100. string date = DateTime.UtcNow.ToString("yyyyMM", Invariants.DateTimeFormat);
  101. string historyFile = "history/" + date + "/" + Path.GetFileName(oldFilePath);
  102. if (File.Exists(UploadHelper.DbFilePath(oldFilePath)))
  103. UploadHelper.CopyFileAndRelated(UploadHelper.DbFilePath(oldFilePath), UploadHelper.DbFilePath(historyFile), overwrite: true);
  104. }
  105. }
  106. }
  107. public override void OnAfterDelete(IDeleteRequestHandler handler)
  108. {
  109. if (handler.Row is IIsActiveDeletedRow ||
  110. handler.Row is IDeleteLogRow)
  111. return;
  112. var field = (StringField)Target;
  113. var oldFilesJSON = field[handler.Row].TrimToNull();
  114. var oldFileList = ParseAndValidate(oldFilesJSON, "oldFiles");
  115. var filesToDelete = new FilesToDelete();
  116. UploadHelper.RegisterFilesToDelete(handler.UnitOfWork, filesToDelete);
  117. foreach (var file in oldFileList)
  118. DeleteOldFile(filesToDelete, file.Filename);
  119. }
  120. private string CopyTemporaryFiles(ISaveRequestHandler handler,
  121. UploadedFile[] oldFileList, UploadedFile[] newFileList, FilesToDelete filesToDelete)
  122. {
  123. foreach (var file in newFileList)
  124. {
  125. var filename = file.Filename.Trim();
  126. if (oldFileList.Any(x => String.Compare(x.Filename.Trim(), filename, StringComparison.OrdinalIgnoreCase) == 0))
  127. continue;
  128. if (!filename.ToLowerInvariant().StartsWith("temporary/"))
  129. throw new InvalidOperationException("For security reasons, only temporary files can be used in uploads!");
  130. ImageUploadBehavior.CheckUploadedImageAndCreateThumbs(attr, ref filename);
  131. var copyResult = uploadHelper.CopyTemporaryFile(filename, ((IIdRow)handler.Row).IdField[handler.Row].Value, filesToDelete);
  132. if (!attr.SubFolder.IsEmptyOrNull())
  133. copyResult.DbFileName = copyResult.DbFileName.Substring(attr.SubFolder.Length + 1);
  134. file.Filename = copyResult.DbFileName;
  135. }
  136. return JSON.Stringify(newFileList);
  137. }
  138. public override void OnAfterSave(ISaveRequestHandler handler)
  139. {
  140. if (handler.IsUpdate)
  141. return;
  142. var field = (StringField)Target;
  143. if (!handler.Row.IsAssigned(field))
  144. return;
  145. var newFilesJSON = field[handler.Row] = field[handler.Row].TrimToNull();
  146. var newFileList = ParseAndValidate(newFilesJSON, "newFiles");
  147. if (newFileList.IsEmptyOrNull())
  148. return;
  149. var filesToDelete = handler.StateBag[this.GetType().FullName + "_" + Target.Name + "_FilesToDelete"] as FilesToDelete;
  150. var copyResult = CopyTemporaryFiles(handler, new UploadedFile[0], newFileList, filesToDelete);
  151. new SqlUpdate(handler.Row.Table)
  152. .Set(field, copyResult)
  153. .WhereEqual((Field)((IIdRow)handler.Row).IdField, ((IIdRow)handler.Row).IdField[handler.Row].Value)
  154. .Execute(handler.UnitOfWork.Connection);
  155. }
  156. }
  157. }