/// <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); }
public UploadToWebonaryDlg(UploadToWebonaryController controller, UploadToWebonaryModel model, Mediator mediator) { InitializeComponent(); if (MiscUtils.IsUnix) { MinimumSize = new Size(MinimumSize.Width, MinimumSize.Height + m_additionalMinimumHeightForMono); } m_controller = controller; Mediator = mediator; Model = model; LoadFromModel(); m_helpTopicProvider = mediator.HelpTopicProvider; // When a link is clicked, open a web page to the URL. explanationLabel.LinkClicked += (sender, args) => { using (Process.Start(((LinkLabel)sender).Text.Substring(args.Link.Start, args.Link.Length))) {} }; // Restore the location and size from last time we called this dialog. if (Mediator != null && Mediator.PropertyTable != null) { object locWnd = Mediator.PropertyTable.GetValue("UploadToWebonaryDlg_Location"); object szWnd = Mediator.PropertyTable.GetValue("UploadToWebonaryDlg_Size"); if (locWnd != null && szWnd != null) { Rectangle rect = new Rectangle((Point)locWnd, (Size)szWnd); ScreenUtils.EnsureVisibleRect(ref rect); DesktopBounds = rect; StartPosition = FormStartPosition.Manual; } } // Start with output log area not shown by default // When a user clicks Publish, it is revealed. This is done within the context of having a resizable table of controls, and having // the output log area be the vertically growing control when a user increases the height of the dialog this.Shown += (sender, args) => { this.Height = this.Height - outputLogTextbox.Height; }; // Handle localizable explanation area with link. var explanationText = xWorksStrings.toApplyForWebonaryAccountExplanation; var explanationTextLink = xWorksStrings.toApplyForWebonaryAccountLink; var explanationTextLinkStart = explanationText.IndexOf("{", StringComparison.Ordinal); var explanationTextLinkLength = explanationTextLink.Length; explanationLabel.Text = string.Format(explanationText, explanationTextLink); // Don't blow up if a localization didn't allow for the link. if (explanationTextLinkStart < 0) { explanationTextLinkStart = 0; explanationTextLinkLength = 0; } explanationLabel.LinkArea = new LinkArea(explanationTextLinkStart, explanationTextLinkLength); }
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); }
public void UploadToWebonaryThrowsOnNullInput() { using (var controller = new MockUploadToWebonaryController(Cache, m_mediator, null, null)) { var view = new MockWebonaryDlg(); var model = new UploadToWebonaryModel(m_mediator); Assert.Throws <ArgumentNullException>(() => controller.UploadToWebonary(null, model, view)); Assert.Throws <ArgumentNullException>(() => controller.UploadToWebonary("notNull", null, view)); Assert.Throws <ArgumentNullException>(() => controller.UploadToWebonary("notNull", model, null)); } }
/// <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"); }
/// <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 stub is intended for other files related to front- and backmatter (things not really managed by FLEx itself)</summary> private void ExportOtherFilesContent(string tempDirectoryToCompress, UploadToWebonaryModel logTextbox, object outputLogTextbox) { //TODO: Copy the user selected other files into the temp directory and normalize filenames to NFC }
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)))); } } }
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)))); } } }
public void DecryptPassword_NullAndEmptyDoNotCrash() { Assert.DoesNotThrow(() => UploadToWebonaryModel.DecryptPassword(null)); Assert.DoesNotThrow(() => UploadToWebonaryModel.DecryptPassword(string.Empty)); }