public void UploadBook()
        {
            _progressBox.WriteMessage("Starting...");
            _uploadWorker         = new BackgroundWorker();
            _uploadWorker.DoWork += BackgroundUpload;
            _uploadWorker.WorkerReportsProgress = true;
            _uploadWorker.RunWorkerCompleted   += (theWorker, completedEvent) =>
            {
                // Return all controls to normal state. (Do this first, just in case we get some further exception somehow.)
                // I believe the event is guaranteed to be raised, even if something in the worker thread throws,
                // so there should be no way to get stuck in the state where the tabs etc. are disabled.
                SetStateOfNonUploadControls(true);
                // Don't call UpdateDisplay, it will wipe out the progress messages.
                if (_progressBox.CancelRequested)
                {
                    _progressBox.WriteMessageWithColor(Color.Red,
                                                       LocalizationManager.GetString("PublishTab.Upload.Cancelled", "Upload was cancelled"));
                }
                else
                {
                    if (completedEvent.Error != null)
                    {
                        string errorMessage = GetBasicErrorUploadingMessage();
                        _progressBox.WriteError(errorMessage, _model.Title);
                        _progressBox.WriteException(completedEvent.Error);
                    }
                    else if ((string)completedEvent.Result == "quiet")
                    {
                        // no more reporting, sufficient message already given.
                    }
                    else if (string.IsNullOrEmpty((string)completedEvent.Result))
                    {
                        // Something went wrong, possibly already reported.
                        if (!_model.PdfGenerationSucceeded)
                        {
                            ReportPdfGenerationFailed();
                        }
                        else
                        {
                            ReportTryAgainDuringUpload();
                        }
                    }
                    else
                    {
                        var    url             = BloomLibraryUrlPrefix + "/my-books/book/" + _parseId;
                        string congratsMessage = LocalizationManager.GetString("PublishTab.Upload.UploadCompleteNotice",
                                                                               "Congratulations, \"{0}\" is now available on BloomLibrary.org ({1})",
                                                                               "{0} is the book title; {1} is a clickable url which will display the book on the website");
                        _progressBox.WriteMessageWithColor(Color.Blue, congratsMessage, _model.Title, url);
                        BookHistory.AddEvent(_model.Book, BookHistoryEventType.Uploaded, "Book uploaded to Bloom Library");
                    }
                }

                _uploadWorker = null;
            };
            SetStateOfNonUploadControls(false);             // Last thing we do before launching the worker, so we can't get stuck in this state.
            _uploadWorker.RunWorkerAsync(_model);
        }
示例#2
0
        /// <summary>
        /// This is our primary entry point for importing from a spreadsheet. There is also a CLI command,
        /// but we shouldn't need that one much, now that we have this on our book thumb context menus.
        /// </summary>
        public void HandleImportContentFromSpreadsheet(Book.Book book)
        {
            if (!_collectionModel.CollectionSettings.HaveEnterpriseFeatures)
            {
                Enterprise.ShowRequiresEnterpriseNotice(Form.ActiveForm, "Import to Spreadsheet");
                return;
            }

            var bookPath = book.GetPathHtmlFile();

            try
            {
                string inputFilepath;
                using (var dlg = new DialogAdapters.OpenFileDialogAdapter())
                {
                    dlg.Filter           = "xlsx|*.xlsx";
                    dlg.RestoreDirectory = true;
                    dlg.InitialDirectory = GetSpreadsheetFolderFor(book, false);
                    if (DialogResult.Cancel == dlg.ShowDialog())
                    {
                        return;
                    }
                    inputFilepath = dlg.FileName;
                    var spreadsheetFolder = Path.GetDirectoryName(inputFilepath);
                    SetSpreadsheetFolder(book, spreadsheetFolder);
                }

                var importer = new SpreadsheetImporter(_webSocketServer, book, Path.GetDirectoryName(inputFilepath));
                importer.ImportWithProgress(inputFilepath);

                // The importer now does BringBookUpToDate() which accomplishes everything this did,
                // plus it may have actually changed the folder (and subsequent 'bookPath')
                // due to a newly imported title. That would cause this call to fail.
                //XmlHtmlConverter.SaveDOMAsHtml5(book.OurHtmlDom.RawDom, bookPath);
                book.ReloadFromDisk(null);
                BookHistory.AddEvent(book, TeamCollection.BookHistoryEventType.ImportSpreadsheet);
                _bookSelection.InvokeSelectionChanged(false);
            }
            catch (Exception ex)
            {
                var msg = LocalizationManager.GetString("Spreadsheet:ImportFailed", "Import failed: ");
                NonFatalProblem.Report(ModalIf.All, PassiveIf.None, msg + ex.Message, exception: ex, showSendReport: false);
            }
        }
示例#3
0
        public void DuplicateBook(Book.Book book)
        {
            var newBookDir = book.Storage.Duplicate();

            // Get rid of any TC status we copied from the original, so Bloom treats it correctly as a new book.
            BookStorage.RemoveLocalOnlyFiles(newBookDir);

            ReloadEditableCollection();

            var dupInfo = TheOneEditableCollection.GetBookInfos()
                          .FirstOrDefault(info => info.FolderPath == newBookDir);

            if (dupInfo != null)
            {
                var newBook = GetBookFromBookInfo(dupInfo);
                SelectBook(newBook);
                BookHistory.AddEvent(newBook, BookHistoryEventType.Created, $"Duplicated from existing book \"{book.Title}\"");
            }
        }
示例#4
0
        private void HandleForceUnlock(ApiRequest request)
        {
            if (!_tcManager.CheckConnection())
            {
                request.Failed();
                return;
            }

            try
            {
                var bookStatus = _tcManager.CurrentCollection.GetStatus(BookFolderName);
                var lockedBy   = bookStatus.lockedByFirstName;
                if (string.IsNullOrEmpty(lockedBy))
                {
                    lockedBy = bookStatus.lockedBy;
                }
                // Could be a problem if there's no current book or it's not in the collection folder.
                // But in that case, we don't show the UI that leads to this being called.
                _tcManager.CurrentCollection.ForceUnlock(BookFolderName);
                BookHistory.AddEvent(_bookSelection.CurrentSelection, BookHistoryEventType.ForcedUnlock, $"Admin force-unlocked while checked out to {lockedBy}.");

                UpdateUiForBook();

                Analytics.Track("TeamCollectionRevertOtherCheckout",
                                new Dictionary <string, string>()
                {
                    { "CollectionId", _settings?.CollectionId },
                    { "CollectionName", _settings?.CollectionName },
                    { "Backend", _tcManager?.CurrentCollection?.GetBackendType() },
                    { "User", CurrentUser },
                    { "BookId", _bookSelection?.CurrentSelection?.ID },
                    { "BookName", _bookSelection?.CurrentSelection?.Title }
                });


                request.PostSucceeded();
            }
            catch (Exception e)
            {
                NonFatalProblem.Report(ModalIf.All, PassiveIf.All, "Could not force unlock", null, e, true);
                request.Failed("could not unlock");
            }
        }
示例#5
0
        public void HandleCheckInCurrentBook(ApiRequest request)
        {
            Action <float> reportCheckinProgress = (fraction) =>
            {
                dynamic messageBundle = new DynamicJson();
                messageBundle.fraction = fraction;
                _socketServer.SendBundle("checkinProgress", "progress", messageBundle);
                // The status panel is supposed to be showing a progress bar in response to getting the bundle,
                // but since we're doing the checkin on the UI thread, it doesn't get painted without this.
                Application.DoEvents();
            };

            try
            {
                // Right before calling this API, the status panel makes a change that
                // should make the progress bar visible. But this method is running on
                // the UI thread so without this call it won't appear until later, when
                // we have Application.DoEvents() as part of reporting progress. We do
                // quite a bit on large books before the first file is written to the
                // zip, so one more DoEvents() here lets the bar appear at once.
                Application.DoEvents();
                _bookSelection.CurrentSelection.Save();
                if (!_tcManager.CheckConnection())
                {
                    request.Failed();
                    return;
                }

                var bookName = Path.GetFileName(_bookSelection.CurrentSelection.FolderPath);
                if (_tcManager.CurrentCollection.OkToCheckIn(bookName))
                {
                    _tcManager.CurrentCollection.PutBook(_bookSelection.CurrentSelection.FolderPath, true, false, reportCheckinProgress);
                    reportCheckinProgress(0);                     // cleans up panel for next time
                    // review: not super happy about this being here in the api. Was stymied by
                    // PutBook not knowing about the actual book object, but maybe that could be passed in.
                    BookHistory.AddEvent(_bookSelection.CurrentSelection, BookHistoryEventType.CheckIn);

                    _tcManager.CurrentCollection.PutBook(_bookSelection.CurrentSelection.FolderPath, checkin: true);

                    Analytics.Track("TeamCollectionCheckinBook",
                                    new Dictionary <string, string>()
                    {
                        { "CollectionId", _settings?.CollectionId },
                        { "CollectionName", _settings?.CollectionName },
                        { "Backend", _tcManager?.CurrentCollection?.GetBackendType() },
                        { "User", CurrentUser },
                        { "BookId", _bookSelection?.CurrentSelection.ID },
                        { "BookName", _bookSelection?.CurrentSelection.Title }
                    });
                }
                else
                {
                    // We can't check in! The system has broken down...perhaps conflicting checkouts while offline.
                    // Save our version in Lost-and-Found
                    _tcManager.CurrentCollection.PutBook(_bookSelection.CurrentSelection.FolderPath, false, true, reportCheckinProgress);
                    reportCheckinProgress(0);                     // cleans up panel for next time
                    // overwrite it with the current repo version.
                    _tcManager.CurrentCollection.CopyBookFromRepoToLocal(bookName, dialogOnError: true);
                    // Force a full reload of the book from disk and update the UI to match.
                    _bookSelection.SelectBook(_bookServer.GetBookFromBookInfo(_bookSelection.CurrentSelection.BookInfo, true));
                    var msg = LocalizationManager.GetString("TeamCollection.ConflictingEditOrCheckout",
                                                            "Someone else has edited this book or checked it out even though you were editing it! Your changes have been saved to Lost and Found");
                    ErrorReport.NotifyUserOfProblem(msg);
                    Analytics.Track("TeamCollectionConflictingEditOrCheckout",
                                    new Dictionary <string, string>()
                    {
                        { "CollectionId", _settings?.CollectionId },
                        { "CollectionName", _settings?.CollectionName },
                        { "Backend", _tcManager?.CurrentCollection?.GetBackendType() },
                        { "User", CurrentUser },
                        { "BookId", _bookSelection?.CurrentSelection?.ID },
                        { "BookName", _bookSelection?.CurrentSelection?.Title }
                    });
                }

                UpdateUiForBook();
                request.PostSucceeded();
            }
            catch (Exception e)
            {
                reportCheckinProgress(0);                 // cleans up panel progress indicator
                var msgId      = "TeamCollection.ErrorCheckingBookIn";
                var msgEnglish = "Error checking in {0}: {1}";
                var log        = _tcManager?.CurrentCollection?.MessageLog;
                // Pushing an error into the log will show the Reload Collection button. It's not obvious this
                // is useful here, since we don't know exactly what went wrong. However, it at least gives the user
                // the option to try it.
                if (log != null)
                {
                    log.WriteMessage(MessageAndMilestoneType.Error, msgId, msgEnglish, _bookSelection?.CurrentSelection?.FolderPath, e.Message);
                }
                Logger.WriteError(String.Format(msgEnglish, _bookSelection?.CurrentSelection?.FolderPath, e.Message), e);
                NonFatalProblem.ReportSentryOnly(e, $"Something went wrong for {request.LocalPath()} ({_bookSelection?.CurrentSelection?.FolderPath})");
                request.Failed("checkin failed");
            }
        }