public void UploadToWebonary(UploadToWebonaryModel model, IUploadToWebonaryView view) { view.UpdateStatus(xWorksStrings.ksUploadingToWebonary); view.SetStatusCondition(WebonaryStatusCondition.None); if (string.IsNullOrEmpty(model.SiteName)) { view.UpdateStatus(xWorksStrings.ksErrorNoSiteName); view.SetStatusCondition(WebonaryStatusCondition.Error); return; } if (string.IsNullOrEmpty(model.UserName)) { view.UpdateStatus(xWorksStrings.ksErrorNoUsername); view.SetStatusCondition(WebonaryStatusCondition.Error); return; } if (string.IsNullOrEmpty(model.Password)) { view.UpdateStatus(xWorksStrings.ksErrorNoPassword); view.SetStatusCondition(WebonaryStatusCondition.Error); return; } if (string.IsNullOrEmpty(model.SelectedPublication)) { view.UpdateStatus(xWorksStrings.ksErrorNoPublication); view.SetStatusCondition(WebonaryStatusCondition.Error); return; } if (string.IsNullOrEmpty(model.SelectedConfiguration)) { view.UpdateStatus(xWorksStrings.ksErrorNoConfiguration); view.SetStatusCondition(WebonaryStatusCondition.Error); return; } var tempDirectoryToCompress = Path.Combine(Path.GetTempPath(), Path.GetRandomFileName()); var zipBasename = UploadFilename(model, view); if (zipBasename == null) { return; } var zipFileToUpload = Path.Combine(Path.GetTempPath(), zipBasename); Directory.CreateDirectory(tempDirectoryToCompress); ExportDictionaryContent(tempDirectoryToCompress, model, view); ExportReversalContent(tempDirectoryToCompress, model, view); ExportOtherFilesContent(tempDirectoryToCompress, model, view); CompressExportedFiles(tempDirectoryToCompress, zipFileToUpload, view); UploadToWebonary(zipFileToUpload, model, view); }
/// <summary> /// Filename of zip file to upload to webonary, based on a particular model. /// If there are any characters that might cause a problem, null is returned. /// </summary> internal static string UploadFilename(UploadToWebonaryModel basedOnModel, IUploadToWebonaryView view) { if (basedOnModel == null) { throw new ArgumentNullException(nameof(basedOnModel)); } if (string.IsNullOrEmpty(basedOnModel.SiteName)) { throw new ArgumentException(nameof(basedOnModel)); } var disallowedCharacters = MiscUtils.GetInvalidProjectNameChars(MiscUtils.FilenameFilterStrength.kFilterProjName) + "_ $.%"; if (basedOnModel.SiteName.IndexOfAny(disallowedCharacters.ToCharArray()) >= 0) { view.UpdateStatus(xWorksStrings.ksErrorInvalidCharacters); view.SetStatusCondition(WebonaryStatusCondition.Error); return(null); } return(basedOnModel.SiteName + ".zip"); }
internal void UploadToWebonary(string zipFileToUpload, UploadToWebonaryModel model, IUploadToWebonaryView view) { if (zipFileToUpload == null) { throw new ArgumentNullException("zipFileToUpload"); } if (model == null) { throw new ArgumentNullException("model"); } if (view == null) { throw new ArgumentNullException("view"); } view.UpdateStatus(xWorksStrings.ksConnectingToWebonary); var targetURI = DestinationURI(model.SiteName); using (var client = CreateWebClient()) { var credentials = string.Format("{0}:{1}", model.UserName, model.Password); client.Headers.Add("Authorization", "Basic " + Convert.ToBase64String(new UTF8Encoding().GetBytes(credentials))); client.Headers.Add("user-agent", string.Format("FieldWorks Language Explorer v.{0}", Assembly.GetExecutingAssembly().GetName().Version)); client.Headers[HttpRequestHeader.Accept] = "*/*"; byte[] response = null; try { response = client.UploadFileToWebonary(targetURI, zipFileToUpload); } catch (WebonaryClient.WebonaryException e) { if (e.StatusCode == HttpStatusCode.Redirect) { view.UpdateStatus(xWorksStrings.ksErrorWebonarySiteName); } else { view.UpdateStatus(string.Format(xWorksStrings.ksErrorCannotConnectToWebonary, Environment.NewLine, e.StatusCode, e.Message)); } view.SetStatusCondition(WebonaryStatusCondition.Error); return; } var responseText = Encoding.ASCII.GetString(response); if (client.ResponseStatusCode == HttpStatusCode.Found) { view.UpdateStatus(xWorksStrings.ksErrorWebonarySiteName); view.SetStatusCondition(WebonaryStatusCondition.Error); } else if (responseText.Contains("Upload successful")) { if (!responseText.Contains("error")) { view.UpdateStatus(xWorksStrings.ksWebonaryUploadSuccessful); view.SetStatusCondition(WebonaryStatusCondition.Success); return; } view.UpdateStatus(xWorksStrings.ksWebonaryUploadSuccessfulErrorProcessing); view.SetStatusCondition(WebonaryStatusCondition.Error); } if (responseText.Contains("Wrong username or password")) { view.UpdateStatus(xWorksStrings.ksErrorUsernameOrPassword); view.SetStatusCondition(WebonaryStatusCondition.Error); } else if (responseText.Contains("User doesn't have permission to import data")) { view.UpdateStatus(xWorksStrings.ksErrorUserDoesntHavePermissionToImportData); view.SetStatusCondition(WebonaryStatusCondition.Error); } else // Unknown error, display the server response, but cut it off at 100 characters { view.UpdateStatus(string.Format("{0}{1}{2}{1}", xWorksStrings.ksResponseFromServer, Environment.NewLine, responseText.Substring(0, Math.Min(100, responseText.Length)))); } } }
/// <summary> /// Exports the reversal xhtml and css for the reversals that the user had selected in the dialog /// </summary> private void ExportReversalContent(string tempDirectoryToCompress, UploadToWebonaryModel model, IUploadToWebonaryView webonaryView) { if (model.Reversals == null) { return; } foreach (var reversal in model.SelectedReversals) { var revWsRFC5646 = model.Reversals.Where(prop => prop.Value.Label == reversal).Select(prop => prop.Value.WritingSystem).FirstOrDefault(); webonaryView.UpdateStatus(string.Format(xWorksStrings.ExportingReversalsToWebonary, reversal)); var reversalWs = m_cache.LangProject.AnalysisWritingSystems.FirstOrDefault(ws => ws.LanguageTag == revWsRFC5646); // The reversalWs should always match the RFC5646 of one of the AnalysisWritingSystems, this exception is for future programming errors if (reversalWs == null) { throw new ApplicationException(string.Format("Could not locate reversal writing system for {0}", reversal)); } var xhtmlPath = Path.Combine(tempDirectoryToCompress, string.Format("reversal_{0}.xhtml", reversalWs.IcuLocale)); var configuration = model.Reversals[reversal]; m_exportService.ExportReversalContent(xhtmlPath, revWsRFC5646, configuration); webonaryView.UpdateStatus(xWorksStrings.ExportingReversalsToWebonaryCompleted); } }
/// <summary> /// This method will recurse into a directory and add files into the zip file with their relative path /// to the original dirToCompress. /// </summary> private static void RecursivelyAddFilesToZip(ZipFile zipFile, string dirToCompress, string dirInZip, IUploadToWebonaryView webonaryView) { foreach (var file in Directory.EnumerateFiles(dirToCompress)) { if (!IsSupportedWebonaryFile(file)) { webonaryView.UpdateStatus(string.Format(xWorksStrings.ksExcludingXXFormatUnsupported, Path.GetFileName(file), Path.GetExtension(file))); continue; } zipFile.AddFile(file, dirInZip); webonaryView.UpdateStatus(Path.GetFileName(file)); } foreach (var dir in Directory.EnumerateDirectories(dirToCompress)) { RecursivelyAddFilesToZip(zipFile, dir, Path.Combine(dirInZip, Path.GetFileName(dir.TrimEnd(Path.DirectorySeparatorChar))), webonaryView); } }
internal static void CompressExportedFiles(string tempDirectoryToCompress, string zipFileToUpload, IUploadToWebonaryView webonaryView) { webonaryView.UpdateStatus(xWorksStrings.BeginCompressingDataForWebonary); using (var zipFile = new ZipFile(Encoding.UTF8)) { RecursivelyAddFilesToZip(zipFile, tempDirectoryToCompress, "", webonaryView); zipFile.Save(zipFileToUpload); } webonaryView.UpdateStatus(xWorksStrings.FinishedCompressingDataForWebonary); }
/// <summary> /// Exports the dictionary xhtml and css for the publication and configuration that the user had selected in the dialog. /// </summary> private void ExportDictionaryContent(string tempDirectoryToCompress, UploadToWebonaryModel model, IUploadToWebonaryView webonaryView) { webonaryView.UpdateStatus(String.Format(xWorksStrings.ExportingEntriesToWebonary, model.SelectedPublication, model.SelectedConfiguration)); var xhtmlPath = Path.Combine(tempDirectoryToCompress, "configured.xhtml"); var configuration = model.Configurations[model.SelectedConfiguration]; m_exportService.ExportDictionaryContent(xhtmlPath, configuration); webonaryView.UpdateStatus(xWorksStrings.ExportingEntriesToWebonaryCompleted); }
internal void UploadToWebonary(string zipFileToUpload, UploadToWebonaryModel model, IUploadToWebonaryView view) { if (zipFileToUpload == null) { throw new ArgumentNullException("zipFileToUpload"); } if (model == null) { throw new ArgumentNullException("model"); } if (view == null) { throw new ArgumentNullException("view"); } view.UpdateStatus("Connecting to Webonary."); var targetURI = DestinationURI(model.SiteName); using (var client = CreateWebClient()) { var credentials = string.Format("{0}:{1}", model.UserName, model.Password); client.Headers.Add("Authorization", "Basic " + Convert.ToBase64String(new UTF8Encoding().GetBytes(credentials))); client.Headers.Add("user-agent", string.Format("FieldWorks Language Explorer v.{0}", Assembly.GetExecutingAssembly().GetName().Version)); client.Headers[HttpRequestHeader.Accept] = "*/*"; byte[] response = null; try { response = client.UploadFileToWebonary(targetURI, zipFileToUpload); } catch (WebonaryClient.WebonaryException e) { if (e.StatusCode == HttpStatusCode.Redirect) { view.UpdateStatus("Error: There has been an error accessing webonary. Is your sitename correct?"); } else { const string errorMessage = "Unable to connect to Webonary. Please check your username and password and your Internet connection."; view.UpdateStatus(string.Format("An error occurred uploading your data: {0}{1}{2}:{3}", errorMessage, Environment.NewLine, e.StatusCode, e.Message)); } view.SetStatusCondition(WebonaryStatusCondition.Error); return; } var responseText = Encoding.ASCII.GetString(response); if (client.ResponseStatusCode == HttpStatusCode.Found) { view.UpdateStatus("Error: There has been an error accessing webonary. Is your sitename correct?"); view.SetStatusCondition(WebonaryStatusCondition.Error); } else if (responseText.Contains("Upload successful")) { if (!responseText.Contains("error")) { view.UpdateStatus("Upload successful. " + "Preparing your data for publication. " + "This may take several minutes to a few hours depending on the size of your dictionary. " + "You will receive an email when the process is complete. " + "You can examine the progress on the admin page of your Webonary site. " + "You may now safely close this dialog."); view.SetStatusCondition(WebonaryStatusCondition.Success); return; } view.UpdateStatus("The upload was successful; however, there were errors processing your data."); view.SetStatusCondition(WebonaryStatusCondition.Error); } if (responseText.Contains("Wrong username or password")) { view.UpdateStatus("Error: Wrong username or password"); view.SetStatusCondition(WebonaryStatusCondition.Error); } else if (responseText.Contains("User doesn't have permission to import data")) { view.UpdateStatus("Error: User doesn't have permission to import data"); view.SetStatusCondition(WebonaryStatusCondition.Error); } else // Unknown error, display the server response, but cut it off at 100 characters { view.UpdateStatus(string.Format("Response from server:{0}{1}{0}", Environment.NewLine, responseText.Substring(0, Math.Min(100, responseText.Length)))); } } }