private string ProcessFile(ContentPropertyData editorValue, ContentItemFile file, string currentPath, Guid cuid, Guid puid) { // process the file // no file, invalid file, reject change if (UploadFileTypeValidator.ValidateFileExtension(file.FileName) == false) { return(null); } // get the filepath // in case we are using the old path scheme, try to re-use numbers (bah...) var filepath = _mediaFileSystem.GetMediaPath(file.FileName, currentPath, cuid, puid); // fs-relative path using (var filestream = File.OpenRead(file.TempFilePath)) { _mediaFileSystem.AddFile(filepath, filestream, true); // must overwrite! var ext = _mediaFileSystem.GetExtension(filepath); if (_mediaFileSystem.IsImageFile(ext)) { var preValues = editorValue.PreValues.FormatAsDictionary(); var sizes = preValues.Any() ? preValues.First().Value.Value : string.Empty; using (var image = Image.FromStream(filestream)) _mediaFileSystem.GenerateThumbnails(image, filepath, sizes); } // all related properties (auto-fill) are managed by ImageCropperPropertyEditor // when the content is saved (through event handlers) } return(filepath); }
private string ProcessFile(ContentPropertyData editorValue, ContentItemFile file, string currentPath, Guid cuid, Guid puid) { // process the file // no file, invalid file, reject change if (UploadFileTypeValidator.ValidateFileExtension(file.FileName) == false) { return(null); } // get the filepath // in case we are using the old path scheme, try to re-use numbers (bah...) var filepath = _mediaFileSystem.GetMediaPath(file.FileName, currentPath, cuid, puid); // fs-relative path using (var filestream = File.OpenRead(file.TempFilePath)) { _mediaFileSystem.AddFile(filepath, filestream, true); // must overwrite! var ext = _mediaFileSystem.GetExtension(filepath); if (_mediaFileSystem.IsImageFile(ext) && ext != ".svg") { var preValues = editorValue.PreValues.FormatAsDictionary(); var sizes = preValues.Any() ? preValues.First().Value.Value : string.Empty; try { using (var image = Image.FromStream(filestream)) _mediaFileSystem.GenerateThumbnails(image, filepath, sizes); } catch (ArgumentException ex) { // send any argument errors caused by the thumbnail generation to the log instead of failing miserably LogHelper.WarnWithException <ImageCropperPropertyValueEditor>("Could not extract image thumbnails.", ex); } } // all related properties (auto-fill) are managed by ImageCropperPropertyEditor // when the content is saved (through event handlers) } return(filepath); }
private string ProcessFile(ContentPropertyData editorValue, ContentPropertyFile file, string currentPath, Guid cuid, Guid puid) { // process the file // no file, invalid file, reject change if (UploadFileTypeValidator.ValidateFileExtension(file.FileName) == false) { return(null); } // get the filepath // in case we are using the old path scheme, try to re-use numbers (bah...) var filepath = _mediaFileSystem.GetMediaPath(file.FileName, currentPath, cuid, puid); // fs-relative path using (var filestream = File.OpenRead(file.TempFilePath)) { // TODO: Here it would make sense to do the auto-fill properties stuff but the API doesn't allow us to do that right // since we'd need to be able to return values for other properties from these methods _mediaFileSystem.AddFile(filepath, filestream, true); // must overwrite! } return(filepath); }
/// <summary> /// Converts the value received from the editor into the value can be stored in the database. /// </summary> /// <param name="editorValue">The value received from the editor.</param> /// <param name="currentValue">The current value of the property</param> /// <returns>The converted value.</returns> /// <remarks> /// <para>The <paramref name="currentValue"/> is used to re-use the folder, if possible.</para> /// <para>The <paramref name="editorValue"/> is value passed in from the editor. We normally don't care what /// the editorValue.Value is set to because we are more interested in the files collection associated with it, /// however we do care about the value if we are clearing files. By default the editorValue.Value will just /// be set to the name of the file - but again, we just ignore this and deal with the file collection in /// editorValue.AdditionalData.ContainsKey("files")</para> /// <para>We only process ONE file. We understand that the current value may contain more than one file, /// and that more than one file may be uploaded, so we take care of them all, but we only store ONE file. /// Other places (FileUploadPropertyEditor...) do NOT deal with multiple files, and our logic for reusing /// folders would NOT work, etc.</para> /// </remarks> public override object ConvertEditorToDb(ContentPropertyData editorValue, object currentValue) { currentValue = currentValue ?? string.Empty; // at that point, // currentValue is either empty or "/media/path/to/img.jpg" // editorValue.Value is { "clearFiles": true } or { "selectedFiles": "img1.jpg,img2.jpg" } // comparing them makes little sense // check the editorValue value to see whether we need to clear files var editorJsonValue = editorValue.Value as JObject; var clears = editorJsonValue != null && editorJsonValue["clearFiles"] != null && editorJsonValue["clearFiles"].Value <bool>(); var uploads = editorValue.AdditionalData.ContainsKey("files") && editorValue.AdditionalData["files"] is IEnumerable <ContentItemFile>; // nothing = no changes, return what we have already (leave existing files intact) if (clears == false && uploads == false) { return(currentValue); } // get the current file paths var currentPaths = currentValue.ToString() .Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries) .Select(x => _mediaFileSystem.GetRelativePath(x)) // get the fs-relative path .ToArray(); // if clearing, remove these files and return if (clears) { foreach (var pathToRemove in currentPaths) { _mediaFileSystem.DeleteFile(pathToRemove, true); } return(string.Empty); // no more files } // ensure we have the required guids if (editorValue.AdditionalData.ContainsKey("cuid") == false || // for the content item editorValue.AdditionalData.ContainsKey("puid") == false) // and the property type { throw new Exception("Missing cuid/puid additional data."); } var cuido = editorValue.AdditionalData["cuid"]; var puido = editorValue.AdditionalData["puid"]; if ((cuido is Guid) == false || (puido is Guid) == false) { throw new Exception("Invalid cuid/puid additional data."); } var cuid = (Guid)cuido; var puid = (Guid)puido; if (cuid == Guid.Empty || puid == Guid.Empty) { throw new Exception("Invalid cuid/puid additional data."); } // process the files var files = ((IEnumerable <ContentItemFile>)editorValue.AdditionalData["files"]).ToArray(); var newPaths = new List <string>(); const int maxLength = 1; // we only process ONE file for (var i = 0; i < maxLength /*files.Length*/; i++) { var file = files[i]; // skip invalid files if (UploadFileTypeValidator.ValidateFileExtension(file.FileName) == false) { continue; } // get the filepath // in case we are using the old path scheme, try to re-use numbers (bah...) var reuse = i < currentPaths.Length ? currentPaths[i] : null; // this would be WRONG with many files var filepath = _mediaFileSystem.GetMediaPath(file.FileName, reuse, cuid, puid); // fs-relative path using (var filestream = File.OpenRead(file.TempFilePath)) { _mediaFileSystem.AddFile(filepath, filestream, true); // must overwrite! var ext = _mediaFileSystem.GetExtension(filepath); if (_mediaFileSystem.IsImageFile(ext) && ext != ".svg") { var preValues = editorValue.PreValues.FormatAsDictionary(); var sizes = preValues.Any() ? preValues.First().Value.Value : string.Empty; using (var image = Image.FromStream(filestream)) _mediaFileSystem.GenerateThumbnails(image, filepath, sizes); } // all related properties (auto-fill) are managed by FileUploadPropertyEditor // when the content is saved (through event handlers) newPaths.Add(filepath); } } // remove all temp files foreach (var file in files) { File.Delete(file.TempFilePath); } // remove files that are not there anymore foreach (var pathToRemove in currentPaths.Except(newPaths)) { _mediaFileSystem.DeleteFile(pathToRemove, true); } return(string.Join(",", newPaths.Select(x => _mediaFileSystem.GetUrl(x)))); }
/// <summary> /// Overrides the deserialize value so that we can save the file accordingly /// </summary> /// <param name="editorValue"> /// This is value passed in from the editor. We normally don't care what the editorValue.Value is set to because /// we are more interested in the files collection associated with it, however we do care about the value if we /// are clearing files. By default the editorValue.Value will just be set to the name of the file (but again, we /// just ignore this and deal with the file collection in editorValue.AdditionalData.ContainsKey("files") ) /// </param> /// <param name="currentValue"> /// The current value persisted for this property. This will allow us to determine if we want to create a new /// file path or use the existing file path. /// </param> /// <returns></returns> public override object ConvertEditorToDb(ContentPropertyData editorValue, object currentValue) { string oldFile = string.Empty; string newFile = string.Empty; JObject newJson = null; JObject oldJson = null; //get the old src path if (currentValue != null && string.IsNullOrEmpty(currentValue.ToString()) == false) { try { oldJson = JObject.Parse(currentValue.ToString()); } catch (Exception ex) { //for some reason the value is invalid so continue as if there was no value there LogHelper.WarnWithException <ImageCropperPropertyValueEditor>("Could not parse current db value to a JObject", ex); } if (oldJson != null && oldJson["src"] != null) { oldFile = oldJson["src"].Value <string>(); } } //get the new src path if (editorValue.Value != null) { newJson = editorValue.Value as JObject; if (newJson != null && newJson["src"] != null) { newFile = newJson["src"].Value <string>(); } } //compare old and new src path //if not alike, that means we have a new file, or delete the current one... if (string.IsNullOrEmpty(newFile) || editorValue.AdditionalData.ContainsKey("files")) { var fs = FileSystemProviderManager.Current.GetFileSystemProvider <MediaFileSystem>(); //if we have an existing file, delete it if (string.IsNullOrEmpty(oldFile) == false) { fs.DeleteFile(fs.GetRelativePath(oldFile), true); } else { oldFile = string.Empty; } //if we have a new file, add it to the media folder and set .src if (editorValue.AdditionalData.ContainsKey("files")) { var files = editorValue.AdditionalData["files"] as IEnumerable <ContentItemFile>; if (files != null && files.Any()) { var file = files.First(); if (UploadFileTypeValidator.ValidateFileExtension(file.FileName)) { //create name and folder number var name = IOHelper.SafeFileName(file.FileName.Substring(file.FileName.LastIndexOf(IOHelper.DirSepChar) + 1, file.FileName.Length - file.FileName.LastIndexOf(IOHelper.DirSepChar) - 1).ToLower()); //try to reuse the folder number from the current file var subfolder = UmbracoConfig.For.UmbracoSettings().Content.UploadAllowDirectories ? oldFile.Replace(fs.GetUrl("/"), "").Split('/')[0] : oldFile.Substring(oldFile.LastIndexOf("/", StringComparison.Ordinal) + 1).Split('-')[0]; //if we dont find one, create a new one int subfolderId; var numberedFolder = int.TryParse(subfolder, out subfolderId) ? subfolderId.ToString(CultureInfo.InvariantCulture) : MediaSubfolderCounter.Current.Increment().ToString(CultureInfo.InvariantCulture); //set a file name or full path var fileName = UmbracoConfig.For.UmbracoSettings().Content.UploadAllowDirectories ? Path.Combine(numberedFolder, name) : numberedFolder + "-" + name; //save file and assign to the json using (var fileStream = System.IO.File.OpenRead(file.TempFilePath)) { var umbracoFile = UmbracoMediaFile.Save(fileStream, fileName); newJson["src"] = umbracoFile.Url; return(newJson.ToString()); } } } } } //incase we submit nothing back if (editorValue.Value == null) { return(null); } return(editorValue.Value.ToString()); }
/// <summary> /// Overrides the deserialize value so that we can save the file accordingly /// </summary> /// <param name="editorValue"> /// This is value passed in from the editor. We normally don't care what the editorValue.Value is set to because /// we are more interested in the files collection associated with it, however we do care about the value if we /// are clearing files. By default the editorValue.Value will just be set to the name of the file (but again, we /// just ignore this and deal with the file collection in editorValue.AdditionalData.ContainsKey("files") ) /// </param> /// <param name="currentValue"> /// The current value persisted for this property. This will allow us to determine if we want to create a new /// file path or use the existing file path. /// </param> /// <returns></returns> public override object ConvertEditorToDb(ContentPropertyData editorValue, object currentValue) { if (currentValue == null) { currentValue = string.Empty; } //if the value is the same then just return the current value so we don't re-process everything if (string.IsNullOrEmpty(currentValue.ToString()) == false && editorValue.Value == currentValue.ToString()) { return(currentValue); } //check the editorValue value to see if we need to clear the files or not. var clear = false; var json = editorValue.Value as JObject; if (json != null && json["clearFiles"] != null && json["clearFiles"].Value <bool>()) { clear = json["clearFiles"].Value <bool>(); } var currentPersistedValues = new string[] {}; if (string.IsNullOrEmpty(currentValue.ToString()) == false) { currentPersistedValues = currentValue.ToString().Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries); } var newValue = new List <string>(); var fs = FileSystemProviderManager.Current.GetFileSystemProvider <MediaFileSystem>(); if (clear) { //Remove any files that are saved for this item foreach (var toRemove in currentPersistedValues) { fs.DeleteFile(fs.GetRelativePath(toRemove), true); } return(""); } //check for any files if (editorValue.AdditionalData.ContainsKey("files")) { var files = editorValue.AdditionalData["files"] as IEnumerable <ContentItemFile>; if (files != null) { //now we just need to move the files to where they should be var filesAsArray = files.ToArray(); //a list of all of the newly saved files so we can compare with the current saved files and remove the old ones var savedFilePaths = new List <string>(); for (var i = 0; i < filesAsArray.Length; i++) { var file = filesAsArray[i]; //don't continue if this is not allowed! if (UploadFileTypeValidator.ValidateFileExtension(file.FileName) == false) { continue; } //TODO: ALl of this naming logic needs to be put into the ImageHelper and then we need to change ContentExtensions to do the same! var currentPersistedFile = currentPersistedValues.Length >= (i + 1) ? currentPersistedValues[i] : ""; var name = IOHelper.SafeFileName(file.FileName.Substring(file.FileName.LastIndexOf(IOHelper.DirSepChar) + 1, file.FileName.Length - file.FileName.LastIndexOf(IOHelper.DirSepChar) - 1).ToLower()); var subfolder = UmbracoConfig.For.UmbracoSettings().Content.UploadAllowDirectories ? currentPersistedFile.Replace(fs.GetUrl("/"), "").Split('/')[0] : currentPersistedFile.Substring(currentPersistedFile.LastIndexOf("/", StringComparison.Ordinal) + 1).Split('-')[0]; int subfolderId; var numberedFolder = int.TryParse(subfolder, out subfolderId) ? subfolderId.ToString(CultureInfo.InvariantCulture) : MediaSubfolderCounter.Current.Increment().ToString(CultureInfo.InvariantCulture); var fileName = UmbracoConfig.For.UmbracoSettings().Content.UploadAllowDirectories ? Path.Combine(numberedFolder, name) : numberedFolder + "-" + name; using (var fileStream = File.OpenRead(file.TempFilePath)) { var umbracoFile = UmbracoMediaFile.Save(fileStream, fileName); if (umbracoFile.SupportsResizing) { var additionalSizes = new List <int>(); //get the pre-vals value var thumbs = editorValue.PreValues.FormatAsDictionary(); if (thumbs.Any()) { var thumbnailSizes = thumbs.First().Value.Value; // additional thumbnails configured as prevalues on the DataType foreach (var thumb in thumbnailSizes.Split(new[] { ";", "," }, StringSplitOptions.RemoveEmptyEntries)) { int thumbSize; if (thumb == "" || int.TryParse(thumb, out thumbSize) == false) { continue; } additionalSizes.Add(thumbSize); } } using (var image = Image.FromStream(fileStream)) { ImageHelper.GenerateMediaThumbnails(fs, fileName, umbracoFile.Extension, image, additionalSizes); } } newValue.Add(umbracoFile.Url); //add to the saved paths savedFilePaths.Add(umbracoFile.Url); } //now remove the temp file File.Delete(file.TempFilePath); } //Remove any files that are no longer saved for this item foreach (var toRemove in currentPersistedValues.Except(savedFilePaths)) { fs.DeleteFile(fs.GetRelativePath(toRemove), true); } return(string.Join(",", newValue)); } } //if we've made it here, we had no files to save and we were not clearing anything so just persist the same value we had before return(currentValue); }