/// <summary>
 /// Create an instance. The webSocketServer may be null unless using ImportWithProgress.
 /// </summary>
 /// <remarks>The web socket server is a constructor argument as a step in the direction
 /// of allowing this class to be instantiated and supplied with the socket server by
 /// AutoFac. However, for that to work, we'd need to move the other constructor arguments,
 /// which AutoFac can't know, to the Import method. And for now, all callers which need
 /// to pass a socket server already have one.</remarks>
 public SpreadsheetImporter(IBloomWebSocketServer webSocketServer, HtmlDom destinationDom, string pathToSpreadsheetFolder = null, string pathToBookFolder = null, CollectionSettings collectionSettings = null)
 {
     _destinationDom   = destinationDom;
     _dataDivElement   = _destinationDom.SafeSelectNodes("//div[@id='bloomDataDiv']").Cast <XmlElement>().First();
     _pathToBookFolder = pathToBookFolder;
     // Tests and CLI may not set one or more of these
     _pathToSpreadsheetFolder = pathToSpreadsheetFolder;
     _webSocketServer         = webSocketServer;
     _collectionSettings      = collectionSettings;
 }
Beispiel #2
0
        // Firebase version of the login dialog. Uses BrowserDialog, since Firebase login is only supported in browsers.

        public static void ShowFirebaseLoginDialog(IBloomWebSocketServer webSocketServer)
        {
            try
            {
                var url = GetLoginDialogUrl();

                // Precondition: we must be on the UI thread for Gecko to work.
                using (var dlg = new BrowserDialog(url))
                {
                    dlg.WebSocketServer = webSocketServer;
                    dlg.CloseMessage    = "close";
                    dlg.Width           = 400;
                    // This is more than we usually need. But it saves scrolling when doing an email sign-up.
                    dlg.Height = 510;
                    dlg.ShowDialog();
                }
            }
            catch (Exception ex)
            {
                Logger.WriteError("*** FirebaseLoginDialog threw an exception", ex);
            }
        }
 public WebSocketProgress(IBloomWebSocketServer bloomWebSocketServer)
 {
     _bloomWebSocketServer = bloomWebSocketServer;
 }
Beispiel #4
0
 /// <summary>
 /// Get an object that you can use to send messages to a given clientContext
 /// </summary>
 /// <param name="bloomWebSocketServer"></param>
 /// <param name="clientContext">This goes out with our messages and, on the client side (typescript), messages are filtered
 /// down to the context (usualy a screen) that requested them.</param>
 public WebSocketProgress(IBloomWebSocketServer bloomWebSocketServer, string clientContext)
 {
     _bloomWebSocketServer = bloomWebSocketServer;
     _clientContext        = clientContext;
 }
 /// <summary>
 /// Used by the main SpreadsheetApi call. Tests and CLI (which don't usually have access to the book)
 /// use the other ctor.
 /// </summary>
 public SpreadsheetImporter(IBloomWebSocketServer webSocketServer, Book.Book book, string pathToSpreadsheetFolder)
     : this(webSocketServer, book.OurHtmlDom, pathToSpreadsheetFolder, book.FolderPath, book.CollectionSettings)
 {
     _book = book;
 }
        public BloomLibraryUploadControl(PublishView parentView, BloomLibraryPublishModel model, IBloomWebSocketServer webSocketServer)
        {
            _model           = model;
            _parentView      = parentView;
            _webSocketServer = webSocketServer;
            InitializeComponent();
            _originalLoginText = _loginLink.Text;             // Before anything might modify it (but after InitializeComponent creates it).
            _titleLabel.Text   = _model.Title;

            _uploadSource.SelectedIndex = 0;

            _progressBox.ShowDetailsMenuItem         = true;
            _progressBox.ShowCopyToClipboardMenuItem = true;
            _progressBox.LinkClicked += _progressBox_LinkClicked;

            _okToUpload = _model.MetadataIsReadyToPublish;

            // See if saved credentials work.
            try
            {
                _model.LogIn();
            }
            catch (Exception e)
            {
                LogAndInformButDontReportFailureToConnectToServer(e);
            }
            CommonApi.NotifyLogin(() =>
            {
                this.Invoke((Action)(UpdateDisplay));
                ;
            });

            switch (_model.LicenseType)
            {
            case LicenseState.CreativeCommons:
                _creativeCommonsLink.Text = _model.LicenseToken;
                _usingNotesSuggestion     = false;
                if (string.IsNullOrWhiteSpace(_model.LicenseRights))
                {
                    _licenseNotesLabel.Hide();
                }
                else
                {
                    _licenseNotesLabel.Text = LocalizationManager.GetString("PublishTab.Upload.AdditionalRequests", "Additional Requests: ") + _model.LicenseRights;
                }
                break;

            case LicenseState.Null:
                _usingCcControls        = false;
                _licenseNotesLabel.Text = LocalizationManager.GetString("PublishTab.Upload.AllReserved", "All rights reserved (Contact the Copyright holder for any permissions.)");
                if (!string.IsNullOrWhiteSpace(_model.LicenseRights))
                {
                    _licenseNotesLabel.Text += Environment.NewLine + _model.LicenseRights;
                }
                _licenseSuggestion.Text = LocalizationManager.GetString("PublishTab.Upload.SuggestAssignCC", "Suggestion: Assigning a Creative Commons License makes it easy for you to clearly grant certain permissions to everyone.");
                break;

            case LicenseState.Custom:
                // This must be custom a license (with non-blank rights...actually,
                // currently, the palaso dialog will not allow a custom license with no rights statement).
                _usingCcControls        = false;
                _licenseNotesLabel.Text = _model.LicenseRights;
                _licenseSuggestion.Text = LocalizationManager.GetString("PublishTab.Upload.SuggestChangeCC", "Suggestion: Creative Commons Licenses make it much easier for others to use your book, even if they aren't fluent in the language of your custom license.");
                break;

            default:
                throw new ApplicationException("Unknown License state.");
            }

            _copyrightLabel.Text = _model.Copyright;
            _creditsLabel.Text   = _model.Credits;
            _summaryBox.Text     = _model.Summary;
            if (!TeamCollectionApi.TheOneInstance.CanEditBook())
            {
                _summaryBox.Enabled        = false;
                _summaryOptionalLabel.Text = LocalizationManager.GetString("TeamCollection.OptionalCheckOutEdit",
                                                                           "optional--check out to edit");
            }

            UpdateFeaturesCheckBoxesDisplay();

            var allLanguages = _model.AllLanguages;

            foreach (var lang in allLanguages.Keys)
            {
                var checkBox = new CheckBox();
                checkBox.UseMnemonic = false;
                checkBox.Text        = _model.PrettyLanguageName(lang);
                if (allLanguages[lang])
                {
                    checkBox.Checked = true;
                }
                else
                {
                    checkBox.Text += @" " + LocalizationManager.GetString("PublishTab.Upload.IncompleteTranslation",
                                                                          "(incomplete translation)",
                                                                          "This is added after the language name, in order to indicate that some parts of the book have not been translated into this language yet.");
                }
                // Disable clicking on languages that have been selected for display in this book.
                // See https://issues.bloomlibrary.org/youtrack/issue/BL-7166.
                if (lang == _model.Book.BookData.Language1.Iso639Code ||
                    lang == _model.Book.Language2IsoCode ||
                    lang == _model.Book.Language3IsoCode)
                {
                    checkBox.Checked   = true;                          // even if partial
                    checkBox.AutoCheck = false;
                }
                checkBox.Margin             = _checkBoxMargin;
                checkBox.AutoSize           = true;
                checkBox.Tag                = lang;
                checkBox.CheckStateChanged += delegate(object sender, EventArgs args)
                {
                    _langsLabel.ForeColor = LanguagesOkToUpload ? Color.Black : Color.Red;
                    if (_okToUploadDependsOnLangsChecked)
                    {
                        _okToUpload = LanguagesOkToUpload;
                        UpdateDisplay();
                    }
                };
                _languagesFlow.Controls.Add(checkBox);
            }

            UpdateAudioCheckBoxDisplay();

            _summaryOptionalLabel.Left = _summaryBox.Right - _summaryOptionalLabel.Width;             // right-align these (even if localization changes their width)
            // Copyright info is not required if the book has been put in the public domain
            // or if we are publishing from a source collection and we have original copyright info
            if (!_model.IsBookPublicDomain && !_model.HasOriginalCopyrightInfoInSourceCollection)
            {
                RequireValue(_copyrightLabel);
            }
            RequireValue(_titleLabel);

            if (BookUpload.UseSandbox)
            {
                var oldTextWidth = TextRenderer.MeasureText(_uploadButton.Text, _uploadButton.Font).Width;
                // Do not localize the following string (https://issues.bloomlibrary.org/youtrack/issue/BL-7383).
                _uploadButton.Text = "Upload (to dev.bloomlibrary.org)";
                var neededWidth = TextRenderer.MeasureText(_uploadButton.Text, _uploadButton.Font).Width;
                _uploadButton.Width += neededWidth - oldTextWidth;
            }

            // After considering all the factors except whether any languages are selected,
            // if we can upload at this point, whether we can from here on depends on whether one is checked.
            // This test needs to come after evaluating everything else uploading depends on (except login)
            _okToUploadDependsOnLangsChecked = _okToUpload;
            if (allLanguages.Keys.Any())
            {
                return;
            }
            // No languages in the book have complete data
            const string space = " ";

            _langsLabel.Text += space + LocalizationManager.GetString("PublishTab.Upload.NoLangsFound", "(None found)");
            if (!_model.OkToUploadWithNoLanguages)
            {
                _langsLabel.ForeColor = Color.Red;
                _okToUpload           = false;
            }
        }
Beispiel #7
0
 public BloomWebSocketServer()
 {
     Instance = this;
 }
Beispiel #8
0
        public static void DoWorkWithProgressDialog(IBloomWebSocketServer socketServer, string socketContext, Func <Form> makeDialog,
                                                    Func <IWebSocketProgress, BackgroundWorker, bool> doWhat, Action <Form> doWhenMainActionFalse = null, IWin32Window owner = null)
        {
            var progress = new WebSocketProgress(socketServer, socketContext);


            // NOTE: This (specifically ShowDialog) blocks the main thread until the dialog is closed.
            // Be careful to avoid deadlocks.
            using (var dlg = makeDialog())
            {
                // For now let's not try to handle letting the user abort.
                dlg.ControlBox = false;
                var worker = new BackgroundWorker();
                worker.WorkerSupportsCancellation = true;
                worker.DoWork += (sender, args) =>
                {
                    ProgressDialogApi.SetCancelHandler(() =>
                    {
                        worker.CancelAsync();
                    });

                    // A way of waiting until the dialog is ready to receive progress messages
                    while (!socketServer.IsSocketOpen(socketContext))
                    {
                        Thread.Sleep(50);
                    }
                    bool waitForUserToCloseDialogOrReportProblems;
                    try
                    {
                        waitForUserToCloseDialogOrReportProblems = doWhat(progress, worker);
                    }
                    catch (Exception ex)
                    {
                        // depending on the nature of the problem, we might want to do more or less than this.
                        // But at least this lets the dialog reach one of the states where it can be closed,
                        // and gives the user some idea things are not right.
                        socketServer.SendEvent(socketContext, "finished");
                        waitForUserToCloseDialogOrReportProblems = true;
                        progress.MessageWithoutLocalizing("Something went wrong: " + ex.Message,
                                                          ex is FatalException? ProgressKind.Fatal:ProgressKind.Error);
                    }

                    // stop the spinner
                    socketServer.SendEvent(socketContext, "finished");
                    if (waitForUserToCloseDialogOrReportProblems)
                    {
                        // Now the user is allowed to close the dialog or report problems.
                        // (ProgressDialog in JS-land is watching for this message, which causes it to turn
                        // on the buttons that allow the dialog to be manually closed (or a problem to be reported).
                        socketServer.SendBundle(socketContext, "show-buttons", new DynamicJson());
                    }
                    else
                    {
                        // Just close the dialog
                        dlg.Invoke((Action)(() =>
                        {
                            if (doWhenMainActionFalse != null)
                            {
                                doWhenMainActionFalse(dlg);
                            }
                            else
                            {
                                dlg.Close();
                            }
                        }));
                    }
                };

                worker.RunWorkerAsync();
                dlg.ShowDialog(owner);                 // returns when dialog closed
                if (progress.HasFatalProblemBeenReported)
                {
                    Application.Exit();
                }

                ProgressDialogApi.SetCancelHandler(null);
            }
        }