/// <summary> /// Creates the file, if not exists. /// </summary> /// <param name="filePath"> /// <see cref="CloudPact.MowblyFramework.Core.Managers.FilePath">FilePath</see> object /// </param> /// <param name="storageType"> /// </param> /// <returns></returns> internal static string GetAbsolutePath(FilePath filePath, bool shouldCreateFile = true) { string rootDir = String.Empty; FileLevel level = filePath.Level; StorageType storageType = filePath.StorageType; string path = filePath.Path; if (level != FileLevel.Storage && !path.StartsWith("/") && !path.StartsWith("file://")) { rootDir = (storageType == StorageType.Cache) ? Mowbly.CacheDirectory : Mowbly.DocumentsDirectory; } // Get the full path path = Path.Combine(rootDir, filePath.Path); // Create the file if (shouldCreateFile) { CreateFile(path); } return(path); }
/// <summary> /// Publishes a file based on the type of versioning required on the parent library. /// </summary> /// <param name="file">Target file to publish.</param> /// <param name="level">Target publish direction (Draft and Published only apply, Checkout is ignored).</param> public static void PublishFileToLevel(this File file, FileLevel level) { if (file == null) { throw new ArgumentNullException("file"); } var publishingRequired = false; var approvalRequired = false; if (level == FileLevel.Draft || level == FileLevel.Published) { var context = file.Context; var parentList = file.ListItemAllFields.ParentList; context.Load(parentList, l => l.EnableMinorVersions, l => l.EnableModeration, l => l.ForceCheckout); var checkOutRequired = parentList.ForceCheckout; try { context.ExecuteQueryRetry(); publishingRequired = parentList.EnableMinorVersions; // minor versions implies that the file must be published approvalRequired = parentList.EnableModeration; } catch (ServerException ex) { if (ex.Message != "The object specified does not belong to a list.") { throw; } } if (file.CheckOutType != CheckOutType.None || checkOutRequired) { LoggingUtility.Internal.TraceVerbose("Checking in file '{0}'", file.Name); file.CheckIn("Checked in by provisioning", publishingRequired ? CheckinType.MinorCheckIn : CheckinType.MajorCheckIn); context.ExecuteQueryRetry(); } if (level == FileLevel.Published) { if (publishingRequired) { LoggingUtility.Internal.TraceVerbose("Publishing file '{0}'", file.Name); file.Publish("Published by provisioning"); context.ExecuteQueryRetry(); } if (approvalRequired) { LoggingUtility.Internal.TraceVerbose("Approving file '{0}'", file.Name); file.Approve("Approved by provisioning"); context.ExecuteQueryRetry(); } } } }
public ProjectConfigHelper(string projectId, FileLevel fileLevel = FileLevel.SOURCE) { if (String.IsNullOrEmpty(projectId)) { throw new Exception(nameof(projectId)); } this.ProjectId = projectId; this.FileLevel = fileLevel; InitialiseProjectConfiguration(); }
/// <summary> /// Constructor for Directory class /// </summary> /// <param name="src">Source Name</param> /// <param name="folder">Folder Path</param> /// <param name="overwrite">Overwrite property</param> /// <param name="level">File Level</param> /// <param name="recursive">Recursive property</param> /// <param name="includeExtensions">Extensions which can be included in directory files</param> /// <param name="excludeExtensions">Extensions which are excluded in drectory files</param> /// <param name="metadataMappingFile">Metadata Mapping File</param> /// <param name="security">ObjectSecurity</param> public Directory(string src, string folder, bool overwrite, FileLevel level = FileLevel.Draft, bool recursive = false, string includeExtensions = null, string excludeExtensions = null, string metadataMappingFile = null, ObjectSecurity security = null) : this() { this.Src = src; this.Folder = folder; this.Overwrite = overwrite; this.Level = level; this.Recursive = recursive; this.IncludedExtensions = includeExtensions; this.ExcludedExtensions = excludeExtensions; this.MetadataMappingFile = metadataMappingFile; if (security != null) { this.Security = security; } }
public static File UploadFile(this Folder folder, string fileName, string localFilePath, IDictionary <string, string> additionalProperties = null, bool replaceContent = true, bool checkHashBeforeUpload = true, FileLevel level = FileLevel.Published, bool useWebDav = true) { if (fileName == null) { throw new ArgumentNullException("fileName"); } if (string.IsNullOrWhiteSpace(fileName)) { throw new ArgumentException("Destination file name is required.", "fileName"); } if (localFilePath == null) { throw new ArgumentNullException("localFilePath"); } if (string.IsNullOrWhiteSpace(localFilePath)) { throw new ArgumentException("Source file path is required.", "localFilePath"); } //Console.WriteLine("Provisioning file '{0}' to '{1}'", localFilePath, fileName); using (var localStream = new System.IO.FileStream(localFilePath, System.IO.FileMode.Open)) { return(UploadFile(folder, fileName, localStream, additionalProperties, replaceContent, checkHashBeforeUpload, level, useWebDav)); } }
/// <summary> /// Constructor for the File class /// </summary> /// <param name="src">Source name of the file</param> /// <param name="folder">Targer Folder of the file</param> /// <param name="overwrite">Overwrite flag of the file</param> /// <param name="webParts">Webparts in the file</param> /// <param name="properties">Properties of the file</param> /// <param name="security">Security Rules of the file</param> /// <param name="level">Level status for the file</param> public File(string src, string folder, bool overwrite, IEnumerable <WebPart> webParts, IDictionary <string, string> properties, ObjectSecurity security = null, FileLevel level = FileLevel.Draft) : this() { this.Src = src; this.Overwrite = overwrite; this.Level = level; this.Folder = folder; this.WebParts.AddRange(webParts); if (properties != null) { foreach (var property in properties) { this.Properties.Add(property.Key, property.Value); } } if (security != null) { this.Security = security; } }
public static void PublishFileToLevel(this File file, FileLevel level) { if (file == null) { throw new ArgumentNullException("file"); } var publishingRequired = false; var approvalRequired = false; if (level == FileLevel.Draft || level == FileLevel.Published) { var context = file.Context; var parentList = file.ListItemAllFields.ParentList; context.Load(parentList, l => l.EnableMinorVersions, l => l.EnableModeration, l => l.ForceCheckout); var checkOutRequired = false; try { context.ExecuteQueryRetry(); checkOutRequired = parentList.ForceCheckout; publishingRequired = parentList.EnableMinorVersions; // minor versions implies that the file must be published approvalRequired = parentList.EnableModeration; } catch (ServerException ex) { if (ex.Message != "The object specified does not belong to a list.") { throw; } } if (file.CheckOutType != CheckOutType.None || checkOutRequired) { Log.Debug(Constants.LOGGING_SOURCE, "Checking in file '{0}'", file.Name); file.CheckIn("Checked in by provisioning", publishingRequired ? CheckinType.MinorCheckIn : CheckinType.MajorCheckIn); context.ExecuteQueryRetry(); } if (level == FileLevel.Published) { if (publishingRequired) { Log.Debug(Constants.LOGGING_SOURCE, "Publishing file '{0}'", file.Name); file.Publish("Published by provisioning"); context.ExecuteQueryRetry(); } if (approvalRequired) { Log.Debug(Constants.LOGGING_SOURCE, "Approving file '{0}'", file.Name); file.Approve("Approved by provisioning"); context.ExecuteQueryRetry(); } } } }
/// <summary> /// Uploads a file to the specified folder, but only if the contents has changed, with additional properties /// </summary> /// <param name="folder">Folder to upload file to.</param> /// <param name="fileName">Name of the file to upload</param> /// <param name="localStream">Stream containing the contents of the file</param> /// <param name="additionalProperties">Optional additional properties, e.g. ContentTypeId</param> /// <param name="replaceContent">true (default) to overwite existing files</param> /// <param name="checkHashBeforeUpload">true (default) to retrieve existing file and compare hash value, only uploading if the contents has changed</param> /// <param name="level">state to leave the file in after upload: Published (default), checked in Draft, or Checked Out</param> /// <param name="useWebDav">true (default) to save the binary directly (via webdav); false to use file creation</param> /// <returns>The uploaded File, so that additional operations (such as setting properties) can be done.</returns> public static File UploadFile(this Folder folder, string fileName, System.IO.Stream localStream, IDictionary<string, string> additionalProperties = null, bool replaceContent = true, bool checkHashBeforeUpload = true, FileLevel level = FileLevel.Published, bool useWebDav = true) { if (fileName == null) { throw new ArgumentNullException("fileName"); } if (localStream == null) { throw new ArgumentNullException("localStream"); } if (string.IsNullOrWhiteSpace(fileName)) { throw new ArgumentException("Destination file name is required.", "fileName"); } // TODO: Check for any other illegal characters in SharePoint if (fileName.Contains('/') || fileName.Contains('\\')) { throw new ArgumentException("The argument must be a single file name and cannot contain path characters.", "fileName"); } // Check for existing file if (!folder.IsObjectPropertyInstantiated("ServerRelativeUrl")) { folder.Context.Load(folder, f => f.ServerRelativeUrl); folder.Context.ExecuteQuery(); } var serverRelativeUrl = folder.ServerRelativeUrl + (folder.ServerRelativeUrl.EndsWith("/") ? "" : "/") + fileName; bool checkOutRequired = false; bool publishingRequired = false; bool approvalRequired = false; // Check for existing file var fileCollection = folder.Files; File existingFile = null; folder.Context.Load(fileCollection); folder.Context.ExecuteQuery(); foreach (var checkFile in fileCollection) { if (string.Equals(checkFile.Name, fileName, StringComparison.InvariantCultureIgnoreCase)) { existingFile = checkFile; break; } } // Determine if upload required bool uploadRequired = false; byte[] serverHash = null; if (existingFile != null) { if (replaceContent) { if (checkHashBeforeUpload) { var streamResult = existingFile.OpenBinaryStream(); folder.Context.ExecuteQuery(); // Hash contents HashAlgorithm ha = HashAlgorithm.Create(); using (var serverStream = streamResult.Value) { serverHash = ha.ComputeHash(serverStream); //Console.WriteLine("Server hash: {0}", BitConverter.ToString(serverHash)); } // Check hash (& rewind) byte[] localHash; localHash = ha.ComputeHash(localStream); localStream.Position = 0; //Console.WriteLine("Local hash: {0}", BitConverter.ToString(localHash)); // Compare hash var contentsMatch = true; for (var index = 0; index < serverHash.Length; index++) { if (serverHash[index] != localHash[index]) { //Console.WriteLine("Hash does not match"); contentsMatch = false; break; } } uploadRequired = !contentsMatch; } else { //Console.WriteLine("Not checking if existing file is the same; force upload"); uploadRequired = true; } } else { throw new Exception("File already exists, replace contents needs to be specified."); } } else { uploadRequired = true; } File file = null; // If different, upload file if (uploadRequired) { LoggingUtility.Internal.TraceInformation((int)EventId.UploadFile, CoreResources.FileFolderExtensions_UploadFile0ToFolder1, fileName, folder.ServerRelativeUrl); if (existingFile != null) { // Existing file (upload required) -- determine if checkout required var parentList = existingFile.ListItemAllFields.ParentList; folder.Context.Load(parentList, l => l.ForceCheckout); try { folder.Context.ExecuteQuery(); checkOutRequired = parentList.ForceCheckout; } catch (ServerException ex) { if (ex.Message != "The object specified does not belong to a list.") { throw; } } //LoggingUtility.Internal.TraceVerbose("*** ForceCheckout {0}", checkOutRequired); if (checkOutRequired && existingFile.CheckOutType == CheckOutType.None) { LoggingUtility.Internal.TraceVerbose("Checking out file '{0}'", fileName); existingFile.CheckOut(); folder.Context.ExecuteQuery(); } } if (useWebDav) { using (var uploadContext = new ClientContext(folder.Context.Url) { Credentials = folder.Context.Credentials }) { LoggingUtility.Internal.TraceVerbose("Save binary direct (via webdav) to '{0}'", serverRelativeUrl); File.SaveBinaryDirect(uploadContext, serverRelativeUrl, localStream, true); uploadContext.ExecuteQuery(); } file = folder.Files.GetByUrl(serverRelativeUrl); } else { FileCreationInformation fileCreation = new FileCreationInformation(); fileCreation.ContentStream = localStream; fileCreation.Url = fileName; fileCreation.Overwrite = true; LoggingUtility.Internal.TraceVerbose("Creating file info with Url '{0}'", fileCreation.Url); file = folder.Files.Add(fileCreation); folder.Context.ExecuteQuery(); } } else { //LoggingUtility.Internal.TraceVerbose("Not uploading; existing file '{0}' in folder '{1}' is identical (hash {2})", fileName, folder.ServerRelativeUrl, BitConverter.ToString(serverHash)); LoggingUtility.Internal.TraceVerbose("Not uploading; existing file '{0}' is identical", fileName); file = existingFile; } folder.Context.Load(file); folder.Context.ExecuteQuery(); // Set file properties (child elements <Property>) var changedProperties = new Dictionary<string,string>(); var changedPropertiesString = new StringBuilder(); var propertyChanged = false; if (additionalProperties != null && additionalProperties.Count > 0) { // If this throws ServerException (does not belong to list), then shouldn't be trying to set properties) folder.Context.Load(file.ListItemAllFields); folder.Context.Load(file.ListItemAllFields.FieldValuesAsText); folder.Context.ExecuteQuery(); // Loop through and detect changes first, then, check out if required and apply foreach (var kvp in additionalProperties) { var propertyName = kvp.Key; var propertyValue = kvp.Value; var fieldValues = file.ListItemAllFields.FieldValues; var currentValue = ""; if (file.ListItemAllFields.FieldValues.ContainsKey(propertyName)) { currentValue = file.ListItemAllFields.FieldValuesAsText[propertyName]; } //LoggingUtility.Internal.TraceVerbose("*** Comparing property '{0}' to current '{1}', new '{2}'", propertyName, currentValue, propertyValue); switch (propertyName.ToUpperInvariant()) { case "CONTENTTYPE": { // TODO: Add support for named ContentType (need to lookup ID and check if it needs changing) throw new NotSupportedException("ContentType property not yet supported; use ContentTypeId instead."); //break; } case "CONTENTTYPEID": { var currentBase = currentValue.Substring(0, currentValue.Length - 34); var sameValue = (currentBase == propertyValue); if (!sameValue && propertyValue.Length >= 32 + 6 && propertyValue.Substring(propertyValue.Length - 34, 2) == "00") { var propertyBase = propertyValue.Substring(0, propertyValue.Length - 34); sameValue = (currentBase == propertyBase); } if (!sameValue) { changedProperties[propertyName] = propertyValue; changedPropertiesString.AppendFormat("{0}='{1}'; ", propertyName, propertyValue); } break; } case "PUBLISHINGASSOCIATEDCONTENTTYPE": { var testValue = ";#" + currentValue.Replace(", ", ";#") + ";#"; if (testValue != propertyValue) { changedProperties[propertyName] = propertyValue; changedPropertiesString.AppendFormat("{0}='{1}'; ", propertyName, propertyValue); } break; } default: { if (currentValue != propertyValue) { //Console.WriteLine("Setting property '{0}' to '{1}'", propertyName, propertyValue); changedProperties[propertyName] = propertyValue; changedPropertiesString.AppendFormat("{0}='{1}'; ", propertyName, propertyValue); } break; } } } if (changedProperties.Count > 0) { if (!uploadRequired) { LoggingUtility.Internal.TraceInformation((int)EventId.UpdateFileProperties, CoreResources.FileFolderExtensions_UpdateFile0Properties1, fileName, changedPropertiesString); if (existingFile != null) { // Existing file (no upload required, but properties were changed) -- determine if checkout required var parentList = file.ListItemAllFields.ParentList; folder.Context.Load(parentList, l => l.ForceCheckout); try { folder.Context.ExecuteQuery(); checkOutRequired = parentList.ForceCheckout; } catch (ServerException ex) { if (ex.Message != "The object specified does not belong to a list.") { throw; } } //LoggingUtility.Internal.TraceVerbose("*** ForceCheckout2 {0}", checkOutRequired, approvalRequired); if (checkOutRequired && file.CheckOutType == CheckOutType.None) { LoggingUtility.Internal.TraceVerbose("Checking out file '{0}'", fileName); file.CheckOut(); folder.Context.ExecuteQuery(); } } } else { LoggingUtility.Internal.TraceVerbose("Updating properties of file '{0}' after upload: {1}", fileName, changedPropertiesString); } foreach (var kvp in changedProperties) { var propertyName = kvp.Key; var propertyValue = kvp.Value; file.ListItemAllFields[propertyName] = propertyValue; } file.ListItemAllFields.Update(); folder.Context.ExecuteQuery(); propertyChanged = true; } } //LoggingUtility.Internal.TraceVerbose("*** Up {0}, Prop {1}, COT {2}, level", uploadRequired, propertyChanged, file.CheckOutType, level); if (uploadRequired || propertyChanged && (level == FileLevel.Draft || level == FileLevel.Published)) { var parentList2 = file.ListItemAllFields.ParentList; folder.Context.Load(parentList2, l => l.EnableMinorVersions, l => l.EnableModeration); try { folder.Context.ExecuteQuery(); publishingRequired = parentList2.EnableMinorVersions; approvalRequired = parentList2.EnableModeration; } catch (ServerException ex) { if (ex.Message != "The object specified does not belong to a list.") { throw; } } //LoggingUtility.Internal.TraceVerbose("*** EnableMinorVerions {0}. EnableModeration {1}", publishingRequired, approvalRequired); if (file.CheckOutType != CheckOutType.None || checkOutRequired) { LoggingUtility.Internal.TraceVerbose("Checking in file '{0}'", fileName); file.CheckIn("Checked in by provisioning", publishingRequired ? CheckinType.MinorCheckIn : CheckinType.MajorCheckIn); folder.Context.ExecuteQuery(); } if (level == FileLevel.Published) { if (publishingRequired) { LoggingUtility.Internal.TraceVerbose("Publishing file '{0}'", fileName); file.Publish("Published by provisioning"); folder.Context.ExecuteQuery(); } if (approvalRequired) { LoggingUtility.Internal.TraceVerbose("Approving file '{0}'", fileName); file.Approve("Approved by provisioning"); folder.Context.ExecuteQuery(); } } } return file; }
/// <summary> /// Uploads a file to the specified folder, but only if the contents has changed, with additional properties /// </summary> /// <param name="folder">Folder to upload file to</param> /// <param name="fileName">Name of the file to upload</param> /// <param name="localFilePath">Location of the file to be uploaded</param> /// <param name="additionalProperties">Optional additional properties, e.g. ContentTypeId</param> /// <param name="replaceContent">true (default) to overwite existing files</param> /// <param name="checkHashBeforeUpload">true (default) to retrieve existing file and compare hash value, only uploading if the contents has changed</param> /// <param name="level">state to leave the file in after upload: Published (default), checked in Draft, or Checked Out</param> /// <param name="useWebDav">true (default) to save the binary directly (via webdav); false to use file creation</param> /// <returns>The uploaded File, so that additional operations (such as setting properties) can be done.</returns> public static File UploadFile(this Folder folder, string fileName, string localFilePath, IDictionary<string, string> additionalProperties = null, bool replaceContent = true, bool checkHashBeforeUpload = true, FileLevel level = FileLevel.Published, bool useWebDav = true) { if (fileName == null) { throw new ArgumentNullException("fileName"); } if (string.IsNullOrWhiteSpace(fileName)) { throw new ArgumentException("Destination file name is required.", "fileName"); } if (localFilePath == null) { throw new ArgumentNullException("localFilePath"); } if (string.IsNullOrWhiteSpace(localFilePath)) { throw new ArgumentException("Source file path is required.", "localFilePath"); } //Console.WriteLine("Provisioning file '{0}' to '{1}'", localFilePath, fileName); using (var localStream = new System.IO.FileStream(localFilePath, System.IO.FileMode.Open)) { return UploadFile(folder, fileName, localStream, additionalProperties, replaceContent, checkHashBeforeUpload, level, useWebDav); } }
/// <summary> /// Uploads a file to the specified folder, but only if the contents has changed, with additional properties /// </summary> /// <param name="folder">Folder to upload file to</param> /// <param name="localFilePath">Location of the file to be uploaded</param> /// <param name="additionalProperties">Optional additional properties, e.g. ContentTypeId</param> /// <param name="replaceContent">true (default) to overwite existing files</param> /// <param name="checkHashBeforeUpload">true (default) to retrieve existing file and compare hash value, only uploading if the contents has changed</param> /// <param name="level">state to leave the file in after upload: Published (default), checked in Draft, or Checked Out</param> /// <param name="useWebDav">true (default) to save the binary directly (via webdav); false to use file creation</param> /// <returns>The uploaded File, so that additional operations (such as setting properties) can be done.</returns> public static File UploadFile(this Folder folder, string localFilePath, IDictionary<string, string> additionalProperties = null, bool replaceContent = true, bool checkHashBeforeUpload = true, FileLevel level = FileLevel.Published, bool useWebDav = true) { if (localFilePath == null) { throw new ArgumentNullException("localFilePath"); } if (string.IsNullOrWhiteSpace(localFilePath)) { throw new ArgumentException("Source file path is required.", "localFilePath"); } var fileName = System.IO.Path.GetFileName(localFilePath); using (var localStream = new System.IO.FileStream(localFilePath, System.IO.FileMode.Open)) { return UploadFile(folder, fileName, localStream, additionalProperties, replaceContent, checkHashBeforeUpload, level, useWebDav); } }
/// <summary> /// Invoke the method specified by the /// <see cref="CloudPact.MowblyFramework.Core.Features.JSMessage">JSMessage</see> object /// </summary> /// <param name="message"> /// <see cref="CloudPact.MowblyFramework.Core.Features.JSMessage">JSMessage</see> object /// </param> internal async override void InvokeAsync(JSMessage message) { string callbackId = message.CallbackId; try { // Variables SqliteConnection connection; DBConfig dbConfig; DbTransaction transaction; string connectionId, query, queryId; long dbSize; JObject o; switch (message.Method) { case "openDatabase": string dbName = message.Args[0] as string; Int64 dblevel = (Int64)message.Args[1]; FileLevel level = (FileLevel)dblevel; Int64 version = (Int64)message.Args[2]; float dbVersion = (float)version; string dbPassword = message.Args[3] as string; string dbPath = null; if (dbName.Equals(Mowbly.GetProperty <string>(Constants.PROPERTY_LOGS_DB))) { dbPath = Mowbly.LogDatabaseFile; if (!FileManager.FileExists(dbPath)) { FileManager.CreateFile(dbPath); } } else { dbPath = FileManager.GetAbsolutePath(new FilePath { Path = Path.Combine(Constants.DIR_DB, String.Concat(dbName, dbVersion.ToString())), Level = level, StorageType = StorageType.Internal }); } dbSize = FileManager.GetFileSize(dbPath); // Create new connection try { connection = new SqliteConnection(); connection.ConnectionString = DBUtils.GetConnectionString(dbPath, dbPassword); connection.Open(); connectionId = Guid.NewGuid().ToString(); dbConfigDict.Add(connectionId, new DBConfig { DBName = dbName, DBVersion = dbVersion, DBPath = dbPath, DBPassword = dbPassword, Connection = connection }); InvokeCallbackJavascript(callbackId, new MethodResult { Result = connectionId }); } catch (SqliteException se) { string error = String.Concat(Mowbly.GetString(Constants.STRING_DATABASE_OPEN_ERROR), se.Message); Logger.Error(error); JToken opt = message.Args[0] as JToken; string Id = opt["queryId"].ToObject <string>(); JObject obj = new JObject(); obj.Add("queryId", Id); InvokeCallbackJavascript(callbackId, new MethodResult { Code = MethodResult.FAILURE_CODE, Result = obj, Error = new MethodError { Message = error } }); } break; case "executeQuery": // Get connection id JToken options = message.Args[0] as JToken; connectionId = options["id"].ToObject <string>(); dbConfig = dbConfigDict[connectionId]; // Read args queryId = options["queryId"].ToObject <string>(); query = options["sql"].ToObject <string>().Trim(); List <object> queryParams = options["params"].ToObject <List <object> >(); // Execute query try { JArray data = null; int rowsAffected = 0; connection = dbConfig.Connection; // Throw exception is connection is null if (connection == null) { throw new ArgumentException(Mowbly.GetString(Constants.STRING_DATABASE_NO_CONNECTION_OPEN_ERROR)); } // Execute query if (query.ToLower().StartsWith("select")) { data = ProcessSelectQuery(ref connection, query, queryParams); } else { rowsAffected = ProcessNonQuery(ref connection, query, queryParams); } // Create result o = new JObject(); o.Add("queryId", queryId); JObject d = new JObject(); d.Add("rowsAffected", rowsAffected); d.Add("insertId", connection.LastInsertRowId); d.Add("rows", data); o.Add("data", d); // Notify JS InvokeCallbackJavascript(callbackId, new MethodResult { Result = o }); } catch (SqliteException se) { // Error string error = String.Concat(Mowbly.GetString(Constants.STRING_DATABASE_QUERY_ERROR), se.Message); Logger.Error(error); // Create result o = new JObject(); o.Add("queryId", queryId); // Notify Js InvokeCallbackJavascript(callbackId, new MethodResult { Code = MethodResult.FAILURE_CODE, Result = o, Error = new MethodError { Message = error } }); } break; case "beginTransaction": connectionId = message.Args[0] as string; dbConfig = dbConfigDict[connectionId]; // Begin transaction try { connection = dbConfig.Connection; // Throw exception is connection is null if (connection == null) { throw new ArgumentException(Mowbly.GetString(Constants.STRING_DATABASE_NO_CONNECTION_OPEN_ERROR)); } transaction = connection.BeginTransaction(); dbConfig.Transaction = transaction; // Notify JS InvokeCallbackJavascript(callbackId, new MethodResult { Result = true }); } catch (SqliteException se) { // Error; Notify JS string error = String.Concat(Mowbly.GetString(Constants.STRING_DATABASE_TRANSACTION_ERROR), se.Message); Logger.Error(error); JToken opt = message.Args[0] as JToken; string Id = opt["queryId"].ToObject <string>(); JObject obj = new JObject(); obj.Add("queryId", Id); InvokeCallbackJavascript(callbackId, new MethodResult { Code = MethodResult.FAILURE_CODE, Result = obj, Error = new MethodError { Message = error } }); } break; case "commit": connectionId = message.Args[0] as string; dbConfig = dbConfigDict[connectionId]; // Commit transaction try { transaction = dbConfig.Transaction; // Throw exception is transaction is null if (transaction == null) { throw new ArgumentException(Mowbly.GetString(Constants.STRING_DATABASE_NO_TRANSACTION_ACTIVE_ERROR)); } transaction.Commit(); queryId = message.Args[1] as string; o = new JObject(); o["queryId"] = queryId; o["data"] = true; // Notify JS InvokeCallbackJavascript(callbackId, new MethodResult { Result = o }); } catch (SqliteException se) { // Error; Notify JS string error = String.Concat(Mowbly.GetString(Constants.STRING_DATABASE_TRANSACTION_ERROR), se.Message); Logger.Error(error); JToken opt = message.Args[0] as JToken; string Id = opt["queryId"].ToObject <string>(); JObject obj = new JObject(); obj.Add("queryId", Id); InvokeCallbackJavascript(callbackId, new MethodResult { Code = MethodResult.FAILURE_CODE, Result = obj, Error = new MethodError { Message = error } }); } break; case "rollback": connectionId = message.Args[0] as string; dbConfig = dbConfigDict[connectionId]; // Commit transaction try { transaction = dbConfig.Transaction; transaction.Rollback(); queryId = message.Args[1] as string; o = new JObject(); o["queryId"] = queryId; o["data"] = true; // Notify JS InvokeCallbackJavascript(callbackId, new MethodResult { Result = o }); } catch (SqliteException se) { // Error; Notify JS string error = String.Concat(Mowbly.GetString(Constants.STRING_DATABASE_TRANSACTION_ERROR), se.Message); Logger.Error(error); JToken opt = message.Args[0] as JToken; string Id = opt["queryId"].ToObject <string>(); JObject obj = new JObject(); obj.Add("queryId", Id); InvokeCallbackJavascript(callbackId, new MethodResult { Code = MethodResult.FAILURE_CODE, Result = obj, Error = new MethodError { Message = error } }); } break; default: Logger.Error("Feature " + Name + " does not support method " + message.Method); break; } } catch (Exception e) { // Error; Notify JS string error = String.Concat(Mowbly.GetString(Constants.STRING_DATABASE_OPERATION_ERROR), e.Message); Logger.Error(error); JToken opt = message.Args[0] as JToken; string Id = opt["queryId"].ToObject <string>(); JObject obj = new JObject(); obj.Add("queryId", Id); InvokeCallbackJavascript(callbackId, new MethodResult { Code = MethodResult.FAILURE_CODE, Result = obj, Error = new MethodError { Message = error } }); } await Task.FromResult(0); }
public static File UploadFile(this Folder folder, string fileName, System.IO.Stream localStream, IDictionary <string, string> additionalProperties = null, bool replaceContent = true, bool checkHashBeforeUpload = true, FileLevel level = FileLevel.Published, bool useWebDav = true) { if (fileName == null) { throw new ArgumentNullException("fileName"); } if (localStream == null) { throw new ArgumentNullException("localStream"); } if (string.IsNullOrWhiteSpace(fileName)) { throw new ArgumentException("Destination file name is required.", "fileName"); } // TODO: Check for any other illegal characters in SharePoint if (fileName.Contains('/') || fileName.Contains('\\')) { throw new ArgumentException("The argument must be a single file name and cannot contain path characters.", "fileName"); } // Check for existing file if (!folder.IsObjectPropertyInstantiated("ServerRelativeUrl")) { folder.Context.Load(folder, f => f.ServerRelativeUrl); folder.Context.ExecuteQuery(); } var serverRelativeUrl = UrlUtility.Combine(folder.ServerRelativeUrl, fileName); bool checkOutRequired = false; bool publishingRequired = false; bool approvalRequired = false; // Check for existing file var fileCollection = folder.Files; File existingFile = null; folder.Context.Load(fileCollection); folder.Context.ExecuteQuery(); foreach (var checkFile in fileCollection) { if (string.Equals(checkFile.Name, fileName, StringComparison.InvariantCultureIgnoreCase)) { existingFile = checkFile; break; } } // Determine if upload required bool uploadRequired = false; byte[] serverHash = null; if (existingFile != null) { if (replaceContent) { if (checkHashBeforeUpload) { var streamResult = existingFile.OpenBinaryStream(); folder.Context.ExecuteQuery(); // Hash contents HashAlgorithm ha = HashAlgorithm.Create(); using (var serverStream = streamResult.Value) { serverHash = ha.ComputeHash(serverStream); //Console.WriteLine("Server hash: {0}", BitConverter.ToString(serverHash)); } // Check hash (& rewind) byte[] localHash; localHash = ha.ComputeHash(localStream); localStream.Position = 0; //Console.WriteLine("Local hash: {0}", BitConverter.ToString(localHash)); // Compare hash var contentsMatch = true; for (var index = 0; index < serverHash.Length; index++) { if (serverHash[index] != localHash[index]) { //Console.WriteLine("Hash does not match"); contentsMatch = false; break; } } uploadRequired = !contentsMatch; } else { //Console.WriteLine("Not checking if existing file is the same; force upload"); uploadRequired = true; } } else { throw new Exception("File already exists, replace contents needs to be specified."); } } else { uploadRequired = true; } File file = null; // If different, upload file if (uploadRequired) { LoggingUtility.Internal.TraceInformation((int)EventId.UploadFile, CoreResources.FileFolderExtensions_UploadFile0ToFolder1, fileName, folder.ServerRelativeUrl); if (existingFile != null) { // Existing file (upload required) -- determine if checkout required var parentList = existingFile.ListItemAllFields.ParentList; folder.Context.Load(parentList, l => l.ForceCheckout); try { folder.Context.ExecuteQuery(); checkOutRequired = parentList.ForceCheckout; } catch (ServerException ex) { if (ex.Message != "The object specified does not belong to a list.") { throw; } } //LoggingUtility.Internal.TraceVerbose("*** ForceCheckout {0}", checkOutRequired); if (checkOutRequired && existingFile.CheckOutType == CheckOutType.None) { LoggingUtility.Internal.TraceVerbose("Checking out file '{0}'", fileName); existingFile.CheckOut(); folder.Context.ExecuteQuery(); } } if (useWebDav) { using (var uploadContext = new ClientContext(folder.Context.Url) { Credentials = folder.Context.Credentials }) { LoggingUtility.Internal.TraceVerbose("Save binary direct (via webdav) to '{0}'", serverRelativeUrl); File.SaveBinaryDirect(uploadContext, serverRelativeUrl, localStream, true); uploadContext.ExecuteQuery(); } file = folder.Files.GetByUrl(serverRelativeUrl); } else { FileCreationInformation fileCreation = new FileCreationInformation(); fileCreation.ContentStream = localStream; fileCreation.Url = fileName; fileCreation.Overwrite = true; LoggingUtility.Internal.TraceVerbose("Creating file info with Url '{0}'", fileCreation.Url); file = folder.Files.Add(fileCreation); folder.Context.ExecuteQuery(); } } else { //LoggingUtility.Internal.TraceVerbose("Not uploading; existing file '{0}' in folder '{1}' is identical (hash {2})", fileName, folder.ServerRelativeUrl, BitConverter.ToString(serverHash)); LoggingUtility.Internal.TraceVerbose("Not uploading; existing file '{0}' is identical", fileName); file = existingFile; } folder.Context.Load(file); folder.Context.ExecuteQuery(); // Set file properties (child elements <Property>) var changedProperties = new Dictionary <string, string>(); var changedPropertiesString = new StringBuilder(); var propertyChanged = false; if (additionalProperties != null && additionalProperties.Count > 0) { // If this throws ServerException (does not belong to list), then shouldn't be trying to set properties) folder.Context.Load(file.ListItemAllFields); folder.Context.Load(file.ListItemAllFields.FieldValuesAsText); folder.Context.ExecuteQuery(); // Loop through and detect changes first, then, check out if required and apply foreach (var kvp in additionalProperties) { var propertyName = kvp.Key; var propertyValue = kvp.Value; var fieldValues = file.ListItemAllFields.FieldValues; var currentValue = ""; if (file.ListItemAllFields.FieldValues.ContainsKey(propertyName)) { currentValue = file.ListItemAllFields.FieldValuesAsText[propertyName]; } //LoggingUtility.Internal.TraceVerbose("*** Comparing property '{0}' to current '{1}', new '{2}'", propertyName, currentValue, propertyValue); switch (propertyName.ToUpperInvariant()) { case "CONTENTTYPE": { // TODO: Add support for named ContentType (need to lookup ID and check if it needs changing) throw new NotSupportedException("ContentType property not yet supported; use ContentTypeId instead."); //break; } case "CONTENTTYPEID": { var currentBase = currentValue.Substring(0, currentValue.Length - 34); var sameValue = (currentBase == propertyValue); if (!sameValue && propertyValue.Length >= 32 + 6 && propertyValue.Substring(propertyValue.Length - 34, 2) == "00") { var propertyBase = propertyValue.Substring(0, propertyValue.Length - 34); sameValue = (currentBase == propertyBase); } if (!sameValue) { changedProperties[propertyName] = propertyValue; changedPropertiesString.AppendFormat("{0}='{1}'; ", propertyName, propertyValue); } break; } case "PUBLISHINGASSOCIATEDCONTENTTYPE": { var testValue = ";#" + currentValue.Replace(", ", ";#") + ";#"; if (testValue != propertyValue) { changedProperties[propertyName] = propertyValue; changedPropertiesString.AppendFormat("{0}='{1}'; ", propertyName, propertyValue); } break; } default: { if (currentValue != propertyValue) { //Console.WriteLine("Setting property '{0}' to '{1}'", propertyName, propertyValue); changedProperties[propertyName] = propertyValue; changedPropertiesString.AppendFormat("{0}='{1}'; ", propertyName, propertyValue); } break; } } } if (changedProperties.Count > 0) { if (!uploadRequired) { LoggingUtility.Internal.TraceInformation((int)EventId.UpdateFileProperties, CoreResources.FileFolderExtensions_UpdateFile0Properties1, fileName, changedPropertiesString); if (existingFile != null) { // Existing file (no upload required, but properties were changed) -- determine if checkout required var parentList = file.ListItemAllFields.ParentList; folder.Context.Load(parentList, l => l.ForceCheckout); try { folder.Context.ExecuteQuery(); checkOutRequired = parentList.ForceCheckout; } catch (ServerException ex) { if (ex.Message != "The object specified does not belong to a list.") { throw; } } //LoggingUtility.Internal.TraceVerbose("*** ForceCheckout2 {0}", checkOutRequired, approvalRequired); if (checkOutRequired && file.CheckOutType == CheckOutType.None) { LoggingUtility.Internal.TraceVerbose("Checking out file '{0}'", fileName); file.CheckOut(); folder.Context.ExecuteQuery(); } } } else { LoggingUtility.Internal.TraceVerbose("Updating properties of file '{0}' after upload: {1}", fileName, changedPropertiesString); } foreach (var kvp in changedProperties) { var propertyName = kvp.Key; var propertyValue = kvp.Value; file.ListItemAllFields[propertyName] = propertyValue; } file.ListItemAllFields.Update(); folder.Context.ExecuteQuery(); propertyChanged = true; } } //LoggingUtility.Internal.TraceVerbose("*** Up {0}, Prop {1}, COT {2}, level", uploadRequired, propertyChanged, file.CheckOutType, level); if (uploadRequired || propertyChanged && (level == FileLevel.Draft || level == FileLevel.Published)) { var parentList2 = file.ListItemAllFields.ParentList; folder.Context.Load(parentList2, l => l.EnableMinorVersions, l => l.EnableModeration); try { folder.Context.ExecuteQuery(); publishingRequired = parentList2.EnableMinorVersions; approvalRequired = parentList2.EnableModeration; } catch (ServerException ex) { if (ex.Message != "The object specified does not belong to a list.") { throw; } } //LoggingUtility.Internal.TraceVerbose("*** EnableMinorVerions {0}. EnableModeration {1}", publishingRequired, approvalRequired); if (file.CheckOutType != CheckOutType.None || checkOutRequired) { LoggingUtility.Internal.TraceVerbose("Checking in file '{0}'", fileName); file.CheckIn("Checked in by provisioning", publishingRequired ? CheckinType.MinorCheckIn : CheckinType.MajorCheckIn); folder.Context.ExecuteQuery(); } if (level == FileLevel.Published) { if (publishingRequired) { LoggingUtility.Internal.TraceVerbose("Publishing file '{0}'", fileName); file.Publish("Published by provisioning"); folder.Context.ExecuteQuery(); } if (approvalRequired) { LoggingUtility.Internal.TraceVerbose("Approving file '{0}'", fileName); file.Approve("Approved by provisioning"); folder.Context.ExecuteQuery(); } } } return(file); }
/// <summary> /// Uploads all files in the specified local folder, after checking a hash value for changes, to the destination folder. /// </summary> /// <param name="sourcePath">Local folder to upload</param> /// <param name="destinationPrefixedUrl">Server relative URL of the destination folder; may use '~sitecollection/' or '~site/' prefix; the folder must already exist</param> /// <param name="publishingLevel">Target final state of the file, e.g. Published or Draft</param> public SynchronizationResult SynchronizeFolder(string sourcePath, string destinationPrefixedUrl, FileLevel publishingLevel) { using (_configuration.ContextManager.ContextScope(_configuration.Log)) { return(SynchronizeFolderInternal(sourcePath, _configuration.ContextManager.CurrentContext.Web, destinationPrefixedUrl, publishingLevel)); } }
public static void PublishFileToLevel(this File file, FileLevel level) { if (file == null) { throw new ArgumentNullException("file"); } var publishingRequired = false; var approvalRequired = false; if (level == FileLevel.Draft || level == FileLevel.Published) { var context = file.Context; bool normalFile = true; var checkOutRequired = false; if (normalFile) { var parentList = file.ListItemAllFields.ParentList; context.Load(parentList, l => l.EnableMinorVersions, l => l.EnableModeration, l => l.ForceCheckout); try { context.ExecuteQueryRetry(); checkOutRequired = parentList.ForceCheckout; publishingRequired = parentList.EnableMinorVersions; // minor versions implies that the file must be published approvalRequired = parentList.EnableModeration; } catch (ServerException ex) { if (ex.Message != "The object specified does not belong to a list.") { if (ex.Message.StartsWith("Cannot invoke method or retrieve property from null object. Object returned by the following call stack is null.") && ex.Message.Contains("ListItemAllFields")) { // E.g. custom display form aspx page being uploaded to the libraries Forms folder normalFile = false; } else { throw; } } } } if (file.CheckOutType != CheckOutType.None || checkOutRequired) { Log.Debug(Constants.LOGGING_SOURCE, "Checking in file '{0}'", file.Name); file.CheckIn("Checked in by provisioning", publishingRequired ? CheckinType.MinorCheckIn : CheckinType.MajorCheckIn); context.ExecuteQueryRetry(); } if (level == FileLevel.Published) { if (publishingRequired) { Log.Debug(Constants.LOGGING_SOURCE, "Publishing file '{0}'", file.Name); file.Publish("Published by provisioning"); context.ExecuteQueryRetry(); } if (approvalRequired) { Log.Debug(Constants.LOGGING_SOURCE, "Approving file '{0}'", file.Name); file.Approve("Approved by provisioning"); context.ExecuteQueryRetry(); } } } }
public static File UploadFile(this Folder folder, string localFilePath, IDictionary <string, string> additionalProperties = null, bool replaceContent = true, bool checkHashBeforeUpload = true, FileLevel level = FileLevel.Published, bool useWebDav = true) { if (localFilePath == null) { throw new ArgumentNullException("localFilePath"); } if (string.IsNullOrWhiteSpace(localFilePath)) { throw new ArgumentException("Source file path is required.", "localFilePath"); } var fileName = Path.GetFileName(localFilePath); using (var localStream = new FileStream(localFilePath, FileMode.Open)) { return(UploadFile(folder, fileName, localStream, additionalProperties, replaceContent, checkHashBeforeUpload, level, useWebDav)); } }
private Tuple <File, UploadInfo> UploadFileInternal(System.IO.Stream stream, Web web, Folder destinationFolder, string sourceFilePath, string destinationFileServerRelativeUrl, FileLevel publishingLevel) { File file = null; byte[] localHash = null; bool changed = false; var splitIndex = destinationFileServerRelativeUrl.LastIndexOf('/'); var fileName = destinationFileServerRelativeUrl.Substring(splitIndex + 1); byte[] serverHash = _configuration.HashProvider.GetFileHash(_configuration.ContextManager, _configuration.Log, destinationFileServerRelativeUrl); bool contentsMatch = false; // _configuration.Log.Information("DEBUG: Check hash: {0}", BitConverter.ToString(serverHash)); using (var streamPreprocessor = new StreamPreprocessor(_configuration.ContextManager, _configuration.Log, stream, _configuration.Preprocessors)) { // Compare hash HashAlgorithm ha = HashAlgorithm.Create(); localHash = ha.ComputeHash(streamPreprocessor.Stream); streamPreprocessor.Stream.Position = 0; // _configuration.Log.Information("DEBUG: Local hash: {0}", BitConverter.ToString(localHash)); if (localHash.Length == serverHash.Length) { contentsMatch = true; for (var index = 0; index < serverHash.Length; index++) { if (serverHash[index] != localHash[index]) { //Console.WriteLine("Hash does not match"); contentsMatch = false; break; } } } if (!contentsMatch) { // Checkout if required var checkOutRequired = false; file = web.GetFileByServerRelativeUrl(destinationFileServerRelativeUrl); _configuration.ContextManager.CurrentContext.Load(file, f => f.CheckOutType); try { _configuration.ContextManager.CurrentContext.ExecuteQuery(); var parentList = file.ListItemAllFields.ParentList; _configuration.ContextManager.CurrentContext.Load(parentList, l => l.ForceCheckout); try { _configuration.ContextManager.CurrentContext.ExecuteQuery(); if (parentList.ForceCheckout && file.CheckOutType == CheckOutType.None) { checkOutRequired = true; } } catch (ServerException ex) { if (ex.Message != "The object specified does not belong to a list.") { throw; } } } catch (ServerException ex) { if (ex.Message != "File Not Found.") { throw; } } if (checkOutRequired) { _configuration.Log.Information("Checking out file '{0}'", destinationFileServerRelativeUrl); file.CheckOut(); _configuration.ContextManager.CurrentContext.ExecuteQuery(); } // Upload file var newFileInfo = new FileCreationInformation() { ContentStream = streamPreprocessor.Stream, Url = fileName, Overwrite = true }; _configuration.Log.Information("{0} : updating ({1}..)", destinationFileServerRelativeUrl, BitConverter.ToString(localHash).Substring(0, 12)); file = destinationFolder.Files.Add(newFileInfo); _configuration.ContextManager.CurrentContext.Load(file); _configuration.ContextManager.CurrentContext.ExecuteQuery(); changed = true; // Check in and publish var publishingRequired = false; var approvalRequired = false; if (publishingLevel == FileLevel.Draft || publishingLevel == FileLevel.Published) { var context = file.Context; var parentList = file.ListItemAllFields.ParentList; context.Load(parentList, l => l.EnableMinorVersions, l => l.EnableModeration, l => l.ForceCheckout); try { context.ExecuteQuery(); checkOutRequired = parentList.ForceCheckout; publishingRequired = parentList.EnableMinorVersions; // minor versions implies that the file must be published approvalRequired = parentList.EnableModeration; } catch (ServerException ex) { if (ex.Message != "The object specified does not belong to a list.") { throw; } } if (file.CheckOutType != CheckOutType.None || checkOutRequired) { _configuration.Log.Information("Checking in file '{0}'", file.Name); file.CheckIn("Checked in by provisioning", publishingRequired ? CheckinType.MinorCheckIn : CheckinType.MajorCheckIn); context.ExecuteQuery(); } if (publishingLevel == FileLevel.Published) { if (publishingRequired) { _configuration.Log.Information("Publishing file '{0}'", file.Name); file.Publish("Published by provisioning"); context.ExecuteQuery(); } if (approvalRequired) { _configuration.Log.Information("Approving file '{0}'", file.Name); file.Approve("Approved by provisioning"); context.ExecuteQuery(); } } } _configuration.HashProvider.StoreFileHash(_configuration.ContextManager, _configuration.Log, destinationFileServerRelativeUrl, localHash); } else { _configuration.Log.Information("{0} : no change ({1}..).", destinationFileServerRelativeUrl, BitConverter.ToString(serverHash).Substring(0, 12)); } } var syncInfo = new UploadInfo(sourceFilePath, destinationFileServerRelativeUrl, changed, localHash); return(Tuple.Create(file, syncInfo)); }
private SynchronizationResult SynchronizeFolderInternal(string sourcePath, Web web, string destinationPrefixedUrl, FileLevel publishingLevel) { // TODO: Consider adding recursive, but think about subfolder creation. if (sourcePath == null) { throw new ArgumentNullException("sourcePath"); } if (web == null) { throw new ArgumentNullException("web"); } if (destinationPrefixedUrl == null) { throw new ArgumentNullException("destinationPrefixedUrl"); } var processedFiles = new List <UploadInfo>(); try { //if (recursive) //{ // throw new NotSupportedException("Recursive not supported yet"); //} var assembly = Assembly.GetExecutingAssembly(); var fvi = FileVersionInfo.GetVersionInfo(assembly.Location); _configuration.Log.Information("IonFar SharePoint Synchronizer v" + fvi.FileVersion); _configuration.Log.Information("== Uploading folder '{0}' ==", destinationPrefixedUrl); var destinationServerRelativeUrl = SPUrlUtility.ResolveServerRelativeUrl(_configuration.ContextManager.CurrentContext.Site, web, destinationPrefixedUrl); var destinationFolder = web.GetFolderByServerRelativeUrl(destinationServerRelativeUrl); var filePaths = System.IO.Directory.EnumerateFiles(sourcePath); foreach (var filePath in filePaths) { var fileName = System.IO.Path.GetFileName(filePath); var fileUrl = SPUrlUtility.Combine(destinationServerRelativeUrl, fileName); using (var localStream = System.IO.File.OpenRead(filePath)) { var uploadResult = UploadFileInternal(localStream, web, destinationFolder, filePath, fileUrl, publishingLevel); processedFiles.Add(uploadResult.Item2); } } return(new SynchronizationResult(processedFiles, successful: true, error: null)); } catch (Exception ex) { _configuration.Log.Error( "Synchronization failed and the environment has been left in a partially complete state, manual intervention may be required.\nException: {0}", ex ); return(new SynchronizationResult(processedFiles, successful: false, error: ex)); } }
/// <summary> /// Uploads a file, replacing any existing file with a new version. /// </summary> /// <param name="stream">Contents of the file to upload</param> /// <param name="web">Web the destination folder exists in</param> /// <param name="destinationPrefixedUrl">Server relative URL of the destination file; may use '~sitecollection/' or '~site/' prefix; the folder must already exist</param> /// <param name="publishingLevel">Target final state of the file, e.g. Published or Draft</param> /// <returns>The updated or newly created file</returns> public File UploadFile(System.IO.Stream stream, Web web, string destinationPrefixedUrl, FileLevel publishingLevel) { var destinationFileServerRelativeUrl = SPUrlUtility.ResolveServerRelativeUrl(_configuration.ContextManager.CurrentContext.Site, web, destinationPrefixedUrl); var destinationFolderServerRelativeUrl = destinationFileServerRelativeUrl.Substring(0, destinationFileServerRelativeUrl.LastIndexOf('/')); // _configuration.Log.Information("DEBUG: file '{0}', folder '{1}'", fileName, folderServerRelativeUrl); var destinationFolder = web.GetFolderByServerRelativeUrl(destinationFolderServerRelativeUrl); var result = UploadFileInternal(stream, web, destinationFolder, null, destinationFileServerRelativeUrl, publishingLevel); return(result.Item1); }