public IRestResponse SetBookRecord(string metadataJson) { if (!LoggedIn) { throw new ApplicationException("BloomParseClient got SetBookRecord, but the user is not logged in."); } if (BookUpload.IsDryRun) { throw new ApplicationException("Should not call SetBookRecord during dry run!"); } var metadata = BookMetaData.FromString(metadataJson); var book = GetSingleBookRecord(metadata.Id); metadataJson = ChangeJsonBeforeCreatingOrModifyingBook(metadataJson); if (book == null) { return(CreateBookRecord(metadataJson)); } var request = MakePutRequest("classes/books/" + book.objectId); request.AddParameter("application/json", metadataJson, ParameterType.RequestBody); var response = Client.Execute(request); if (response.StatusCode != HttpStatusCode.OK) { throw new ApplicationException("BloomParseClient.SetBookRecord: " + response.StatusDescription + " " + response.Content); } return(response); }
/// <summary> /// This method assumes we just did IsBookOnServer() and got a positive response. /// </summary> public dynamic GetBookOnServer(string bookPath) { var metadata = BookMetaData.FromString(RobustFile.ReadAllText(bookPath.CombineForPath(BookInfo.MetaDataFileName))); // 'true' parameter tells the query to include language information so we can get the names. return(ParseClient.GetSingleBookRecord(metadata.Id, true)); }
private void FixupHeaderForWriting(BBeB book) { if (book.MetaData == null) { // TODO - This is just because we don't have any metadata yet Debug.WriteLineIf(s_bDebugMode, "Book has no metadata - Mocking some up for testing"); MemoryStream metaStream = new MemoryStream(); XmlSerializer xmlSerializer = new XmlSerializer(typeof(BookMetaData)); BookMetaData md = new BookMetaData(); xmlSerializer.Serialize(metaStream, md); metaStream.Seek(0, SeekOrigin.Begin); book.MetaData = md; //.Load(metaStream); } if (book.Header.wVersion >= 800) { if (book.ThumbnailData == null) { throw new InvalidBookException("Don't have a thumbnail image"); } book.Header.dwThumbSize = (uint)book.ThumbnailData.Length; } book.Header.NumberOfObjects = (ulong)book.Objects.Count; }
public IRestResponse SetBookRecord(string metadataJson) { if (!LoggedIn) { throw new ApplicationException(); } var metadata = BookMetaData.FromString(metadataJson); var book = GetSingleBookRecord(metadata.Id); if (book == null) { return(CreateBookRecord(metadataJson)); } var request = MakePutRequest("classes/books/" + book.objectId); request.AddParameter("application/json", metadataJson, ParameterType.RequestBody); var response = _client.Execute(request); if (response.StatusCode != HttpStatusCode.OK) { throw new ApplicationException(response.StatusDescription + " " + response.Content); } return(response); }
private static string GetMetaJsonModfiedForTemplate(string path) { var meta = BookMetaData.FromString(RobustFile.ReadAllText(path)); meta.IsSuitableForMakingShells = true; return(meta.Json); }
public void HandleBookOrder(string bookOrderPath, string projectPath) { var metadata = BookMetaData.FromString(File.ReadAllText(bookOrderPath)); var s3BookId = metadata.DownloadSource; _s3Client.DownloadBook(s3BookId, Path.GetDirectoryName(projectPath)); }
public void FeaturesSetter_OverallFeaturesOnly_ConvertBackGetsSameResult() { var input = new string[] { "blind", "talkingBook", "signLanguage", "quiz", "motion", "comic", "activity", "widget" }; var metadata = new BookMetaData(); // System under test metadata.Features = input; // Run the setter string[] convertBackResult = metadata.Features; // Run the getter // Verify that converting back gets the same result (We don't care about the order they're in, though)) CollectionAssert.AreEqual(input.OrderBy(x => x), convertBackResult.OrderBy(x => x)); // Verify individual other properties too Assert.AreEqual(true, metadata.Feature_Blind, "Blind"); Assert.AreEqual(true, metadata.Feature_TalkingBook, "TalkingBook"); Assert.AreEqual(true, metadata.Feature_SignLanguage, "SignLanguage"); Assert.AreEqual(true, metadata.Feature_Quiz, "Quiz"); Assert.AreEqual(true, metadata.Feature_Motion, "Motion"); Assert.AreEqual(true, metadata.Feature_Comic, "Comic"); Assert.AreEqual(true, metadata.Feature_Activity, "Activity"); Assert.AreEqual(true, metadata.Feature_Widget, "Widget"); string[] expectedResult = new string[] { "" }; CollectionAssert.AreEqual(expectedResult, metadata.Feature_Blind_LangCodes, "Blind Language Codes"); CollectionAssert.AreEqual(expectedResult, metadata.Feature_TalkingBook_LangCodes, "TB Language Codes"); CollectionAssert.AreEqual(expectedResult, metadata.Feature_SignLanguage_LangCodes, "SL Language Codes"); }
/// <summary> /// Read the metadata using the supplied reader. /// </summary> /// <param name="reader">The reader to use to read the metadata with. It is /// already positioned at the first byte of metadata.</param> /// <param name="nCompressedLen">The length of the compressed metadata. The first /// four bytes is the size of the uncompressed data.</param> public BookMetaData DeserializeMetaData(BinaryReader reader, int nCompressedLen) { Debug.WriteLineIf(s_bDebugMode, "Reading metadata"); byte[] byUncompressedData = ZLib.Decompress(reader, nCompressedLen); Debug.WriteLineIf(s_bDebugMode, "Parsing metadata"); MemoryStream xmlStream = new MemoryStream(byUncompressedData); XmlSerializer serializer = new XmlSerializer(typeof(BookMetaData)); XmlTextReader xreader = new XmlTextReader(xmlStream); BookMetaData metaData = null; try { metaData = (BookMetaData)serializer.Deserialize(xreader); } catch (Exception e) { Debug.WriteLineIf(s_bDebugMode, e.ToString()); } xreader.Close(); return(metaData); }
public void MetaData_WithUnknownTool_DiscardsIt() { var json = "{ \"bookInstanceId\":\"bee9496b-00c2-42f2-83c5-7e2f61f50a33\",\"tools\":[{\"name\":\"decodableReader\",\"enabled\":true,\"state\":\"stage:1;sort:alphabetic\"},{\"name\":\"leveledReader\",\"enabled\":true,\"state\":\"1\"},{\"name\":\"talkingBook\",\"enabled\":true,\"state\":null}, {\"name\":\"rubbish\",\"enabled\":true,\"state\":null}],\"currentTool\":\"leveledReaderTool\",\"toolboxIsOpen\":true}"; var metadata = BookMetaData.FromString(json); Assert.That(metadata.Tools, Has.Count.EqualTo(3)); // Unknown tool should not show up. }
public void UploadBook_FillsInMetaData() { var bookFolder = MakeBook("My incomplete book", "", "", "data"); File.WriteAllText(Path.Combine(bookFolder, "thumbnail.png"), @"this should be a binary picture"); Login(); string s3Id = _transfer.UploadBook(bookFolder, new NullProgress()); _transfer.WaitUntilS3DataIsOnServer(bookFolder); var dest = _workFolderPath.CombineForPath("output"); Directory.CreateDirectory(dest); var newBookFolder = _transfer.DownloadBook(s3Id, dest); var metadata = BookMetaData.FromString(File.ReadAllText(Path.Combine(newBookFolder, BookInfo.MetaDataFileName))); Assert.That(string.IsNullOrEmpty(metadata.Id), Is.False, "should have filled in missing ID"); Assert.That(metadata.Uploader.ObjectId, Is.EqualTo(_parseClient.UserId), "should have set uploader to id of logged-in user"); Assert.That(metadata.DownloadSource, Is.EqualTo(s3Id)); var record = _parseClient.GetSingleBookRecord(metadata.Id); string baseUrl = record.baseUrl; Assert.That(baseUrl.StartsWith("https://s3.amazonaws.com/BloomLibraryBooks"), "baseUrl should start with s3 prefix"); string order = record.bookOrder; Assert.That(order, Is.StringContaining("My+incomplete+book.BloomBookOrder"), "order url should include correct file name"); Assert.That(order.StartsWith(BloomLinkArgs.kBloomUrlPrefix + BloomLinkArgs.kOrderFile + "="), "order url should start with Bloom URL prefix"); Assert.That(File.Exists(Path.Combine(newBookFolder, "My incomplete book.BloomBookOrder")), "Should have created, uploaded and downloaded the book order"); }
/// <summary> /// Internal for testing because it's not yet clear this is the appropriate public routine. /// Probably some API gets a list of BloomInfo objects from the parse.com data, and we pass one of /// them as the argument for the public method. /// </summary> /// <param name="bucket"></param> /// <param name="s3BookId"></param> /// <param name="dest"></param> /// <returns></returns> internal string DownloadBook(string bucket, string s3BookId, string dest) { var destinationPath = _s3Client.DownloadBook(bucket, s3BookId, dest, _progressDialog); if (BookDownLoaded != null) { var bookInfo = new BookInfo(destinationPath, false); // A downloaded book is a template, so never editable. BookDownLoaded(this, new BookDownloadedEventArgs() { BookDetails = bookInfo }); } // Books in the library should generally show as locked-down, so new users are automatically in localization mode. // Occasionally we may want to upload a new authoring template, that is, a 'book' that is suitableForMakingShells. // Such books should not be locked down. // So, we try to lock it. What we want to do is Book.RecordedAsLockedDown = true; Book.Save(). // But all kinds of things have to be set up before we can create a Book. So we duplicate a few bits of code. var htmlFile = BookStorage.FindBookHtmlInFolder(destinationPath); if (htmlFile == "") { return(destinationPath); //argh! we can't lock it. } var xmlDomFromHtmlFile = XmlHtmlConverter.GetXmlDomFromHtmlFile(htmlFile, false); var dom = new HtmlDom(xmlDomFromHtmlFile); if (!BookMetaData.FromString(MetaDataText(destinationPath)).IsSuitableForMakingShells) { dom.RecordAsLockedDown(true); XmlHtmlConverter.SaveDOMAsHtml5(dom.RawDom, htmlFile); } return(destinationPath); }
public void HandleBookOrder(string bookOrderPath, string projectPath) { var metadata = BookMetaData.FromString(RobustFile.ReadAllText(bookOrderPath)); var s3BookId = metadata.DownloadSource; var bucket = BloomS3Client.ProductionBucketName; //TODO _s3Client.DownloadBook(bucket, s3BookId, Path.GetDirectoryName(projectPath)); }
private string S3BookId(BookMetaData metadata) { // It's tempting to use '/' so that S3 tools will treat all the books with the same ID as a folder. // But this complicates things because that character is taken as a path separator (even in Windows), // which gives us an extra level of folder in our temp folder...too much trouble for now, anyway. // So use a different separator. var s3BookId = _parseClient.Account + "/" + metadata.Id; return(s3BookId); }
public void CreateBookOnDiskFromTemplateStarter_IsTemplate_ButNotTemplateFactory() { var source = BloomFileLocator.GetFactoryBookTemplateDirectory("Template Starter"); var path = _starter.CreateBookOnDiskFromTemplate(source, _projectFolder.Path); var newMetaData = BookMetaData.FromFolder(path); Assert.That(newMetaData.IsSuitableForMakingShells, Is.True); Assert.That(newMetaData.IsSuitableForMakingTemplates, Is.False); }
/// <summary> /// Creates the .bloomd and bloomdigital folders /// </summary> private static CreateArtifactsExitCode CreateBloomDigitalArtifacts(string bookPath, string creator, string zippedBloomDOutputPath, string unzippedBloomDigitalOutputPath) { #if DEBUG // Useful for allowing debugging of Bloom while running the harvester //MessageBox.Show("Attach debugger now"); #endif var exitCode = CreateArtifactsExitCode.Success; using (var tempBloomD = TempFile.CreateAndGetPathButDontMakeTheFile()) { if (String.IsNullOrEmpty(zippedBloomDOutputPath)) { zippedBloomDOutputPath = tempBloomD.Path; } BookServer bookServer = _projectContext.BookServer; var metadata = BookMetaData.FromFolder(bookPath); bool isTemplateBook = metadata.IsSuitableForMakingShells; using (var folderForUnzipped = new TemporaryFolder("BloomCreateArtifacts_Unzipped")) { // Ensure directory exists, just in case. Directory.CreateDirectory(Path.GetDirectoryName(zippedBloomDOutputPath)); // Make the bloomd string unzippedPath = Publish.Android.BloomPubMaker.CreateBloomPub( zippedBloomDOutputPath, bookPath, bookServer, System.Drawing.Color.Azure, // TODO: What should this be? new Bloom.web.NullWebSocketProgress(), folderForUnzipped, creator, isTemplateBook); // Currently the zipping process does some things we actually need, like making the cover picture // transparent (BL-7437). Eventually we plan to separate the preparation and zipping steps (BL-7445). // Until that is done, the most reliable way to get an unzipped BloomD for our preview is to actually // unzip the BloomD. if (!String.IsNullOrEmpty(unzippedBloomDigitalOutputPath)) { SIL.IO.RobustIO.DeleteDirectory(unzippedBloomDigitalOutputPath, recursive: true); // In case the folder isn't already empty // Ensure directory exists, just in case. Directory.CreateDirectory(Path.GetDirectoryName(unzippedBloomDigitalOutputPath)); ZipFile.ExtractToDirectory(zippedBloomDOutputPath, unzippedBloomDigitalOutputPath); exitCode |= RenameBloomDigitalFiles(unzippedBloomDigitalOutputPath); } } } return(exitCode); }
public void CreateBookOnDiskFromTemplate_OriginalIsTemplate_CopyIsNotTemplate() { var source = BloomFileLocator.GetFactoryBookTemplateDirectory("Basic Book"); var originalMetaData = BookMetaData.FromFolder(source); Assert.That(originalMetaData.IsSuitableForMakingShells); var path = _starter.CreateBookOnDiskFromTemplate(source, _projectFolder.Path); var newMetaData = BookMetaData.FromFolder(path); Assert.That(newMetaData.IsSuitableForMakingShells, Is.False); }
public void FeaturesGetter_NeitherQuizNorWidgetSet_ThenActivityIsFalse() { var metadata = new BookMetaData(); metadata.Feature_Quiz = metadata.Feature_Widget = false; // System under test string[] result = metadata.Features; Assert.IsFalse(result.Contains("activity")); }
public void InsertOrUpdateMetaData(BookMetaData entity) { if (entity.Id == default(int)) { Context.BookMetaData.Add(entity); } else { Context.Entry(entity).State = EntityState.Modified; } }
public void FeaturesGetter_Comic(bool containsComic) { var metadata = new BookMetaData(); metadata.Feature_Comic = containsComic; // System under test string[] result = metadata.Features; string[] expectedResult = containsComic ? new string[] { "comic" } : new string[0]; Assert.AreEqual(expectedResult, result); }
public void FeaturesGetter_Activity(bool containsActivity) { var metadata = new BookMetaData(); metadata.Feature_Activity = containsActivity; // System under test string[] result = metadata.Features; string[] expectedResult = containsActivity ? new string[] { "activity" } : new string[0]; Assert.AreEqual(expectedResult, result); }
public void FeaturesGetter_Motion(bool containsMotion) { var metadata = new BookMetaData(); metadata.Feature_Motion = containsMotion; // System under test string[] result = metadata.Features; string[] expectedResult = containsMotion ? new string[] { "motion" } : new string[0]; Assert.AreEqual(expectedResult, result); }
public void FeaturesGetter_IfQuizOrWidgetSet_ThenActivityIsTrue(bool containsQuiz, bool containsWidget) { var metadata = new BookMetaData(); metadata.Feature_Quiz = containsQuiz; metadata.Feature_Widget = containsWidget; // System under test string[] result = metadata.Features; Assert.IsTrue(result.Contains("activity")); }
public void FeaturesGetter_Quiz(bool containsQuiz) { var metadata = new BookMetaData(); metadata.Feature_Quiz = containsQuiz; // System under test string[] result = metadata.Features; string[] expectedResult = containsQuiz ? new string[] { "quiz" } : new string[0]; Assert.AreEqual(expectedResult, result); }
public void FeaturesGetter_Blind(IEnumerable <string> langCodes, string[] featuresExpected) { var metadata = new BookMetaData(); metadata.Feature_Blind_LangCodes = langCodes; // System under test string[] featuresResult = metadata.Features; bool featureBlindResult = metadata.Feature_Blind; Assert.AreEqual(featuresExpected, featuresResult, "Features"); Assert.AreEqual(featuresExpected.Any(), featureBlindResult, "Feature_Blind"); }
public void FeaturesGetter_SignLanguage(IEnumerable <string> langCodes, string[] featuresExpected) { var metadata = new BookMetaData(); metadata.Feature_SignLanguage_LangCodes = langCodes; // System under test string[] result = metadata.Features; bool featureSignLanguageResult = metadata.Feature_SignLanguage; Assert.AreEqual(featuresExpected, result, "Features"); Assert.AreEqual(featuresExpected.Any(), featureSignLanguageResult, "Feature_SignLanguage"); }
public void FeaturesGetter_Widget(bool containsWidget) { var metadata = new BookMetaData(); metadata.Feature_Widget = containsWidget; // System under test string[] result = metadata.Features; bool expectedResult = containsWidget; Assert.AreEqual(expectedResult, result.Contains("widget")); }
public void AudioLangsToPublishForBloomReader_GivenNonDefaultJson_DeserializesProperly() { var json = "{ \"audioLangsToPublish\": { \"bloomPUB\": { \"en\": \"Include\" } } }"; // System under test var metadata = BookMetaData.FromString(json); // Verification var expected = new Dictionary <string, Bloom.Publish.InclusionSetting>(); expected.Add("en", Bloom.Publish.InclusionSetting.Include); CollectionAssert.AreEquivalent(expected, metadata.AudioLangsToPublish.ForBloomPUB); }
/// <summary> /// Review: this is fragile and expensive. We're doing real internet traffic and creating real objects on S3 and parse.com /// which (to a very small extent) costs us real money. This will be slow. Also, under S3 eventual consistency rules, /// there is no guarantee that the data we just created will actually be retrievable immediately. /// </summary> /// <param name="bookName"></param> /// <param name="id"></param> /// <param name="uploader"></param> /// <param name="data"></param> /// <returns></returns> public Tuple <string, string> UploadAndDownLoadNewBook(string bookName, string id, string uploader, string data, bool isTemplate = false) { // Create a book folder with meta.json that includes an uploader and id and some other files. var originalBookFolder = MakeBook(bookName, id, uploader, data, true); if (isTemplate) { var metadata = BookMetaData.FromFolder(originalBookFolder); metadata.IsSuitableForMakingShells = true; metadata.WriteToFolder(originalBookFolder); } // The files that actually get uploaded omit some of the ones in the folder. // The only omitted one that messes up current unit tests is meta.bak var filesToUpload = Directory.GetFiles(originalBookFolder).Where(p => !p.EndsWith(".bak") && !p.Contains(BookStorage.PrefixForCorruptHtmFiles)); int fileCount = filesToUpload.Count(); Login(); //HashSet<string> notifications = new HashSet<string>(); var progress = new SIL.Progress.StringBuilderProgress(); var s3Id = _uploader.UploadBook(originalBookFolder, progress); var uploadMessages = progress.Text.Split(new string[] { Environment.NewLine }, StringSplitOptions.RemoveEmptyEntries); var expectedFileCount = fileCount + 2; // should get one per file, plus one for metadata, plus one for book order #if DEBUG ++expectedFileCount; // and if in debug mode, then plus one for S3 ID #endif Assert.That(uploadMessages.Length, Is.EqualTo(expectedFileCount), "Uploaded file counts do not match"); Assert.That(progress.Text, Does.Contain( LocalizationManager.GetString("PublishTab.Upload.UploadingBookMetadata", "Uploading book metadata", "In this step, Bloom is uploading things like title, languages, & topic tags to the bloomlibrary.org database."))); Assert.That(progress.Text, Does.Contain(Path.GetFileName(filesToUpload.First()))); _uploader.WaitUntilS3DataIsOnServer(BloomS3Client.UnitTestBucketName, originalBookFolder); var dest = _workFolderPath.CombineForPath("output"); Directory.CreateDirectory(dest); _downloadedBooks.Clear(); var url = BookUpload.BloomS3UrlPrefix + BloomS3Client.UnitTestBucketName + "/" + s3Id; var newBookFolder = _downloader.HandleDownloadWithoutProgress(url, dest); Assert.That(Directory.GetFiles(newBookFolder).Length, Is.EqualTo(fileCount + 1), "Book order was not added during upload"); // book order is added during upload Assert.That(_downloadedBooks.Count, Is.EqualTo(1)); Assert.That(_downloadedBooks[0].FolderPath, Is.EqualTo(newBookFolder)); // Todo: verify that metadata was transferred to Parse.com return(new Tuple <string, string>(originalBookFolder, newBookFolder)); }
public void TopicsList_SetsTopicsWhileLeavingOtherTagsIntact(string jsonTagsList, string topicsListToSet, string expectedTopicsList, string[] expectedTags) { var jsonPath = Path.Combine(_folder.Path, BookInfo.MetaDataFileName); File.WriteAllText(jsonPath, @"{'tags':[" + jsonTagsList + @"]}"); var bi = new BookInfo(_folder.Path, true); //SUT bi.TopicsList = topicsListToSet; Assert.AreEqual(expectedTopicsList, bi.TopicsList); BookMetaData metadata = (BookMetaData)ReflectionHelper.GetField(bi, "_metadata"); Assert.AreEqual(expectedTags, metadata.Tags); }
// Wait (up to three seconds) for data uploaded to become available. // Currently only used in unit testing. // I have no idea whether 3s is an adequate time to wait for 'eventual consistency'. So far it seems to work. internal void WaitUntilS3DataIsOnServer(string bookPath) { var s3Id = S3BookId(BookMetaData.FromFolder(bookPath)); var count = Directory.GetFiles(bookPath).Length; for (int i = 0; i < 30; i++) { var uploaded = _s3Client.GetBookFileCount(s3Id); if (uploaded >= count) { return; } Thread.Sleep(100); } throw new ApplicationException("S3 is very slow today"); }