Esempio n. 1
0
 public override void Setup()
 {
     base.Setup();
     Program.SetUpLocalization(new ApplicationContainer());
     _bookServer = CreateBookServer();
     s_bookSelection.SelectBook(CreateBook());
 }
        protected Bloom.Book.Book CreateTestBook(string body, bool createPhysicalFile = false, string extraHeadContent = "")
        {
            Bloom.Book.Book book;
            string          head = @"<meta charset='UTF-8'/>
				<link rel='stylesheet' href='defaultLangStyles.css'/>
				<link rel='stylesheet' href='basePage.css' type='text/css'/>
				<link rel='stylesheet' href='langVisibility.css' type='text/css'/>
				<link rel='stylesheet' href='customCollectionStyles.css' type='text/css'/>
				<link rel='stylesheet' href='Basic Book.css' type='text/css'></link>
				<link rel='stylesheet' href='Device-XMatter.css' type='text/css'></link>
				<link rel='stylesheet' href='customBookStyles.css'/>"                 + extraHeadContent;

            if (createPhysicalFile)
            {
                book = CreateBookWithPhysicalFile(MakeBookHtml(body, head));
            }
            else
            {
                SetDom(body, head);
                book = CreateBook();
            }
            CreateCommonCssFiles(book);
            s_bookSelection.SelectBook(book);

            // Set up the visibility classes correctly
            book.UpdateEditableAreasOfElement(book.OurHtmlDom);

            book.CollectionSettings.XMatterPackName = "Device";                 // give us predictable xmatter with content on page 2

            return(book);
        }
Esempio n. 3
0
        private void OnBookCollectionCreated(object collection, EventArgs args)
        {
            var c = collection as BookCollection;

            if (c.ContainsDownloadedBooks)
            {
                c.FolderContentChanged += (sender, eventArgs) =>
                {
                    if (IsDisposed)
                    {
                        Debug.Fail("FolderContentChanged handler invoked from a CollectionTabView that has already been disposed. Did the collection have cleanup such as StopWatchingDirectory() occur?");
                        return;
                    }
                    if (_tabSelection.ActiveTab == WorkspaceTab.collection)
                    {
                        // We got a new or modified book in the downloaded books collection.
                        // If this (collection) tab is active, we want to select it.
                        // (If we're in the middle of editing or publishing some book, we
                        // don't want to change that.)
                        // One day we may enhance it so that we switch tabs and show it,
                        // but there are states where that would be dangerous.
                        var newBook = new BookInfo(eventArgs.Path, false);
                        var book    = _model.GetBookFromBookInfo(newBook, true);
                        _bookSelection.SelectBook(book, false);
                    }
                };
            }
        }
        private EnhancedImageServer CreateImageServer()
        {
            var bookSelection = new BookSelection();

            bookSelection.SelectBook(new Bloom.Book.Book());
            return(new EnhancedImageServer(new RuntimeImageProcessor(new BookRenamedEvent()), null, bookSelection, _fileLocator));
        }
        private void SelectBook(BookInfo bookInfo)
        {
            try
            {
                _bookSelection.SelectBook(_model.GetBookFromBookInfo(bookInfo));

                _bookContextMenu.Enabled = true;
                //Debug.WriteLine("before selecting " + SelectedBook.Title);
                _model.SelectBook(SelectedBook);
                //Debug.WriteLine("after selecting " + SelectedBook.Title);
                //didn't help: _listView.Focus();//hack we were losing clicks
                SelectedBook.ContentsChanged -= new EventHandler(OnContentsOfSelectedBookChanged);                 //in case we're already subscribed
                SelectedBook.ContentsChanged += new EventHandler(OnContentsOfSelectedBookChanged);

                deleteMenuItem.Enabled                  = _model.CanDeleteSelection;
                _updateThumbnailMenu.Visible            = _model.CanUpdateSelection;
                _updateFrontMatterToolStripMenu.Visible = _model.CanUpdateSelection;
            }
            catch (Exception error)
            {
                //skip over the dependency injection layer
                if (error.Source == "Autofac" && error.InnerException != null)
                {
                    error = error.InnerException;
                }

                Palaso.Reporting.ErrorReport.NotifyUserOfProblem(error, "Bloom cannot display that book.");
            }
        }
Esempio n. 6
0
        /// <summary>
        /// Handles the recursion through directories: if a folder looks like a Bloom book upload it; otherwise, try its children.
        /// Invisible folders like .hg are ignored.
        /// </summary>
        /// <param name="folder"></param>
        /// <param name="dlg"></param>
        /// <param name="container"></param>
        /// <param name="context"></param>
        private void UploadInternal(string folder, BulkUploadProgressDlg dlg, ApplicationContainer container, ref ProjectContext context)
        {
            if (Path.GetFileName(folder).StartsWith("."))
            {
                return;                 // secret folder, probably .hg
            }
            if (Directory.GetFiles(folder, "*.htm").Count() == 1)
            {
                // Exactly one htm file, assume this is a bloom book folder.
                dlg.Progress.WriteMessage("Starting to upload " + folder);

                // Make sure the files we want to upload are up to date.
                // Unfortunately this requires making a book object, which requires making a ProjectContext, which must be created with the
                // proper parent book collection if possible.
                var parent         = Path.GetDirectoryName(folder);
                var collectionPath = Directory.GetFiles(parent, "*.bloomCollection").FirstOrDefault();
                if (collectionPath == null && context == null)
                {
                    collectionPath = Settings.Default.MruProjects.Latest;
                }
                if (context == null || context.SettingsPath != collectionPath)
                {
                    if (context != null)
                    {
                        context.Dispose();
                    }
                    // optimise: creating a context seems to be quite expensive. Probably the only thing we need to change is
                    // the collection. If we could update that in place...despite autofac being told it has lifetime scope...we would save some time.
                    // Note however that it's not good enough to just store it in the project context. The one that is actually in
                    // the autofac object (_scope in the ProjectContext) is used by autofac to create various objects, in particular, books.
                    context = container.CreateProjectContext(collectionPath);
                }
                var server = context.BookServer;
                var book   = server.GetBookFromBookInfo(new BookInfo(folder, true));
                book.BringBookUpToDate(new NullProgress());

                // Assemble the various arguments needed to make the objects normally involved in an upload.
                // We leave some constructor arguments not actually needed for this purpose null.
                var bookSelection = new BookSelection();
                bookSelection.SelectBook(book);
                var currentEditableCollectionSelection = new CurrentEditableCollectionSelection();
                if (collectionPath != null)
                {
                    var collection = new BookCollection(collectionPath, BookCollection.CollectionType.SourceCollection,
                                                        bookSelection);
                    currentEditableCollectionSelection.SelectCollection(collection);
                }
                var publishModel = new PublishModel(bookSelection, new PdfMaker(), currentEditableCollectionSelection, null, server, _htmlThumbnailer);
                publishModel.PageLayout = book.GetLayout();
                var    view = new PublishView(publishModel, new SelectedTabChangedEvent(), new LocalizationChangedEvent(), this, null);
                string dummy;
                FullUpload(book, dlg.Progress, view, out dummy, dlg);
                return;
            }
            foreach (var sub in Directory.GetDirectories(folder))
            {
                UploadInternal(sub, dlg, container, ref context);
            }
        }
Esempio n. 7
0
        private BloomServer CreateBloomServer(BookInfo info = null)
        {
            var bookSelection      = new BookSelection();
            var collectionSettings = new CollectionSettings();

            bookSelection.SelectBook(new Bloom.Book.Book(info));
            return(new BloomServer(new RuntimeImageProcessor(new BookRenamedEvent()), bookSelection, collectionSettings, _fileLocator));
        }
Esempio n. 8
0
        public void Setup()
        {
            _bookSelection = new BookSelection();
            _bookSelection.SelectBook(new Bloom.Book.Book());
            _server = new BloomServer(_bookSelection);

            var controller = new ReadersApi(_bookSelection, null);

            controller.RegisterWithApiHandler(_server.ApiHandler);
        }
Esempio n. 9
0
        public void InitialSetup()
        {
            var bookSelection = new BookSelection();

            bookSelection.SelectBook(new Bloom.Book.Book());
            _server = new BloomServer(bookSelection);

            var controller = new FileIOApi(bookSelection);

            controller.RegisterWithApiHandler(_server.ApiHandler);
        }
Esempio n. 10
0
        private BookSelection GetDefaultBookSelection()
        {
            var bookSelection = new BookSelection();
            var mockBook      = new Mock <Bloom.Book.Book>();

            mockBook.Setup(x => x.TitleBestForUserDisplay).Returns("Fake Book Title");

            bookSelection.SelectBook(mockBook.Object);

            return(bookSelection);
        }
Esempio n. 11
0
        public void Setup()
        {
            var bookSelection = new BookSelection();

            bookSelection.SelectBook(new Bloom.Book.Book());
            _server = new EnhancedImageServer(bookSelection);

            //needed to avoid a check in the server
            _server.CurrentCollectionSettings = new CollectionSettings();
            var controller = new ReadersApi(bookSelection);

            controller.RegisterWithServer(_server);
        }
Esempio n. 12
0
        private void OnClickBook(object sender, EventArgs e)
        {
            try
            {
                BookInfo bookInfo = ((Button)sender).Tag as BookInfo;
                if (bookInfo == null)
                {
                    return;
                }

                if (SelectedBook != null && bookInfo == SelectedBook.BookInfo)
                {
                    //I couldn't get the DoubleClick event to work, so I rolled my own
                    if (Control.MouseButtons == MouseButtons.Left && DateTime.Now.Subtract(_lastClickTime).TotalMilliseconds < SystemInformation.DoubleClickTime)
                    {
                        _model.DoubleClickedBook();
                        return;
                    }
                }
                else
                {
                    _bookSelection.SelectBook(_model.GetBookFromBookInfo(bookInfo));
                }

                _lastClickTime = DateTime.Now;

                _bookContextMenu.Enabled = true;
                //Debug.WriteLine("before selecting " + SelectedBook.Title);
                _model.SelectBook(SelectedBook);
                //Debug.WriteLine("after selecting " + SelectedBook.Title);
                //didn't help: _listView.Focus();//hack we were losing clicks
                SelectedBook.ContentsChanged -= new EventHandler(OnContentsOfSelectedBookChanged);                 //in case we're already subscribed
                SelectedBook.ContentsChanged += new EventHandler(OnContentsOfSelectedBookChanged);

                deleteMenuItem.Enabled                  = _model.CanDeleteSelection;
                _updateThumbnailMenu.Visible            = _model.CanUpdateSelection;
                _updateFrontMatterToolStripMenu.Visible = _model.CanUpdateSelection;
            }
            catch (Exception error)
            {
                //skip over the dependency injection layer
                if (error.Source == "Autofac" && error.InnerException != null)
                {
                    error = error.InnerException;
                }

                Palaso.Reporting.ErrorReport.NotifyUserOfProblem(error, "Bloom cannot display that book.");
            }
        }
Esempio n. 13
0
        public void DeleteBook(Book.BookInfo bookInfo)
        {
            var didDelete = ConfirmRecycleDialog.Recycle(bookInfo.FolderPath);

            if (!didDelete)
            {
                return;
            }

            Logger.WriteEvent("After BookStorage.DeleteBook({0})", bookInfo.FolderPath);
            HandleBookDeletedFromCollection(bookInfo.FolderPath);
            if (_bookSelection != null)
            {
                _bookSelection.SelectBook(null);
            }
        }
Esempio n. 14
0
        public void DeleteBook(Book.BookInfo bookInfo)
        {
            var didDelete = ConfirmRecycleDialog.Recycle(bookInfo.FolderPath);

            if (!didDelete)
            {
                return;
            }

            Logger.WriteEvent("After BookStorage.DeleteBook({0})", bookInfo.FolderPath);
            //Debug.Assert(_bookInfos.Contains(bookInfo)); this will occur if we delete a book from the BloomLibrary section
            _bookInfos.Remove(bookInfo);

            if (CollectionChanged != null)
            {
                CollectionChanged.Invoke(this, null);
            }
            if (_bookSelection != null)
            {
                _bookSelection.SelectBook(null);
            }
        }
        public void DeleteBook(Book.BookInfo bookInfo)
        {
            var didDelete = ConfirmRecycleDialog.Recycle(bookInfo.FolderPath);

            if (!didDelete)
            {
                return;
            }

            Logger.WriteEvent("After BookStorage.DeleteBook({0})", bookInfo.FolderPath);
            //ListOfBooksIsOutOfDate();
            Debug.Assert(_bookInfos.Contains(bookInfo));
            _bookInfos.Remove(bookInfo);

            if (CollectionChanged != null)
            {
                CollectionChanged.Invoke(this, null);
            }
            if (_bookSelection != null)
            {
                _bookSelection.SelectBook(null);
            }
        }
Esempio n. 16
0
        /// <summary>
        /// Handles the recursion through directories: if a folder looks like a Bloom book upload it; otherwise, try its children.
        /// Invisible folders like .hg are ignored.
        /// </summary>
        /// <param name="folder"></param>
        /// <param name="dlg"></param>
        /// <param name="container"></param>
        /// <param name="excludeAudio"></param>
        /// <param name="alreadyUploaded"></param>
        /// <param name="context"></param>
        private void UploadInternal(string folder, BulkUploadProgressDlg dlg, ApplicationContainer container, bool excludeAudio, string[] alreadyUploaded, ref ProjectContext context)
        {
            var lastFolderPart = Path.GetFileName(folder);

            if (lastFolderPart != null && lastFolderPart.StartsWith("."))
            {
                return;                 // secret folder, probably .hg
            }
            if (Directory.GetFiles(folder, "*.htm").Length == 1)
            {
                if (alreadyUploaded.Contains(folder))
                {
                    return;                     // skip this one; we already successfully uploaded it at some point
                }
                // Exactly one htm file, assume this is a bloom book folder.
                dlg.Progress.WriteMessage("Starting to upload " + folder);

                // Make sure the files we want to upload are up to date.
                // Unfortunately this requires making a book object, which requires making a ProjectContext, which must be created with the
                // proper parent book collection if possible.
                var parent         = Path.GetDirectoryName(folder);
                var collectionPath = Directory.GetFiles(parent, "*.bloomCollection").FirstOrDefault();
                if (collectionPath == null)
                {
                    collectionPath = Settings.Default.MruProjects.Latest;
                }
                if (collectionPath == null)
                {
                    throw new ApplicationException("Collection not found in this or parent directory.");
                }
                if (context == null || context.SettingsPath != collectionPath)
                {
                    context?.Dispose();
                    // optimise: creating a context seems to be quite expensive. Probably the only thing we need to change is
                    // the collection. If we could update that in place...despite autofac being told it has lifetime scope...we would save some time.
                    // Note however that it's not good enough to just store it in the project context. The one that is actually in
                    // the autofac object (_scope in the ProjectContext) is used by autofac to create various objects, in particular, books.
                    context = container.CreateProjectContext(collectionPath);
                    Program.SetProjectContext(context);
                }
                var server   = context.BookServer;
                var bookInfo = new BookInfo(folder, true);
                bookInfo.BookshelfList = GetBookshelfName(folder);
                var book = server.GetBookFromBookInfo(bookInfo);
                book.BringBookUpToDate(new NullProgress());

                // Assemble the various arguments needed to make the objects normally involved in an upload.
                // We leave some constructor arguments not actually needed for this purpose null.
                var bookSelection = new BookSelection();
                bookSelection.SelectBook(book);
                var currentEditableCollectionSelection = new CurrentEditableCollectionSelection();

                var collection = new BookCollection(collectionPath, BookCollection.CollectionType.SourceCollection, bookSelection);
                currentEditableCollectionSelection.SelectCollection(collection);

                var publishModel = new PublishModel(bookSelection, new PdfMaker(), currentEditableCollectionSelection, context.Settings, server, _thumbnailer, null);
                publishModel.PageLayout = book.GetLayout();
                var    view           = new PublishView(publishModel, new SelectedTabChangedEvent(), new LocalizationChangedEvent(), this, null, null, null);
                var    blPublishModel = new BloomLibraryPublishModel(this, book);
                string dummy;

                // Normally we let the user choose which languages to upload. Here, just the ones that have complete information.
                var langDict          = book.AllLanguages;
                var languagesToUpload = langDict.Keys.Where(l => langDict[l]).ToArray();
                if (blPublishModel.MetadataIsReadyToPublish && (languagesToUpload.Any() || blPublishModel.OkToUploadWithNoLanguages))
                {
                    if (blPublishModel.BookIsAlreadyOnServer)
                    {
                        var msg = "Apparently this book is already on the server. Overwriting...";
                        ReportToLogBoxAndLogger(dlg.Progress, folder, msg);
                    }
                    FullUpload(book, dlg.Progress, view, languagesToUpload, out dummy, excludeAudio);
                    AppendBookToUploadLogFile(folder);
                }
                else
                {
                    // report to the user why we are not uploading their book
                    ReportToLogBoxAndLogger(dlg.Progress, folder, blPublishModel.GetReasonForNotUploadingBook());
                }
                return;
            }
            foreach (var sub in Directory.GetDirectories(folder))
            {
                UploadInternal(sub, dlg, container, excludeAudio, alreadyUploaded, ref context);
            }
        }
Esempio n. 17
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");
            }
        }
Esempio n. 18
0
 public void SelectBook(Book.Book book)
 {
     _bookSelection.SelectBook(book);
 }
Esempio n. 19
0
        public void GetTextOfContentPagesAsJson_OmitsUnwantedPages()
        {
            var htmlLeveledReader = $@"<html><head><meta charset='UTF-8'></meta></head>
<body class='leveled-reader' data-l1='en' data-l2='fr' data-l3='es'>
    <!-- ignore page with bloom-frontMatter class -->
    <div class='bloom-page bloom-frontMatter' id='b8408838-e9ed-4d76-bb8a-24ad0708b329' lang='fr'>
        <div class='marginBox'>
            <div class='bloom-translationGroup bookTitle' data-default-languages='V,N1'>
                <div class='bloom-editable bloom-content1 bloom-visibility-code-on' lang='en'>
                    <p>Level Two</p>
                </div>
            </div>
            <div class='bloom-imageContainer' title='Name: aor_IN16.png'>
                <img src='aor_IN16.png'></img>
                <div class='bloom-translationGroup bloom-imageDescription'>
                    <div class='bloom-editable bloom-content1 bloom-visibility-code-on' lang='en'>cat</div>
                </div>
            </div>
        </div>
    </div>
    <!-- ignore page with bloom-nonprinting class -->
    <div class='bloom-page bloom-noreader bloom-nonprinting screen-only' id='33b7e4c5-6cd1-4611-a50f-85837143cbf6' lang=''>
        <div class='pageLabel' data-i18n='TemplateBooks.PageLabel.Translation Instructions' lang='en'>Translation Instructions</div>
        <div class='marginBox'>
            <div class='split-pane-component-inner'>
                <div class='bloom-translationGroup' data-default-languages='*'>
                    <div class='bloom-editable bloom-content1 bloom-visibility-code-on' data-book='' lang='en' contenteditable='true'>
                        <p>Instructions in vernacular language ...</p>
                    </div>
                </div>
            </div>
        </div>
    </div>
    <!-- skip over page with no bloom-content1 content apart from image descriptions -->
	<div class='bloom-page numberedPage' id='a2ecb8be-5c7f-440d-9ef5-d503476211cd' data-page-number='1' lang=''>
        <div class='pageLabel' data-i18n='TemplateBooks.PageLabel.Just a Picture' lang='en'>Just a Picture</div>
        <div class='marginBox'>
            <div class='split-pane-component-inner'>
                <div class='bloom-imageContainer' title='Name: aor_acc034m.png'>
                    <img src='aor_acc034m.png' alt='cat staring at something outside the picture'></img>
                    <div class='bloom-translationGroup bloom-imageDescription bloom-trailingElement'>
                        <div class='bloom-editable bloom-content1 bloom-visibility-code-on' lang='en'>
                            <p>cat staring at something outside the picture</p>
                        </div>
                    </div>
                </div>
            </div>
        </div>
    </div>
    <!-- include content page with bloom-content1 content, ignoring image description -->
    <div class='bloom-page numberedPage' id='85a320a4-b73f-4149-87a1-9a1297ef04b0' data-page-number='2' lang=''>
        <div class='pageLabel' data-i18n='TemplateBooks.PageLabel.Basic Text &amp; Picture' lang='en'>Basic Text &amp; Picture</div>
        <div class='marginBox'>
            <div class='split-pane horizontal-percent'>
                <div class='split-pane-component position-top'>
                    <div class='split-pane-component-inner'>
                        <div class='bloom-imageContainer bloom-leadingElement' title='Name: aor_Cat3.png'>
                            <img src='aor_Cat3.png' alt='cat lying down and staring at you through slitted eyes'></img>
                            <div class='bloom-translationGroup bloom-imageDescription'>
                                <div class='bloom-editable bloom-content1 bloom-visibility-code-on' lang='en'>
                                    <p>cat lying down and staring at you through slitted eyes</p>
                                </div>
                            </div>
                        </div>
                    </div>
                </div>
                <div class='split-pane-divider horizontal-divider'></div>
                <div class='split-pane-component position-bottom'>
                    <div class='split-pane-component-inner'>
                        <div class='bloom-translationGroup' data-default-languages='auto'>
                            <div class='bloom-editable bloom-content1 bloom-visibility-code-on' id='i57437cd1-c55c-499e-b0c3-d7195fba5f11' lang='en'>
                                <p>A cat stares at you.</p>
                            </div>
                        </div>
                    </div>
                </div>
            </div>
        </div>
    </div>
    <!-- include content page with empty bloom-content1 content, ignoring image description -->
    <div class='bloom-page numberedPage' id='d46e4259-2a99-4197-b21d-bf97a992b7d0' data-page-number='3' lang=''>
        <div class='pageLabel' data-i18n='TemplateBooks.PageLabel.Basic Text &amp; Picture' lang='en'>Basic Text &amp; Picture</div>
        <div class='marginBox'>
            <div class='split-pane horizontal-percent'>
                <div class='split-pane-component position-top'>
                    <div class='split-pane-component-inner'>
                        <div class='bloom-imageContainer' title='Name: aor_ACC029M.png'>
                            <img src='aor_ACC029M.png' alt='cat sleeping in a box that is just large enough'></img>
                            <div class='bloom-translationGroup bloom-imageDescription'>
                                <div class='bloom-editable bloom-content1 bloom-visibility-code-on' lang='en'>
                                    <p>cat sleeping in a box that is just large enough</p>
                                </div>
                            </div>
                        </div>
                    </div>
                </div>
                <div class='split-pane-divider horizontal-divider'></div>
                <div class='split-pane-component position-bottom'>
                    <div class='split-pane-component-inner'>
                        <div class='bloom-translationGroup' data-default-languages='auto'>
                            <div class='bloom-editable bloom-content1 bloom-visibility-code-on' lang='en'>
                                <p></p>
                            </div>
                        </div>
                    </div>
                </div>
            </div>
        </div>
    </div>
    <!-- include content page with bloom-content1 content and no image -->
    <div class='bloom-page numberedPage' id='5a424678-ec70-4c97-a547-015ff38dfd11' data-page-number='4' lang=''>
        <div class='marginBox'>
            <div class='bloom-translationGroup bloom-trailingElement' data-default-languages='auto'>
                <div class='bloom-editable normal-style bloom-content1 bloom-visibility-code-on' lang='en'>
                    <p>See the two kittens.</p>
                </div>
            </div>
        </div>
    </div>
	<!-- include page with non-vernacular text if it also has vernacular text -->
    <div class='bloom-page numberedPage' id='ebbd7f47-05fa-4e6d-a7a1-cb526bb5efb8' data-page-number='5' lang=''>
        <div class='pageLabel' data-i18n='TemplateBooks.PageLabel.Custom' lang='en'>Custom</div>
        <div class='marginBox'>
            <div class='split-pane horizontal-percent'>
                <div class='split-pane-component position-top'>
                    <div class='split-pane-component-inner' min-width='60px 150px 250px' min-height='60px 150px'>
                        <div class='bloom-translationGroup bloom-trailingElement' data-default-languages='N1'>
                            <div class='bloom-editable bloom-contentNational1 bloom-visibility-code-on' lang='fr'>
                                <p>national language text</p>
                            </div>
                        </div>
                    </div>
                </div>
                <div class='split-pane-divider horizontal-divider' title='33.2%'></div>
                <div class='split-pane-component position-bottom'>
                    <div class='split-pane-component position-top'>
                        <div class='split-pane-component-inner' min-width='60px 150px 250px' min-height='60px 150px'>
                            <div class='bloom-translationGroup bloom-trailingElement' data-default-languages='V'>
                                <div class='bloom-editable bloom-content1 bloom-visibility-code-on' lang='en'>
                                    <p>local language text</p>
                                </div>
                            </div>
                        </div>
                    </div>
                </div>
            </div>
        </div>
    </div>
	<!-- ignore page with bloom-ignoreForReaderStats class -->
    <div class='bloom-page numberedPage bloom-ignoreForReaderStats' id='ebad7a47-05fa-4e6d-a7a1-cb526bb5efb8' data-page-number='6' lang=''>
        <div class='pageLabel' data-i18n='TemplateBooks.PageLabel.Custom' lang='en'>Custom</div>
        <div class='marginBox'>
            <div class='split-pane horizontal-percent'>
                <div class='split-pane-component position-top'>
                    <div class='split-pane-component-inner' min-width='60px 150px 250px' min-height='60px 150px'>
                        <div class='bloom-translationGroup bloom-trailingElement' data-default-languages='N1'>
                            <div class='bloom-editable normal-style bloom-contentNational1 bloom-visibility-code-on' lang='fr'>
                                <p>This is in the national language.</p>
                            </div>
                        </div>
                    </div>
                </div>
                <div class='split-pane-divider horizontal-divider' title='33.2%'></div>
                <div class='split-pane-component position-bottom'>
                    <div class='split-pane-component position-top'>
                        <div class='split-pane-component-inner' min-width='60px 150px 250px' min-height='60px 150px'>
                            <div class='bloom-translationGroup bloom-trailingElement' data-default-languages='V'>
                                <div class='bloom-editable normal-style bloom-content1 bloom-visibility-code-on' lang='en'>
                                    <p>This is in the local language.</p>
                                </div>
                            </div>
                        </div>
                    </div>
                </div>
            </div>
        </div>
    </div>
    <!-- ignore page with bloom-backMatter class -->
    <div class='bloom-page titlePage bloom-backMatter' id='0f8d4d80-0519-42b6-bcde-6362b99ed1ff' lang='fr'>
        <div class='pageLabel' lang='en' data-i18n='TemplateBooks.PageLabel.Title Page'>Title Page</div>
        <div class='marginBox'>
            <div class='bloom-translationGroup' data-default-languages='V,N1' id='titlePageTitleBlock'>
                <div class='bloom-editable bloom-content1 bloom-visibility-code-on' lang='en'>
                    <p>Level Two</p>
                </div>
            </div>
        </div>
    </div>
</body></html>
";
            var doc = new XmlDocument();

            doc.LoadXml(htmlLeveledReader);
            var dom     = new HtmlDom(doc);
            var storage = CreateMockStorage(dom, "GetPagesForReader");
            var book    = new Bloom.Book.Book(storage.Object.BookInfo, storage.Object);

            _bookSelection.SelectBook(book);

            var result = ApiTest.GetString(_server, "readers/io/textOfContentPages");

            Assert.That(result, Is.EqualTo("{\"85a320a4-b73f-4149-87a1-9a1297ef04b0\":\"<p>A cat stares at you.</p>\",\"d46e4259-2a99-4197-b21d-bf97a992b7d0\":\"<p />\",\"5a424678-ec70-4c97-a547-015ff38dfd11\":\"<p>See the two kittens.</p>\",\"ebbd7f47-05fa-4e6d-a7a1-cb526bb5efb8\":\"<p>local language text</p>\"}"));
        }
Esempio n. 20
0
 public override void Setup()
 {
     base.Setup();
     _bookServer = CreateBookServer();
     s_bookSelection.SelectBook(CreateBook());
 }
Esempio n. 21
0
        private void UploadBookInternal(IProgress progress, ApplicationContainer container, BookUploadParameters uploadParams,
                                        ref ProjectContext context)
        {
            progress.WriteMessageWithColor("Cyan", "Starting to upload " + uploadParams.Folder);
            // Make sure the files we want to upload are up to date.
            // Unfortunately this requires making a book object, which requires making a ProjectContext, which must be created with the
            // proper parent book collection if possible.
            var parent         = Path.GetDirectoryName(uploadParams.Folder);
            var collectionPath = Directory.GetFiles(parent, "*.bloomCollection").FirstOrDefault();

            if (collectionPath == null || !RobustFile.Exists(collectionPath))
            {
                progress.WriteError("Skipping book because no collection file was found in its parent directory.");
                return;
            }
            _collectionFoldersUploaded.Add(collectionPath);

            // Compute the book hash file and compare it to the existing one for bulk upload.
            var currentHashes = BookUpload.HashBookFolder(uploadParams.Folder);

            progress.WriteMessage(currentHashes);
            var pathToLocalHashInfoFromLastUpload = Path.Combine(uploadParams.Folder, HashInfoFromLastUpload);

            if (!uploadParams.ForceUpload)
            {
                var canSkip = false;
                if (Program.RunningUnitTests)
                {
                    canSkip = _singleBookUploader.CheckAgainstLocalHashfile(currentHashes, pathToLocalHashInfoFromLastUpload);
                }
                else
                {
                    canSkip = _singleBookUploader.CheckAgainstHashFileOnS3(currentHashes, uploadParams.Folder, progress);
                    RobustFile.WriteAllText(pathToLocalHashInfoFromLastUpload, currentHashes);                             // ensure local copy is saved
                }
                if (canSkip)
                {
                    // local copy of hashes file is identical or has been saved
                    progress.WriteMessageWithColor("green", $"Skipping '{Path.GetFileName(uploadParams.Folder)}' because it has not changed since being uploaded.");
                    ++_booksSkipped;
                    return;                             // skip this one; we already uploaded it earlier.
                }
            }
            // save local copy of hashes file: it will be uploaded with the other book files
            RobustFile.WriteAllText(pathToLocalHashInfoFromLastUpload, currentHashes);

            if (context == null || context.SettingsPath != collectionPath)
            {
                context?.Dispose();
                // optimise: creating a context seems to be quite expensive. Probably the only thing we need to change is
                // the collection. If we could update that in place...despite autofac being told it has lifetime scope...we would save some time.
                // Note however that it's not good enough to just store it in the project context. The one that is actually in
                // the autofac object (_scope in the ProjectContext) is used by autofac to create various objects, in particular, books.
                context = container.CreateProjectContext(collectionPath);
                Program.SetProjectContext(context);
            }
            var server   = context.BookServer;
            var bookInfo = new BookInfo(uploadParams.Folder, true);
            var book     = server.GetBookFromBookInfo(bookInfo);

            book.BringBookUpToDate(new NullProgress());
            bookInfo.Bookshelf = book.CollectionSettings.DefaultBookshelf;
            var bookshelfName = String.IsNullOrWhiteSpace(book.CollectionSettings.DefaultBookshelf) ? "(none)" : book.CollectionSettings.DefaultBookshelf;

            progress.WriteMessage($"Bookshelf is '{bookshelfName}'");

            // Assemble the various arguments needed to make the objects normally involved in an upload.
            // We leave some constructor arguments not actually needed for this purpose null.
            var bookSelection = new BookSelection();

            bookSelection.SelectBook(book);
            var currentEditableCollectionSelection = new CurrentEditableCollectionSelection();

            var collection = new BookCollection(collectionPath, BookCollection.CollectionType.SourceCollection, bookSelection);

            currentEditableCollectionSelection.SelectCollection(collection);

            var publishModel = new PublishModel(bookSelection, new PdfMaker(), currentEditableCollectionSelection, context.Settings, server, _thumbnailer);

            publishModel.PageLayout = book.GetLayout();
            var    view           = new PublishView(publishModel, new SelectedTabChangedEvent(), new LocalizationChangedEvent(), _singleBookUploader, null, null, null, null);
            var    blPublishModel = new BloomLibraryPublishModel(_singleBookUploader, book, publishModel);
            string dummy;

            // Normally we let the user choose which languages to upload. Here, just the ones that have complete information.
            var langDict          = book.AllPublishableLanguages();
            var languagesToUpload = langDict.Keys.Where(l => langDict[l]).ToList();

            if (!string.IsNullOrEmpty(book.CollectionSettings.SignLanguageIso639Code) && BookUpload.GetVideoFilesToInclude(book).Any())
            {
                languagesToUpload.Insert(0, book.CollectionSettings.SignLanguageIso639Code);
            }
            if (blPublishModel.MetadataIsReadyToPublish && (languagesToUpload.Any() || blPublishModel.OkToUploadWithNoLanguages))
            {
                if (blPublishModel.BookIsAlreadyOnServer)
                {
                    var msg = $"Overwriting the copy of {uploadParams.Folder} on the server...";
                    progress.WriteWarning(msg);
                }
                using (var tempFolder = new TemporaryFolder(Path.Combine("BloomUpload", Path.GetFileName(book.FolderPath))))
                {
                    BookUpload.PrepareBookForUpload(ref book, server, tempFolder.FolderPath, progress);
                    uploadParams.LanguagesToUpload = languagesToUpload.ToArray();
                    _singleBookUploader.FullUpload(book, progress, view, uploadParams, out dummy);
                }

                progress.WriteMessageWithColor("Green", "{0} has been uploaded", uploadParams.Folder);
                if (blPublishModel.BookIsAlreadyOnServer)
                {
                    ++_booksUpdated;
                }
                else
                {
                    ++_newBooksUploaded;
                }
            }
            else
            {
                // report to the user why we are not uploading their book
                var reason = blPublishModel.GetReasonForNotUploadingBook();
                progress.WriteError("{0} was not uploaded.  {1}", uploadParams.Folder, reason);
                ++_booksWithErrors;
            }
        }