/// <summary> /// Write logs on the log file /// </summary> /// <param name="log"></param> public void writeLog(CopyLog log) { //We retrieve the date DateTime date = DateTime.Now; string formatedDate = date.ToString("yyyy-MM-dd-HH-mm-ss"); //We iterate the ActionStatus value to render the log switch (log.ActionStatus) { case CopyLog.Status.Verbose: var verboseLogLine = new StringBuilder(); verboseLogLine.AppendLine($"{formatedDate}-[{log.Action} - {log.ActionStatus}] #Path : {log.ItemPath}"); File.AppendAllText(this.LogFilePath, verboseLogLine.ToString(), Encoding.UTF8); break; case CopyLog.Status.Empty: var emptyLogLine = new StringBuilder(); emptyLogLine.AppendLine("------------------------------------------------"); emptyLogLine.AppendLine($"{formatedDate}-{log.Comment}"); emptyLogLine.AppendLine("------------------------------------------------"); File.AppendAllText(this.LogFilePath, emptyLogLine.ToString(), Encoding.UTF8); break; default: //Do we display a comment ? if (string.IsNullOrWhiteSpace(log.Comment)) { var defaultLogLine = new StringBuilder(); defaultLogLine.AppendLine($"{formatedDate}-[{log.Action} - {log.ActionStatus}] #Path : {log.ItemPath}"); File.AppendAllText(this.LogFilePath, defaultLogLine.ToString(), Encoding.UTF8); } else { var defaultLogLine = new StringBuilder(); defaultLogLine.AppendLine($"{formatedDate}-[{log.Action} - {log.ActionStatus}] #Path : {log.ItemPath} #Message : {log.Comment}"); File.AppendAllText(this.LogFilePath, defaultLogLine.ToString(), Encoding.UTF8); } break; } }
/// <summary> /// Create the result csv file and set header /// </summary> /// <param name="libName">SharePoint Online library name</param> private void createFiles(string libName, string siteUrl) { //We create the result file name and ensure the Result folder exists string resultFilePath = setFilePath(libName, reportFileType.Result); string logFilePath = setFilePath(libName, reportFileType.Log); //We set to FilePath properties of the Reporting object this.ResultFilePath = resultFilePath; this.LogFilePath = logFilePath; //We create the result file and set the header var resultHeader = new StringBuilder(); var header = "Name,Type,Path,Status,Comment"; resultHeader.AppendLine(header); File.WriteAllText(resultFilePath, resultHeader.ToString(), Encoding.UTF8); //We create the log file by writing process start var logStartMessage = $"[Process beggin]Destination Site : {siteUrl} | Destination Library : {libName}"; CopyLog log = new CopyLog(logStartMessage); writeLog(log); }
/// <summary> /// BackgroundWorker Work event: /// Copy file and folders from the path selected to the target SharePoint Online library /// </summary> /// <param name="sender">Btn_Copy</param> /// <param name="e">OnClick()</param> private void bw_Dowork(object sender, DoWorkEventArgs e) { //[RESULT/LOG] We instanciate the repporting object Reporting repport = new Reporting(this.DocLib, this.Context.Web.ServerRelativeUrl); //[LOG:Verbose] We create the log object and log Local Path formating CopyLog log = new CopyLog(CopyLog.Status.Verbose, "Local path formating", LocalPath, ""); repport.writeLog(log); try { //We ensure the localpath endwith "/" for further formating actions if (!this.LocalPath.EndsWith("/") || !this.LocalPath.EndsWith("\\")) { this.LocalPath = this.LocalPath + "\\"; } //[LOG:OK] Local Path formating : Log success log.ActionStatus = CopyLog.Status.OK; repport.writeLog(log); //[LOG:Verbose] Local file retrieve log.update(CopyLog.Status.Verbose, "Local file retrieve", LocalPath, ""); repport.writeLog(log); //We retrive the list of DirectoryInfo and FileInfo List <FileInfo> files = FileLogic.getFiles(LocalPath); List <DirectoryInfo> folders = FileLogic.getSourceFolders(LocalPath); //[LOG:OK] Local file retrieve log.ActionStatus = CopyLog.Status.OK; repport.writeLog(log); //We instanciate the SPOLogic object to interact with SharePoint Online SPOLogic ctx = new SPOLogic(Context); //[LOG:Verbose] Checking library log.update(CopyLog.Status.Verbose, "Checking library", LocalPath, ""); repport.writeLog(log); //We enable Folder creation for the SharePoint Online library and ensure the Hash column exist bw.ReportProgress(0, "Checking Library"); List list = ctx.setLibraryReadyForPRocessing(this.DocLib); //[LOG:OK] Checking library log.ActionStatus = CopyLog.Status.OK; repport.writeLog(log); //[LOG:Verbose] Online ListItem retrieve log.update(CopyLog.Status.Verbose, "Online ListItem retrieve", LocalPath, ""); repport.writeLog(log); // We retrieve all listitems in the library bw.ReportProgress(0, "Retrieving ListItems"); List <ListItem> onlineListItem = ctx.GetAllDocumentsInaLibrary(this.DocLib); //[LOG:OK] Online ListItem retrieve log.ActionStatus = CopyLog.Status.OK; repport.writeLog(log); #region Folder Creation //[LOG:Title] Folder creation beggins log.update("[Starting Folder Creation process]"); repport.writeLog(log); var rootFolder = list.RootFolder; Context.Load(rootFolder); Context.ExecuteQuery(); //We set the index to display progression int i = 0; int count = 0; foreach (DirectoryInfo folder in folders) { //Progression display i++; double percentage = (double)i / folders.Count; int advancement = Convert.ToInt32(percentage * 100); bw.ReportProgress(advancement, $"Checking folders - {advancement}%\n{i}/{folders.Count}"); //We check for pending cancellation if (bw.CancellationPending == true) { //[LOG:CANCEL] Cancellation log log.update("[Process Cancelled]"); repport.writeLog(log); //We cancel the backgroundWorker and return e.Cancel = true; return; } //If no cancellation, we launch the copy folder process else { //[LOG:Verbose] Folder Creation log.update(CopyLog.Status.Verbose, "Folder creation", folder.FullName, ""); repport.writeLog(log); //We process the folder CopyStatus copyStatus = ctx.copyFolderToSPO(folder, list, LocalPath, onlineListItem); //[LOG:OK] Folder Creation log.ActionStatus = CopyLog.Status.OK; if (copyStatus != null) { //[LOG:OK] Folder Creation update path log.ItemPath = copyStatus.Path; log.Comment = copyStatus.Comment; repport.writeLog(log); //[RESULT] Folder Creation repport.writeResult(copyStatus); } else { //We skip writing result for the rootfolder repport.writeLog(log); } } } i = 0; count = 0; foreach (FoldersToProcess folder in ctx.FoldersToUpload) { //Progression display i++; double percentage = (double)i / folders.Count; int advancement = Convert.ToInt32(percentage * 100); bw.ReportProgress(advancement, $"Batching folders upload - {advancement}%\n{i}/{folders.Count}"); count++; var myFolder = rootFolder.Folders.Add(folder.ItemUrls.ServerRelativeUrl); if (count >= this.BatchRequestSize) { bw.ReportProgress(advancement, "Uploading folders batch"); Context.RequestTimeout = -1; Context.ExecuteQuery(); count = 0; } } bw.ReportProgress(0, "Finalising folders upload"); Context.RequestTimeout = -1; Context.ExecuteQuery(); i = 0; count = 0; foreach (FoldersToProcess folder in ctx.FoldersToUpload) { //Progression display i++; double percentage = (double)i / folders.Count; int advancement = Convert.ToInt32(percentage * 100); bw.ReportProgress(advancement, $"Batching folders metadata - {advancement}%\n{i}/{folders.Count}"); //We update metadate ListItem listitemFolder = Context.Web.GetListItem(folder.ItemUrls.ServerRelativeUrl); listitemFolder["Created"] = folder.Created; listitemFolder["Modified"] = folder.Modified; listitemFolder.Update(); count++; if (count >= this.BatchRequestSize) { bw.ReportProgress(advancement, "Uploading folders metadata batch"); Context.RequestTimeout = -1; Context.ExecuteQuery(); count = 0; } } bw.ReportProgress(0, "Finalising folders Metadata"); Context.RequestTimeout = -1; Context.ExecuteQuery(); #endregion #region FileCopy //[LOG:Title] File upload beggins log.update("[Starting File Upload process]"); repport.writeLog(log); //We reset the progression index i = 0; foreach (FileInfo file in files) { //Progression display i++; double percentage = (double)i / files.Count; int advancement = Convert.ToInt32(percentage * 100); bw.ReportProgress(advancement, $"Checking files - {advancement}%\n{i}/{files.Count}"); //Check if Cancellation is pending if (bw.CancellationPending == true) { //[LOG:CANCEL] Cancellation log log.update("[Process Cancelled]"); repport.writeLog(log); //We cancel the backgroundWorker and return e.Cancel = true; return; } //If no cancellation, we launch the copy file process else { //[LOG:Verbose] File Upload log.update(CopyLog.Status.Verbose, "File upload", file.FullName, ""); repport.writeLog(log); //We copy the file CopyStatus copyStatus = ctx.copyFileToSPO(file, list, LocalPath, onlineListItem); //[LOG:OK] File Upload log.ActionStatus = CopyLog.Status.OK; log.ItemPath = copyStatus.Path; log.Comment = copyStatus.Comment; //[RESULT/LOG: OK] File Upload repport.writeLog(log); repport.writeResult(copyStatus); } } #endregion #region Item Deletion //We handle the delete old items checkbox feature if (this.DeleteOldItems == true) { //[LOG:Verbose] Online ListItem retrieve log.update(CopyLog.Status.Verbose, "Online ListItem retrieve", LocalPath, ""); repport.writeLog(log); // We retrieve all listitems in the library and divide files and folders bw.ReportProgress(0, "Retrieving ListItems"); onlineListItem = ctx.GetAllDocumentsInaLibrary(this.DocLib); List <ListItem> onlineFiles = ctx.GetOnlyFiles(onlineListItem); List <ListItem> onlineFolders = ctx.GetOnlyFolders(onlineListItem); //[LOG:OK] Online ListItem retrieve log.ActionStatus = CopyLog.Status.OK; repport.writeLog(log); //[LOG:Title] File deletion beggins log.update("[Starting File Deletion process]"); repport.writeLog(log); #region File Deletion //We retrieve all the formated urls from local source files List <ItemURLs> itemsUrls = new List <ItemURLs>(); foreach (FileInfo file in files) { ItemURLs itemUrl = ctx.formatUrl(file, list, LocalPath); itemsUrls.Add(itemUrl); } //We reset the progression index i = 0; count = 0; foreach (ListItem onlineFile in onlineFiles) { //Progression display i++; double percentage = (double)i / onlineFiles.Count; int advancement = Convert.ToInt32(percentage * 100); bw.ReportProgress(advancement, $"Checking old files - {advancement}%\n{i}/{onlineFiles.Count}"); //Check if Cancellation is pending if (bw.CancellationPending == true) { //[LOG:CANCEL] Cancellation log log.update("[Process Cancelled]"); repport.writeLog(log); //We cancel the backgroundWorker and return e.Cancel = true; return; } //If no cancellation, we launch the file deletion process else { //[LOG:Verbose] File Deletion log.update(CopyLog.Status.Verbose, "File deletion", (string)onlineFile["FileLeafRef"], ""); repport.writeLog(log); //Attempt to delete the file if necessary CopyStatus copystat = ctx.CheckItemToDelete(itemsUrls, list, LocalPath, onlineFile); if (copystat.Status == CopyStatus.ItemStatus.Deleted) { count++; ListItem item = list.GetItemById((Int32)onlineFile["ID"]); item.DeleteObject(); } if (count >= this.BatchRequestSize) { count = 0; Context.ExecuteQuery(); } //[LOG:OK] File Deletion log.ActionStatus = CopyLog.Status.OK; log.ItemPath = copystat.Path; log.Comment = copystat.Comment; //[RESULT/LOG: OK] File Deletion repport.writeLog(log); repport.writeResult(copystat); } } bw.ReportProgress(0, "Deleting old files"); Context.RequestTimeout = -1; Context.ExecuteQuery(); #endregion #region Folder Deletion //Folder deletion //We retrieve all the formated urls from local source folders List <ItemURLs> folderUrls = new List <ItemURLs>(); foreach (DirectoryInfo folder in folders) { ItemURLs itemUrl = ctx.formatUrl(folder, list, LocalPath); folderUrls.Add(itemUrl); } //We reset the progression index i = 0; count = 0; foreach (ListItem onlineFolder in onlineFolders) { //Progression display i++; Double percentage = (double)i / onlineFolders.Count; int advancement = Convert.ToInt32(percentage * 100); bw.ReportProgress(advancement, $"Checking old folders - {advancement}%\n{i}/{onlineFolders.Count}"); //Check if Cancellation is pending if (bw.CancellationPending == true) { //[LOG:CANCEL] Cancellation log log.update("[Process Cancelled]"); repport.writeLog(log); //We cancel the backgroundWorker and return e.Cancel = true; return; } //If no cancellation, we launch the folder deletion process else { //[LOG:Verbose] Folder Deletion log.update(CopyLog.Status.Verbose, "Folder deletion", (string)onlineFolder["FileLeafRef"], ""); repport.writeLog(log); //Attempt to delete the file if necessary CopyStatus copystat = ctx.CheckItemToDelete(folderUrls, list, LocalPath, onlineFolder); //Change the item type to folder for result purpose copystat.Type = CopyStatus.ItemType.Folder; int pathRootFolderCount = FileLogic.isRootFolder(list.RootFolder.ServerRelativeUrl); int pathFolderCount = FileLogic.isRootFolder(copystat.Path); if ((pathFolderCount - pathRootFolderCount) == 1 && copystat.Status == CopyStatus.ItemStatus.Deleted) { count++; ListItem item = list.GetItemById((Int32)onlineFolder["ID"]); item.DeleteObject(); } if (count >= this.BatchRequestSize) { Context.RequestTimeout = -1; try { Context.ExecuteQuery(); } catch (Exception ex) { if (!ex.Message.Contains("Item does not exist. It may have been deleted by another user.")) { throw ex; } } } //[LOG:OK] Folder Deletion log.ActionStatus = CopyLog.Status.OK; log.ItemPath = copystat.Path; log.Comment = copystat.Comment; //[RESULT/LOG: OK] Folder Deletion repport.writeLog(log); repport.writeResult(copystat); } } bw.ReportProgress(0, "Deleting old folders"); Context.RequestTimeout = -1; try { Context.ExecuteQuery(); } catch (Exception ex) { if (!ex.Message.Contains("Item does not exist. It may have been deleted by another user.")) { throw ex; } } #endregion } #endregion } catch (Exception ex) { //We cancel the backgroundWorker if an exception is not handled so far MessageBox.Show(ex.Message); bw.CancelAsync(); e.Cancel = true; //[LOG:ERROR] Error log log.ActionStatus = CopyLog.Status.Error; log.Comment = ex.Message; repport.writeLog(log); //[RESULT:ERROR] Error result CopyStatus copyError = new CopyStatus { Comment = ex.Message, Name = log.ItemPath, Path = log.ItemPath, Status = CopyStatus.ItemStatus.Error }; repport.writeResult(copyError); } }