Inheritance: IDisposable
Example #1
1
        /// <summary>
        /// Warning, if the book already exists in the location, this is going to delete it an over-write it. So it's up to the caller to check the sanity of that.
        /// </summary>
        /// <param name="storageKeyOfBookFolder"></param>
        public string DownloadBook(string bucketName, string storageKeyOfBookFolder, string pathToDestinationParentDirectory,
			IProgressDialog downloadProgress = null)
        {
            //review: should we instead save to a newly created folder so that we don't have to worry about the
            //other folder existing already? Todo: add a test for that first.

            // We need to download individual files to avoid downloading unwanted files (PDFs and thumbs.db to
            // be specific).  See https://silbloom.myjetbrains.com/youtrack/issue/BL-2312.  So we need the list
            // of items, not just the count.
            var matching = GetMatchingItems(bucketName, storageKeyOfBookFolder);
            var totalItems = CountDesiredFiles(matching);
            if(totalItems == 0)
                throw new DirectoryNotFoundException("The book we tried to download is no longer in the BloomLibrary");

            Debug.Assert(matching.S3Objects[0].Key.StartsWith(storageKeyOfBookFolder + "/"));

            // Get the top-level directory name of the book from the first object key.
            var bookFolderName = matching.S3Objects[0].Key.Substring(storageKeyOfBookFolder.Length + 1);
            while(bookFolderName.Contains("/"))
                bookFolderName = Path.GetDirectoryName(bookFolderName);

            // Amazon.S3 appears to truncate titles at 50 characters when building directory and filenames.  This means
            // that relative paths can be as long as 117 characters (2 * 50 + 2 for slashes + 15 for .BloomBookOrder).
            // So our temporary folder must be no more than 140 characters (allow some margin) since paths can be a
            // maximum of 260 characters in Windows.  (More margin than that may be needed because there's no guarantee
            // that image filenames are no longer than 65 characters.)  See https://jira.sil.org/browse/BL-1160.
            using(var tempDestination = new TemporaryFolder("BDS_" + Guid.NewGuid()))
            {
                var tempDirectory = Path.Combine(tempDestination.FolderPath, bookFolderName);
                if(downloadProgress != null)
                    downloadProgress.Invoke((Action) (() => { downloadProgress.ProgressRangeMaximum = totalItems; }));
                int booksDownloaded = 0;
                using(var transferUtility = new TransferUtility(_amazonS3))
                {
                    for(int i = 0; i < matching.S3Objects.Count; ++i)
                    {
                        var objKey = matching.S3Objects[i].Key;
                        if(AvoidThisFile(objKey))
                            continue;
                        // Removing the book's prefix from the object key, then using the remainder of the key
                        // in the filepath allows for nested subdirectories.
                        var filepath = objKey.Substring(storageKeyOfBookFolder.Length + 1);
                        // Download this file then bump progress.
                        var req = new TransferUtilityDownloadRequest()
                        {
                            BucketName = bucketName,
                            Key = objKey,
                            FilePath = Path.Combine(tempDestination.FolderPath, filepath)
                        };
                        transferUtility.Download(req);
                        ++booksDownloaded;
                        if(downloadProgress != null)
                            downloadProgress.Invoke((Action) (() => { downloadProgress.Progress = booksDownloaded; }));
                    }
                    var destinationPath = Path.Combine(pathToDestinationParentDirectory, bookFolderName);

                    //clear out anything existing on our target
                    var didDelete = false;
                    if(Directory.Exists(destinationPath))
                    {
                        try
                        {
                            SIL.IO.RobustIO.DeleteDirectory(destinationPath, true);
                            didDelete = true;
                        }
                        catch(IOException)
                        {
                            // can't delete it...see if we can copy into it.
                        }
                    }

                    //if we're on the same volume, we can just move it. Else copy it.
                    // It's important that books appear as nearly complete as possible, because a file watcher will very soon add the new
                    // book to the list of downloaded books the user can make new ones from, once it appears in the target directory.
                    bool done = false;
                    if(didDelete && PathUtilities.PathsAreOnSameVolume(pathToDestinationParentDirectory, tempDirectory))
                    {
                        try
                        {
                            SIL.IO.RobustIO.MoveDirectory(tempDirectory, destinationPath);
                            done = true;
                        }
                        catch(IOException)
                        {
                            // If moving didn't work we'll just try copying
                        }
                        catch(UnauthorizedAccessException)
                        {
                        }
                    }
                    if(!done)
                        done = CopyDirectory(tempDirectory, destinationPath);
                    if(!done)
                    {
                        var msg = LocalizationManager.GetString("Download.CopyFailed",
                            "Bloom downloaded the book but had problems making it available in Bloom. Please restart your computer and try again. If you get this message again, please click the 'Details' button and report the problem to the Bloom developers");
                        // The exception doesn't add much useful information but it triggers a version of the dialog with a Details button
                        // that leads to the yellow box and an easy way to send the report.
                        ErrorReport.NotifyUserOfProblem(new ApplicationException("File Copy problem"), msg);
                    }
                    return destinationPath;
                }
            }
        }
        public void SetupFixture()
        {
            // Basic setup
            _workFolder = new TemporaryFolder("unittest2");
            var workFolderPath = _workFolder.FolderPath;
            Assert.AreEqual(0, Directory.GetDirectories(workFolderPath).Count(), "Some stuff was left over from a previous test");

            _client = new BloomS3Client(BloomS3Client.UnitTestBucketName);

            // Now do standard upload/download. We save time by making this whole class do one upload/download sequence
            // on the assumption that things that should be uploaded were if they make it through the download process too.
            // Individual tests just compare what was uploaded with what came back through the download.
            // If we want to upload and download to separate (collection) folders, we need another layer for the actual book

            _storageKeyOfBookFolder = Guid.NewGuid().ToString();

            // First create folder to upload from
            var unittestGuid = Guid.NewGuid();
            var srcFolder = new TemporaryFolder(_workFolder, "unittest-src-" + unittestGuid);
            _srcCollectionPath = srcFolder.FolderPath;

            // Then create standard book
            var book = MakeBookIncludingThumbs(srcFolder);

            // Upload standard book
            UploadBook(book);

            // Create folder to download to
            var destFolder = new TemporaryFolder(_workFolder, "unittest-dest-" + unittestGuid);
            _destCollectionPath = destFolder.FolderPath;

            // Download standard book
            DownloadBook();
        }
 public LowResImageCache(BookRenamedEvent bookRenamedEvent)
 {
     _bookRenamedEvent = bookRenamedEvent;
     _paths = new Dictionary<string, string>();
     _cacheFolder = new TemporaryFolder("Bloom");
     _bookRenamedEvent.Subscribe(OnBookRenamed);
 }
 public void UploadBook_EmptyFolder_DoesntThrow()
 {
     string storageKeyOfBookFolder = Guid.NewGuid().ToString();
     using (var f = new TemporaryFolder(_workFolder,"emptyFolder"))
     {
         _client.UploadBook(storageKeyOfBookFolder, f.FolderPath);
     }
 }
        public void Setup()
        {
            _workFolder = new TemporaryFolder("unittest");
            var workFolderPath = _workFolder.FolderPath;
            Assert.AreEqual(0, Directory.GetDirectories(workFolderPath).Count(), "Some stuff was left over from a previous test");
            Assert.AreEqual(0, Directory.GetFiles(workFolderPath).Count(), "Some stuff was left over from a previous test");

            _client = new BloomS3Client(BloomS3Client.UnitTestBucketName);
        }
 public void UploadBook_EmptyFolder_DoesntThrow()
 {
     var storageKeyOfBookFolder = Guid.NewGuid().ToString();
     using (var f = new TemporaryFolder(_workFolder, "emptyFolder"))
     {
         _client.UploadBook(storageKeyOfBookFolder, f.FolderPath, new NullProgress());
     }
     // This doesn't actually create an entry, since the folder is empty,
     // so no need to delete it after our test
 }
Example #7
0
 public TempFile(TemporaryFolder parentFolder)
 {
     if (parentFolder != null)
     {
         _path = parentFolder.GetPathForNewTempFile(true);
     }
     else
     {
         _path = System.IO.Path.GetTempFileName();
     }
 }
        public void UpdateAllHtmlDataAttributesForAllImgElements_HasBothImgAndBackgroundImageElements_UpdatesBoth()
        {
            var dom = new HtmlDom("<html><body><img src='test.png'/><div style='color:orange; background-image=url(\"test.png\")'/></body></html>");

            using (var folder = new TemporaryFolder("bloom pictures test source"))
            {
                MakeSamplePngImageWithMetadata(folder.Combine("test.png"));
                ImageUpdater.UpdateAllHtmlDataAttributesForAllImgElements(folder.FolderPath, dom, new NullProgress());
            }

            AssertThatXmlIn.Dom(dom.RawDom).HasSpecifiedNumberOfMatchesForXpath("//*[@data-copyright='Copyright 1999 by me']", 2);
            AssertThatXmlIn.Dom(dom.RawDom).HasSpecifiedNumberOfMatchesForXpath("//*[@data-creator='joe']", 2);
            AssertThatXmlIn.Dom(dom.RawDom).HasSpecifiedNumberOfMatchesForXpath("//*[@data-license='cc-by-nd']", 2);
        }
 public void Setup()
 {
     _workFolder = new TemporaryFolder("unittest");
     _workFolderPath = _workFolder.FolderPath;
     Assert.AreEqual(0,Directory.GetDirectories(_workFolderPath).Count(),"Some stuff was left over from a previous test");
     Assert.AreEqual(0, Directory.GetFiles(_workFolderPath).Count(),"Some stuff was left over from a previous test");
     // Todo: Make sure the S3 unit test bucket is empty.
     // Todo: Make sure the parse.com unit test book table is empty
     _parseClient = new BloomParseClient();
     // These substitute keys target the "silbloomlibraryunittests" application so testing won't interfere with the real one.
     _parseClient.ApiKey = "HuRkXoF5Z3hv8f3qHE4YAIrDjwNk4VID9gFxda1U";
     _parseClient.ApplicationKey = "r1H3zle1Iopm1IB30S4qEtycvM4xYjZ85kRChjkM";
     _transfer = new BookTransfer(_parseClient, new BloomS3Client(BloomS3Client.UnitTestBucketName));
 }
        private void TestUpdateImgMetadataAttributesToMatchImage(string contents)
        {
            var dom = new XmlDocument();
            dom.LoadXml(contents);

            using (var folder = new TemporaryFolder("bloom pictures test source"))
            {
                MakeSamplePngImageWithMetadata(folder.Combine("test.png"));
                ImageUpdater.UpdateImgMetdataAttributesToMatchImage(folder.FolderPath,
                    dom.SelectSingleNode("//*[@id='two']") as XmlElement, new NullProgress());
            }

            AssertThatXmlIn.Dom(dom).HasSpecifiedNumberOfMatchesForXpath("//*[@data-copyright='Copyright 1999 by me']", 1);
            AssertThatXmlIn.Dom(dom).HasSpecifiedNumberOfMatchesForXpath("//*[@data-creator='joe']", 1);
            AssertThatXmlIn.Dom(dom).HasSpecifiedNumberOfMatchesForXpath("//*[@data-license='cc-by-nd']", 1);
        }
        public void UploadSmokeTest()
        {
            using(var folder = new TemporaryFolder("Upload Smoke Test"))
            {
                File.WriteAllText(folder.Combine("hello there.txt"), "hello there");
                using(var bookZip = TempFile.WithFilenameInTempFolder("Upload Smoketest.zip"))
                {
                    var zip = new BloomZipFile(bookZip.Path);
                    zip.AddDirectory(folder.FolderPath);
                    zip.Save();

                    var progress = new StringBuilderProgress();
                    ProblemBookUploader.UploadBook(BloomS3Client.UnitTestBucketName, bookZip.Path,progress);
                    Assert.IsTrue(progress.Text.Contains("Success"), progress.Text);
                }
            }
        }
 private string MakeBook()
 {
     var f = new TemporaryFolder(_workFolder, "unittest");
     File.WriteAllText(Path.Combine(f.FolderPath, "one.htm"), "test");
     File.WriteAllText(Path.Combine(f.FolderPath, "one.css"), "test");
     return f.FolderPath;
 }
 /// <summary>
 /// Make an ePUB out of the specified book. Sets up several instance variables with commonly useful parts of the results.
 /// </summary>
 /// <param name="mainFileName"></param>
 /// <param name="folderName"></param>
 /// <param name="book"></param>
 /// <returns></returns>
 private ZipFile MakeEpub(string mainFileName, string folderName, Bloom.Book.Book book)
 {
     var epubFolder = new TemporaryFolder(folderName);
     var epubName = mainFileName + ".epub";
     var epubPath = Path.Combine(epubFolder.FolderPath, epubName);
     using (var maker = CreateEpubMaker(book))
     {
         maker.Unpaginated = true; // Currently we always make unpaginated epubs.
         maker.SaveEpub(epubPath);
     }
     Assert.That(File.Exists(epubPath));
     _epub= new ZipFile(epubPath);
     _manifestFile = GetManifestFile(_epub);
     _manifestContent = StripXmlHeader(GetZipContent(_epub, _manifestFile));
     _manifestDoc = XDocument.Parse(_manifestContent);
     GetPageOneData();
     return _epub;
 }
        public void Setup()
        {
            _testFolder = new TemporaryFolder("hydration test");
            _bookFolder = new TemporaryFolder(_testFolder,"original name");
            _originalHtmlPath = _bookFolder.Combine("original name.html");
            File.WriteAllText(_originalHtmlPath,
                @"<html><head></head><body>
                    <div id='bloomDataDiv'>
                        <div data-book='bookTitle' lang='en'>
                                mudmen
                        </div>
                        <div data-book='topic' lang='en'>
                            Story Book
                        </div>

                        <div data-book='copyright' lang='*'>
                            Copyright © 2016, Joe Author
                        </div>

                        <div data-book='licenseUrl' lang='*'>
                            http://creativecommons.org/licenses/by/4.0/
                        </div>

                        <div data-book='originalAcknowledgments' lang='en'>
                            Some Acknowledgments
                        </div>

                        <div data-book-attributes='frontCover' data-backgroundaudio='audio/SoundTrack1.mp3' data-backgroundaudiovolume='0.17'></div>
                    </div>
                    <div id ='firstPage' class='bloom-page A5Landscape'>1st page</div>
                </body></html>");

            //NOTE: At the moment, if the bookTitle of the selected vernacular language does not match
            //the name of the file and folder, the hydration process will rename the book's folder and file,
            //just like opening it in Bloom does. At the moment, we set the name of the folder/file to be
            //the same as the title in the requested vernacular, so it isn't an issue. But further tests
            //could make it an issue. For now, these are the same:
            //_eventualHtmlPath = _testFolder.Combine("mudmen", "mudmen.htm");

            //decided that allowing a new name is just going to confuse the programs using this CLI, so
            //let's expect the program to NOT change the names for now.
            _eventualHtmlPath = _testFolder.Combine("original name", "original name.html");
        }
Example #15
0
 public void InsertPageAfter_TemplateRefsPicture_PictureCopied()
 {
     var book = CreateBook();
     var existingPage = book.GetPages().First();
     Mock<IPage> templatePage = CreateTemplatePage("<div class='bloom-page'  data-page='extra' >hello<img src='read.png'/></div>");
     using (var tempFolder = new TemporaryFolder("InsertPageAfter_TemplateRefsPicture_PictureCopied"))
     {
         File.WriteAllText(Path.Combine(tempFolder.FolderPath, "read.png"),"This is a test");
         var mockTemplateBook = new Moq.Mock<Bloom.Book.Book>();
         mockTemplateBook.Setup(x => x.FolderPath).Returns(tempFolder.FolderPath);
         mockTemplateBook.Setup(x => x.OurHtmlDom.GetTemplateStyleSheets()).Returns(new string[] {});
         templatePage.Setup(x => x.Book).Returns(mockTemplateBook.Object);
         book.InsertPageAfter(existingPage, templatePage.Object);
     }
     Assert.That(File.Exists(Path.Combine(book.FolderPath, "read.png")));
 }
Example #16
0
        public void InsertPageAfter_PageRequiresStylesheetWeDontHave_StylesheetLinkAdded()
        {
            using(var bookFolder = new TemporaryFolder("InsertPageAfter_PageRequiresStylesheetWeDontHave_StylesheetLinkAdded"))
            {
                var templatePage = MakeTemplatePageThatHasABookWithStylesheets(bookFolder, new[] {"foo.css"});
                SetDom("<div class='bloom-page' id='1'></div>", ""); //but no special stylesheets in the target book
                var targetBook = CreateBook();
                targetBook.InsertPageAfter(targetBook.GetPages().First(), templatePage);

                Assert.NotNull(targetBook.OurHtmlDom.GetTemplateStyleSheets().First(name => name == "foo.css"));
            }
        }
Example #17
0
 public static TemporaryFolder TrackExisting(string path)
 {
     Debug.Assert(Directory.Exists(path));
     TemporaryFolder f = new TemporaryFolder();
     f._path = path;
     return f;
 }
Example #18
0
        public TempLiftFile(string fileName, TemporaryFolder parentFolder, string xmlOfEntries, string claimedLiftVersion)
            : base(false)
        {
            _path = parentFolder.Combine(fileName);

            string liftContents = string.Format("<?xml version='1.0' encoding='utf-8'?><lift version='{0}'>{1}</lift>", claimedLiftVersion, xmlOfEntries);
            RobustFile.WriteAllText(_path, liftContents);
        }
 private string MakeBookIncludingThumbs(TemporaryFolder srcFolder)
 {
     var bookFolder = new TemporaryFolder(srcFolder, BookName).FolderPath;
     File.WriteAllText(Path.Combine(bookFolder, "one.htm"), @"test");
     File.WriteAllText(Path.Combine(bookFolder, "one.css"), @"test");
     File.WriteAllText(Path.Combine(bookFolder, "preview.pdf"), @"test pdf file");
     File.WriteAllText(Path.Combine(bookFolder, "extra.pdf"), @"unwanted pdf file");
     File.WriteAllText(Path.Combine(bookFolder, "thumbs.db"), @"test thumbs.db file");
     File.WriteAllText(Path.Combine(bookFolder, "book.userPrefs"), @"test book.userPrefs file");
     File.WriteAllText(Path.Combine(bookFolder, "my.bloompack"), @"test bloompack file");
     return bookFolder;
 }
Example #20
0
 public static TempFile CreateXmlFileWithContents(string fileName, TemporaryFolder folder, string xmlBody)
 {
     string path = folder.Combine(fileName);
     using (XmlWriter x = XmlWriter.Create(path))
     {
         x.WriteStartDocument();
         x.WriteRaw(xmlBody);
     }
     return new TempFile(path, true);
 }
Example #21
0
        public static void SetUpLocalization(ApplicationContainer applicationContainerSource = null)
        {
            var applicationContainer = _applicationContainer;
            if (applicationContainerSource != null)
                applicationContainer = applicationContainerSource;
            var installedStringFileFolder = FileLocator.GetDirectoryDistributedWithApplication(true,"localization");
            if (installedStringFileFolder == null)
            {
                // nb do NOT try to localize this...it's a shame, but the problem we're reporting is that the localization data is missing!
                var msg =
                    @"Bloom seems to be missing some of the files it needs to run. Please uninstall Bloom, then install it again. If that's doesn't fix things, please contact us by clicking the ""Details"" button below, and we'd be glad to help.";
                ErrorReport.NotifyUserOfProblem(new ApplicationException("Missing localization directory"), msg);
                // If the user insists on continuing after that, start up using the built-in English.
                // We need an LM, and it needs some folder of tmx files, though it can be empty. So make a fake one.
                // Ideally we would dispose this at some point, but I don't know when we safely can. Normally this should never happen,
                // so I'm not very worried.
                var fakeLocalDir = new TemporaryFolder("Bloom fake localization").FolderPath;
                applicationContainer.LocalizationManager = LocalizationManager.Create("en", "Bloom", "Bloom", Application.ProductVersion, fakeLocalDir, "SIL/Bloom",
                                           Resources.BloomIcon, "*****@*****.**",
                                            //the parameters that follow are namespace beginnings:
                                           "Bloom");
                return;
            }

            try
            {
                applicationContainer.LocalizationManager = LocalizationManager.Create(Settings.Default.UserInterfaceLanguage,
                                           "Bloom", "Bloom", Application.ProductVersion,
                                           installedStringFileFolder,
                                           "SIL/Bloom",
                                           Resources.BloomIcon, "*****@*****.**",
                                           //the parameters that follow are namespace beginnings:
                                           "Bloom");

                //We had a case where someone translated stuff into another language, and sent in their tmx. But their tmx had soaked up a bunch of string
                //from their various templates, which were not Bloom standard templates. So then someone else sitting down to localize bloom would be
                //faced with a bunch of string that made no sense to them, because they don't have those templates.
                //So for now, we only soak up new strings if it's a developer, and hope that the Commit process will be enough for them to realize "oh no, I
                //don't want to check that stuff in".

            #if DEBUG
                applicationContainer.LocalizationManager.CollectUpNewStringsDiscoveredDynamically = true;
            #else
                applicationContainer.LocalizationManager.CollectUpNewStringsDiscoveredDynamically = false;
            #endif

                var uiLanguage =   LocalizationManager.UILanguageId;//just feeding this into subsequent creates prevents asking the user twice if the language of their os isn't one we have a tmx for
                var unusedGoesIntoStatic = LocalizationManager.Create(uiLanguage,
                                           "Palaso", "Palaso", /*review: this is just bloom's version*/Application.ProductVersion,
                                           installedStringFileFolder,
                                            "SIL/Bloom",
                                            Resources.BloomIcon, "*****@*****.**", "SIL");

                Settings.Default.UserInterfaceLanguage = LocalizationManager.UILanguageId;
            }
            catch (Exception error)
            {
                //handle http://jira.palaso.org/issues/browse/BL-213
                if (GetRunningBloomProcessCount() > 1)
                {
                    ErrorReport.NotifyUserOfProblem("Whoops. There is another copy of Bloom already running while Bloom was trying to set up L10NSharp.");
                    Environment.FailFast("Bloom couldn't set up localization");
                }

                if (error.Message.Contains("Bloom.en.tmx"))
                {
                    ErrorReport.NotifyUserOfProblem(error,
                        "Sorry. Bloom is trying to set up your machine to use this new version, but something went wrong getting at the file it needs. If you restart your computer, all will be well.");

                    Environment.FailFast("Bloom couldn't set up localization");
                }

                //otherwise, we don't know what caused it.
                throw;
            }
        }
Example #22
0
        /// <summary>
        /// Warning, if the book already exists in the location, this is going to delete it an over-write it. So it's up to the caller to check the sanity of that.
        /// </summary>
        /// <param name="storageKeyOfBookFolder"></param>
        public string DownloadBook(string storageKeyOfBookFolder, string pathToDestinationParentDirectory)
        {
            //TODO tell it not to download pdfs. Those are just in there for previewing purposes, we don't need to get them now that we're getting the real thing

            var matchingFilesResponse = _amazonS3.ListObjects(new ListObjectsRequest()
            {
                BucketName = _bucketName,
                Delimiter = kDirectoryDelimeterForS3,
                Prefix = storageKeyOfBookFolder
            });

            foreach (var s3Object in matchingFilesResponse.S3Objects)
            {
                _amazonS3.BeginGetObject(new GetObjectRequest() {BucketName = _bucketName, Key = s3Object.Key},
                    OnDownloadCallback, s3Object);
            }

            //review: should we instead save to a newly created folder so that we don't have to worry about the
            //other folder existing already? Todo: add a test for that first.

            if (!GetBookExists(storageKeyOfBookFolder))
                throw new DirectoryNotFoundException("The book we tried to download is no longer in the BloomLibrary");

            using (var tempDestination =
                    new TemporaryFolder("BloomDownloadStaging " + storageKeyOfBookFolder + " " + Guid.NewGuid()))
            {
                var token = _transferUtility.BeginDownloadDirectory(_bucketName, storageKeyOfBookFolder,
                    tempDestination.FolderPath, OnDownloadProgress, storageKeyOfBookFolder);

                _transferUtility.EndDownloadDirectory(token);

                //look inside the wrapper that we got

                var children = Directory.GetDirectories(tempDestination.FolderPath);
                if (children.Length != 1)
                {
                    throw new ApplicationException(
                        string.Format("Bloom expected to find a single directory in {0}, but instead there were {1}",
                            tempDestination.FolderPath, children.Length));
                }
                var destinationPath = Path.Combine(pathToDestinationParentDirectory, Path.GetFileName(children[0]));

                //clear out anything exisitng on our target
                if (Directory.Exists(destinationPath))
                {
                    Directory.Delete(destinationPath, true);
                }

                //if we're on the same volume, we can just move it. Else copy it.
                if (Directory.GetDirectoryRoot(pathToDestinationParentDirectory) == Directory.GetDirectoryRoot(tempDestination.FolderPath))
                {
                    Directory.Move(children[0], destinationPath);
                }
                else
                {
                    CopyDirectory(children[0], destinationPath);
                }
                return destinationPath;
            }
        }
        private string MakeBook(string bookName, string id, string uploader, string data)
        {
            var f = new TemporaryFolder(_workFolder, bookName);
            File.WriteAllText(Path.Combine(f.FolderPath, "one.htm"), data);
            File.WriteAllText(Path.Combine(f.FolderPath, "one.css"), @"test");

            File.WriteAllText(Path.Combine(f.FolderPath, "meta.json"), "{\"bookInstanceId\":\"" + id + "\",\"uploadedBy\":\"" + uploader + "\"}");

            return f.FolderPath;
        }
 public void Setup()
 {
     _workFolder = new TemporaryFolder("unittest-" + _thisTestId);
     _workFolderPath = _workFolder.FolderPath;
     Assert.AreEqual(0,Directory.GetDirectories(_workFolderPath).Count(),"Some stuff was left over from a previous test");
     Assert.AreEqual(0, Directory.GetFiles(_workFolderPath).Count(),"Some stuff was left over from a previous test");
     // Todo: Make sure the S3 unit test bucket is empty.
     // Todo: Make sure the parse.com unit test book table is empty
     _parseClient = new BloomParseClientDouble(_thisTestId);
     _htmlThumbNailer = new HtmlThumbNailer(new NavigationIsolator());
     _transfer = new BookTransfer(_parseClient, new BloomS3Client(BloomS3Client.UnitTestBucketName), new BookThumbNailer(_htmlThumbNailer), new BookDownloadStartingEvent());
     _transfer.BookDownLoaded += (sender, args) => _downloadedBooks.Add(args.BookDetails);
 }
Example #25
0
        /// <summary>
        /// Generate all the files we will zip into the ePUB for the current book into the StagingFolder.
        /// It is required that the parent of the StagingFolder is a temporary folder into which we can
        /// copy the Readium stuff. This folder is deleted when the EpubMaker is disposed.
        /// </summary>
        public void StageEpub(bool publishWithoutAudio = false)
        {
            _publishWithoutAudio = publishWithoutAudio;
            Debug.Assert(_stagingFolder == null, "EpubMaker should only be used once");

            //I (JH) kept having trouble making epubs because this kept getting locked.
            SIL.IO.DirectoryUtilities.DeleteDirectoryRobust(Path.Combine(Path.GetTempPath(), kEPUBExportFolder));

            _stagingFolder = new TemporaryFolder(kEPUBExportFolder);
            // The readium control remembers the current page for each book.
            // So it is useful to have a unique name for each one.
            // However, it needs to be something we can put in a URL without complications,
            // so a guid is better than say the book's own folder name.
            StagingDirectory = Path.Combine(_stagingFolder.FolderPath, _book.ID);
            // in case of previous versions // Enhance: delete when done? Generate new name if conflict?
            var contentFolderName = "content";
            _contentFolder = Path.Combine(StagingDirectory, contentFolderName);
            Directory.CreateDirectory(_contentFolder); // also creates parent staging directory
            var pageIndex = 0;
            _manifestItems = new List<string>();
            _spineItems = new List<string>();
            int firstContentPageIndex = Book.GetIndexLastFrontkMatterPage() + 2; // pageIndex starts at 1
            _firstContentPageItem = null;
            foreach (XmlElement pageElement in Book.GetPageElements())
            {
                ++pageIndex;
                var pageDom = MakePageFile(pageElement, pageIndex, firstContentPageIndex);
                // for now, at least, all Bloom book pages currently have the same stylesheets, so we only neeed
                //to look at those stylesheets on the first page
                if (pageIndex == 1)
                    CopyStyleSheets(pageDom);
            }

            string coverPageImageFile = "thumbnail-256.png";
            // This thumbnail is otherwise only made when uploading, so it may be out of date.
            // Just remake it every time.
            ApplicationException thumbNailException = null;
            try
            {
                _thumbNailer.MakeThumbnailOfCover(Book, 256, Form.ActiveForm);
            }
            catch (ApplicationException e)
            {
                thumbNailException = e;
            }
            var coverPageImagePath = Path.Combine(Book.FolderPath, coverPageImageFile);
            if (thumbNailException != null || !RobustFile.Exists(coverPageImagePath))
            {
                NonFatalProblem.Report(ModalIf.All, PassiveIf.All, "Bloom failed to make a high-quality cover page for your book (BL-3209)",
                    "We will try to make the book anyway, but you may want to try again.",
                    thumbNailException);

                coverPageImageFile = "thumbnail.png"; // Try a low-res image, which should always exist
                coverPageImagePath = Path.Combine(Book.FolderPath, coverPageImageFile);
                if (!RobustFile.Exists(coverPageImagePath))
                {
                    // I don't think we can make an epub without a cover page so at this point we've had it.
                    // I suppose we could recover without actually crashing but it doesn't seem worth it unless this
                    // actually happens to real users.
                    throw new FileNotFoundException("Could not find or create thumbnail for cover page (BL-3209)", coverPageImageFile);
                }
            }
            CopyFileToEpub(coverPageImagePath);

            EmbedFonts(); // must call after copying stylesheets
            MakeNavPage();

            //supporting files

            // Fixed requirement for all epubs
            RobustFile.WriteAllText(Path.Combine(StagingDirectory, "mimetype"), @"application/epub+zip");

            var metaInfFolder = Path.Combine(StagingDirectory, "META-INF");
            Directory.CreateDirectory(metaInfFolder);
            var containerXmlPath = Path.Combine(metaInfFolder, "container.xml");
            RobustFile.WriteAllText(containerXmlPath, @"<?xml version='1.0' encoding='utf-8'?>
                    <container version='1.0' xmlns='urn:oasis:names:tc:opendocument:xmlns:container'>
                    <rootfiles>
                    <rootfile full-path='content/content.opf' media-type='application/oebps-package+xml'/>
                    </rootfiles>
                    </container>");

            MakeManifest(coverPageImageFile);
        }
Example #26
0
        private IPage MakeTemplatePageThatHasABookWithStylesheets(TemporaryFolder bookFolder, IEnumerable<string> stylesheetNames )
        {
            var headContents = "";
            foreach(var stylesheetName in stylesheetNames)
            {
                headContents += "<link rel='stylesheet' href='"+stylesheetName+"' type='text/css'></link>";
            }

            var templateDom =
                new HtmlDom("<html><head>" + headContents + "</head><body><div class='bloom-page' id='1'></div></body></html>");
            var templateBook = new Moq.Mock<Bloom.Book.Book>();
            templateBook.Setup(x => x.FolderPath).Returns(bookFolder.FolderPath);
            templateBook.Setup(x => x.OurHtmlDom).Returns(templateDom);
            Mock<IPage> templatePage = CreateTemplatePage("<div class='bloom-page' id='1'></div>");
            templatePage.Setup(x => x.Book).Returns(templateBook.Object);
            return templatePage.Object;
        }
Example #27
0
 public TemporaryFolder(TemporaryFolder parent, string name)
 {
     _path = parent.Combine(name);
     if (Directory.Exists(_path))
     {
        DeleteFolderThatMayBeInUse(_path);
     }
     Directory.CreateDirectory(_path);
 }
Example #28
0
        public void InsertPageAfter_PageRequiresStylesheetWeAlreadyHave_StylesheetNotAdded()
        {
            using(var templateBookFolder = new TemporaryFolder("InsertPageAfter_PageRequiresStylesheetWeAlreadyHave_StylesheetNotAdded"))
            {
                var templatePage = MakeTemplatePageThatHasABookWithStylesheets(templateBookFolder, new string[] {"foo.css"});
                    //it's in the template
                var link = "<link rel='stylesheet' href='foo.css' type='text/css'></link>";
                SetDom("<div class='bloom-page' id='1'></div>", link); //and we already have it in the target book
                var targetBook = CreateBook();
                targetBook.InsertPageAfter(targetBook.GetPages().First(), templatePage);

                Assert.AreEqual(1, targetBook.OurHtmlDom.GetTemplateStyleSheets().Count(name => name == "foo.css"));
            }
        }
Example #29
0
        public TempLiftFile(TemporaryFolder parentFolder, string xmlOfEntries, string claimedLiftVersion)
            : base(false)
        {
            if (parentFolder != null)
            {
                _path = parentFolder.GetPathForNewTempFile(false) + ".lift";
            }
            else
            {
                _path = System.IO.Path.GetRandomFileName() + ".lift";
            }

            string liftContents = string.Format("<?xml version='1.0' encoding='utf-8'?><lift version='{0}'>{1}</lift>", claimedLiftVersion, xmlOfEntries);
            RobustFile.WriteAllText(_path, liftContents);
        }
Example #30
0
        public void InsertPageAfter_PageRequiresStylesheetWeDontHave_StylesheetFileCopied()
        {
            //we need an actual templateBookFolder to contain the stylesheet we need to see copied into the target book
            using(var templateBookFolder = new TemporaryFolder("InsertPageAfter_PageRequiresStylesheetWeDontHave_StylesheetFileCopied"))
            {
                //just a boring simple target book
                SetDom("<div class='bloom-page' id='1'></div>", "");
                var targetBook = CreateBook();

                //our template folder will have this stylesheet file
                File.WriteAllText(templateBookFolder.Combine("foo.css"), ".dummy{width:100px}");

                //we're going to reference one stylesheet that is actually available in the template folder, and one that isn't

                var templatePage = MakeTemplatePageThatHasABookWithStylesheets( templateBookFolder, new [] {"foo.css","notthere.css"});

                targetBook.InsertPageAfter(targetBook.GetPages().First(), templatePage);

                Assert.True(File.Exists(targetBook.FolderPath.CombineForPath("foo.css")));

                //Now add it again, to see if that causes problems
                targetBook.InsertPageAfter(targetBook.GetPages().First(), templatePage);

                //Have the template list a file it doesn't actually have
                var templatePage2 = MakeTemplatePageThatHasABookWithStylesheets( templateBookFolder, new[] { "notthere.css" });

                    //for now, we just want it to not crash
                targetBook.InsertPageAfter(targetBook.GetPages().First(), templatePage2);
            }
        }