Exemple #1
0
        public void Action_WithOneModifiedEntry_ShouldCountOneModified()
        {
            // Setup
            var lfProj = _lfProj;

            sutFdoToMongo.Run(lfProj);

            Guid       entryGuid     = Guid.Parse(TestEntryGuidStr);
            LfLexEntry entry         = _conn.GetLfLexEntryByGuid(entryGuid);
            FdoCache   cache         = lfProj.FieldWorksProject.Cache;
            string     vernacularWS  = cache.LanguageProject.DefaultVernacularWritingSystem.Id;
            string     changedLexeme = "modified lexeme for this test";

            entry.Lexeme     = LfMultiText.FromSingleStringMapping(vernacularWS, changedLexeme);
            entry.AuthorInfo = new LfAuthorInfo();
            entry.AuthorInfo.ModifiedDate = DateTime.UtcNow;
            _conn.UpdateMockLfLexEntry(entry);

            // Exercise
            sutMongoToFdo.Run(lfProj);

            // Verify
            Assert.That(_counts.Added, Is.EqualTo(0));
            Assert.That(_counts.Modified, Is.EqualTo(1));
            Assert.That(_counts.Deleted, Is.EqualTo(0));

            Assert.That(LfMergeBridgeServices.FormatCommitMessageForLfMerge(_counts.Added, _counts.Modified, _counts.Deleted),
                        Is.EqualTo("Language Forge: 1 entry modified"));
        }
Exemple #2
0
        /// <summary>
        /// Convert FDO example LF example.
        /// </summary>
        /// <returns>LF example
        /// <param name="fdoExample">Fdo example.</param>
        private LfExample FdoExampleToLfExample(ILexExampleSentence fdoExample)
        {
            var lfExample = new LfExample();

            ILgWritingSystem AnalysisWritingSystem   = ServiceLocator.LanguageProject.DefaultAnalysisWritingSystem;
            ILgWritingSystem VernacularWritingSystem = ServiceLocator.LanguageProject.DefaultVernacularWritingSystem;

            lfExample.Guid      = fdoExample.Guid;
            lfExample.Sentence  = ToMultiText(fdoExample.Example);
            lfExample.Reference = LfMultiText.FromSingleITsString(fdoExample.Reference, ServiceLocator.WritingSystemFactory);
            // ILexExampleSentence fields we currently do not convert:
            // fdoExample.DoNotPublishInRC;
            // fdoExample.LiftResidue;
            // fdoExample.PublishIn;

            // NOTE: Currently, LanguageForge only stores one translation per example, whereas FDO can store
            // multiple translations with (possibly) different statuses (as freeform strings, like "old", "updated",
            // "needs fixing"...). Until LanguageForge acquires a data model where translations are stored in a list,
            // we will save only the first translation (if any) to Mongo. We also save the GUID so that the Mongo->FDO
            // direction will know which ICmTranslation object to update with any changes.
            // TODO: Once LF improves its data model for translations, persist all of them instead of just the first.
            foreach (ICmTranslation translation in fdoExample.TranslationsOC.Take(1))
            {
                lfExample.Translation     = ToMultiText(translation.Translation);
                lfExample.TranslationGuid = translation.Guid;
            }

            BsonDocument customFieldsAndGuids = _convertCustomField.GetCustomFieldsForThisCmObject(fdoExample, "examples", ListConverters);
            BsonDocument customFieldsBson     = customFieldsAndGuids["customFields"].AsBsonDocument;
            BsonDocument customFieldGuids     = customFieldsAndGuids["customFieldGuids"].AsBsonDocument;

            lfExample.CustomFields     = customFieldsBson;
            lfExample.CustomFieldGuids = customFieldGuids;
            return(lfExample);
        }
Exemple #3
0
        public void Action_WithOneNewEntry_ShouldCountOneAdded()
        {
            // Setup
            var lfProj = _lfProj;

            LfLexEntry newEntry = new LfLexEntry();

            newEntry.Guid = Guid.NewGuid();
            FdoCache cache        = lfProj.FieldWorksProject.Cache;
            string   vernacularWS = cache.LanguageProject.DefaultVernacularWritingSystem.Id;
            string   newLexeme    = "new lexeme for this test";

            newEntry.Lexeme                  = LfMultiText.FromSingleStringMapping(vernacularWS, newLexeme);
            newEntry.AuthorInfo              = new LfAuthorInfo();
            newEntry.AuthorInfo.CreatedDate  = DateTime.UtcNow;
            newEntry.AuthorInfo.ModifiedDate = newEntry.AuthorInfo.CreatedDate;
            _conn.UpdateMockLfLexEntry(newEntry);

            // Exercise
            sutMongoToFdo.Run(lfProj);

            // Verify
            Assert.That(_counts.Added, Is.EqualTo(1));
            Assert.That(_counts.Modified, Is.EqualTo(0));
            Assert.That(_counts.Deleted, Is.EqualTo(0));

            Assert.That(LfMergeBridgeServices.FormatCommitMessageForLfMerge(_counts.Added, _counts.Modified, _counts.Deleted),
                        Is.EqualTo("Language Forge: 1 entry added"));
        }
Exemple #4
0
 public static LfMultiText ToMultiText(IMultiAccessorBase fdoMultiString, ILgWritingSystemFactory fdoWritingSystemManager)
 {
     if ((fdoMultiString == null) || (fdoWritingSystemManager == null))
     {
         return(null);
     }
     return(LfMultiText.FromFdoMultiString(fdoMultiString, fdoWritingSystemManager));
 }
Exemple #5
0
 private LfMultiText ToMultiText(IMultiAccessorBase fdoMultiString)
 {
     if (fdoMultiString == null)
     {
         return(null);
     }
     return(LfMultiText.FromFdoMultiString(fdoMultiString, ServiceLocator.WritingSystemManager));
 }
Exemple #6
0
 public static LfMultiText ToMultiText(IMultiAccessorBase LcmMultiString, ILgWritingSystemFactory LcmWritingSystemManager)
 {
     if ((LcmMultiString == null) || (LcmWritingSystemManager == null))
     {
         return(null);
     }
     return(LfMultiText.FromLcmMultiString(LcmMultiString, LcmWritingSystemManager));
 }
Exemple #7
0
        public void Action_RunTwiceWithOneNewEntryEachTime_ShouldCountTwoAddedInTotal()
        {
            // Setup
            var lfProj = _lfProj;

            LfLexEntry newEntry = new LfLexEntry();

            newEntry.Guid = Guid.NewGuid();
            LcmCache cache        = lfProj.FieldWorksProject.Cache;
            string   vernacularWS = cache.LanguageProject.DefaultVernacularWritingSystem.Id;
            string   newLexeme    = "new lexeme for this test";

            newEntry.Lexeme                  = LfMultiText.FromSingleStringMapping(vernacularWS, newLexeme);
            newEntry.AuthorInfo              = new LfAuthorInfo();
            newEntry.AuthorInfo.CreatedDate  = DateTime.UtcNow;
            newEntry.AuthorInfo.ModifiedDate = newEntry.AuthorInfo.CreatedDate;
            _conn.UpdateMockLfLexEntry(newEntry);

            // Exercise
            SutMongoToLcm.Run(lfProj);

            // Verify
            Assert.That(_counts.Added, Is.EqualTo(1));
            Assert.That(_counts.Modified, Is.EqualTo(0));
            Assert.That(_counts.Deleted, Is.EqualTo(0));

            Assert.That(LfMergeBridgeServices.FormatCommitMessageForLfMerge(_counts.Added, _counts.Modified, _counts.Deleted),
                        Is.EqualTo("Language Forge: 1 entry added"));

            // Setup second run
            newEntry                         = new LfLexEntry();
            newEntry.Guid                    = Guid.NewGuid();
            newLexeme                        = "second new lexeme for this test";
            newEntry.Lexeme                  = LfMultiText.FromSingleStringMapping(vernacularWS, newLexeme);
            newEntry.AuthorInfo              = new LfAuthorInfo();
            newEntry.AuthorInfo.CreatedDate  = DateTime.UtcNow;
            newEntry.AuthorInfo.ModifiedDate = newEntry.AuthorInfo.CreatedDate;
            _conn.UpdateMockLfLexEntry(newEntry);

            // Exercise
            SutMongoToLcm.Run(lfProj);

            // Verify
            Assert.That(_counts.Added, Is.EqualTo(1));
            // Modified and Deleted shouldn't have changed, but check Added first
            // since that's the main point of this test
            Assert.That(_counts.Modified, Is.EqualTo(0));
            Assert.That(_counts.Deleted, Is.EqualTo(0));

            Assert.That(LfMergeBridgeServices.FormatCommitMessageForLfMerge(_counts.Added, _counts.Modified, _counts.Deleted),
                        Is.EqualTo("Language Forge: 1 entry added"));
        }
        public void SynchronizeAction_LFDataChangedLDEntryDeleted_LFWins()
        {
            // Setup
            TestEnvironment.CopyFwProjectTo(modifiedTestProjectCode, _lDSettings.WebWorkDirectory);
            Directory.Move(Path.Combine(_lDSettings.WebWorkDirectory, modifiedTestProjectCode), LanguageDepotMock.ProjectFolderPath);

            _lfProject.IsInitialClone = true;
            _transferFdoToMongo.Run(_lfProject);

            IEnumerable <LfLexEntry> originalMongoData = _mongoConnection.GetLfLexEntries();
            LfLexEntry lfEntry = originalMongoData.First(e => e.Guid == _testDeletedEntryGuid);
            DateTime   originalLfDateModified = lfEntry.DateModified;

            Assert.That(lfEntry.Senses.Count, Is.EqualTo(1));
            const string lfCreatedGloss = "new English gloss - added in LF";
            const string fwChangedGloss = "English gloss - changed in FW";

            // LF adds a gloss to the entry that LD is deleting
            lfEntry.Senses[0].Gloss         = LfMultiText.FromSingleStringMapping("en", lfCreatedGloss);
            lfEntry.AuthorInfo.ModifiedDate = DateTime.UtcNow;
            _mongoConnection.UpdateRecord(_lfProject, lfEntry);

            _lDProject = new LanguageDepotMock(testProjectCode, _lDSettings);
            var lDcache = _lDProject.FieldWorksProject.Cache;

            Assert.That(() => lDcache.ServiceLocator.GetObject(_testDeletedEntryGuid),
                        Throws.InstanceOf <KeyNotFoundException>());
            var lDFdoEntry = lDcache.ServiceLocator.GetObject(_testEntryGuid) as ILexEntry;

            Assert.That(lDFdoEntry.SensesOS[0].Gloss.AnalysisDefaultWritingSystem.Text, Is.EqualTo(fwChangedGloss));
            DateTime originalLdDateModified = lDFdoEntry.DateModified;

            // Exercise
            var sutSynchronize = new SynchronizeAction(_env.Settings, _env.Logger);
            var timeBeforeRun  = DateTime.UtcNow;

            sutSynchronize.Run(_lfProject);

            // Verify modified LF entry wins
            Assert.That(GetGlossFromMongoDb(_testDeletedEntryGuid, originalNumOfFdoEntries + 1, 0),
                        Is.EqualTo(lfCreatedGloss));
            Assert.That(GetGlossFromMongoDb(_testEntryGuid, originalNumOfFdoEntries + 1, 0),
                        Is.EqualTo(fwChangedGloss));
            Assert.That(GetGlossFromLanguageDepot(_testDeletedEntryGuid, 1), Is.EqualTo(lfCreatedGloss));
            LfLexEntry updatedLfEntry        = _mongoConnection.GetLfLexEntries().First(e => e.Guid == _testEntryGuid);
            DateTime   updatedLfDateModified = updatedLfEntry.DateModified;

            Assert.That(updatedLfDateModified, Is.GreaterThan(originalLfDateModified));
            Assert.That(updatedLfDateModified, Is.GreaterThan(originalLdDateModified));
            Assert.That(_mongoConnection.GetLastSyncedDate(_lfProject), Is.GreaterThanOrEqualTo(timeBeforeRun));
        }
Exemple #9
0
        public void Action_RunTwiceWithTheSameEntryModifiedEachTime_ShouldCountTwoModifiedInTotal()
        {
            // Setup
            var lfProj = _lfProj;

            sutFdoToMongo.Run(lfProj);

            Guid       entryGuid     = Guid.Parse(TestEntryGuidStr);
            LfLexEntry entry         = _conn.GetLfLexEntryByGuid(entryGuid);
            FdoCache   cache         = lfProj.FieldWorksProject.Cache;
            string     vernacularWS  = cache.LanguageProject.DefaultVernacularWritingSystem.Id;
            string     changedLexeme = "modified lexeme for this test";

            entry.Lexeme     = LfMultiText.FromSingleStringMapping(vernacularWS, changedLexeme);
            entry.AuthorInfo = new LfAuthorInfo();
            entry.AuthorInfo.ModifiedDate = DateTime.UtcNow;
            _conn.UpdateMockLfLexEntry(entry);

            // Exercise
            sutMongoToFdo.Run(lfProj);

            // Verify
            Assert.That(_counts.Added, Is.EqualTo(0));
            Assert.That(_counts.Modified, Is.EqualTo(1));
            Assert.That(_counts.Deleted, Is.EqualTo(0));

            Assert.That(LfMergeBridgeServices.FormatCommitMessageForLfMerge(_counts.Added, _counts.Modified, _counts.Deleted),
                        Is.EqualTo("Language Forge: 1 entry modified"));

            // Setup second run
            string changedLexeme2 = "second modified lexeme for this test";

            entry.Lexeme     = LfMultiText.FromSingleStringMapping(vernacularWS, changedLexeme2);
            entry.AuthorInfo = new LfAuthorInfo();
            entry.AuthorInfo.ModifiedDate = DateTime.UtcNow;
            _conn.UpdateMockLfLexEntry(entry);

            // Exercise second run
            sutMongoToFdo.Run(lfProj);

            // Verify second run
            Assert.That(_counts.Modified, Is.EqualTo(1));
            // Added and Deleted shouldn't have changed, but check Modified first
            // since that's the main point of this test
            Assert.That(_counts.Added, Is.EqualTo(0));
            Assert.That(_counts.Deleted, Is.EqualTo(0));

            Assert.That(LfMergeBridgeServices.FormatCommitMessageForLfMerge(_counts.Added, _counts.Modified, _counts.Deleted),
                        Is.EqualTo("Language Forge: 1 entry modified"));
        }
        public void SynchronizeAction_LFDataChangedLDOtherDataChanged_ModifiedDateUpdated()
        {
            //Setup
            TestEnvironment.CopyFwProjectTo(modifiedTestProjectCode, _lDSettings.WebWorkDirectory);
            Directory.Move(Path.Combine(_lDSettings.WebWorkDirectory, modifiedTestProjectCode), LanguageDepotMock.ProjectFolderPath);

            _lfProject.IsInitialClone = true;
            _transferFdoToMongo.Run(_lfProject);

            var lfEntry = _mongoConnection.GetLfLexEntries().First(e => e.Guid == _testEntryGuid);
            var originalLfDateModified           = lfEntry.DateModified;
            var originalLfAuthorInfoModifiedDate = lfEntry.AuthorInfo.ModifiedDate;

            lfEntry.Note = LfMultiText.FromSingleStringMapping("en", "A note from LF");
            lfEntry.AuthorInfo.ModifiedDate = DateTime.UtcNow;
            _mongoConnection.UpdateRecord(_lfProject, lfEntry);

            var fwChangedGloss = lfEntry.Senses[0].Gloss["en"].Value + " - changed in FW";

            _lDProject = new LanguageDepotMock(testProjectCode, _lDSettings);
            var lDcache    = _lDProject.FieldWorksProject.Cache;
            var lDFdoEntry = lDcache.ServiceLocator.GetObject(_testEntryGuid) as ILexEntry;

            Assert.That(lDFdoEntry.SensesOS[0].Gloss.AnalysisDefaultWritingSystem.Text, Is.EqualTo(fwChangedGloss));

            // Exercise
            var sutSynchronize = new SynchronizeAction(_env.Settings, _env.Logger);
            var timeBeforeRun  = DateTime.UtcNow;

            sutSynchronize.Run(_lfProject);

            // Verify
            Assert.That(GetGlossFromMongoDb(_testEntryGuid), Is.EqualTo(fwChangedGloss));
            var updatedLfEntry = _mongoConnection.GetLfLexEntries().First(e => e.Guid == _testEntryGuid);

            // LF and LD changed the same entry but different fields, so we want to see the
            // DateModified change so that LF will re-process the entry.
            Assert.That(updatedLfEntry.DateModified, Is.GreaterThan(originalLfDateModified));
            // The FDO modified date (AuthorInfo.ModifiedDate in LF) should be updated.
            Assert.That(updatedLfEntry.AuthorInfo.ModifiedDate, Is.GreaterThan(originalLfAuthorInfoModifiedDate));

            Assert.That(_mongoConnection.GetLastSyncedDate(_lfProject), Is.GreaterThanOrEqualTo(timeBeforeRun));
        }
Exemple #11
0
        /// <summary>
        /// Convert FDO sense to LF sense.
        /// </summary>
        /// <returns>LF sense
        /// <param name="fdoSense">Fdo sense.</param>
        private LfSense FdoSenseToLfSense(ILexSense fdoSense)
        {
            var lfSense = new LfSense();

            ILgWritingSystem VernacularWritingSystem = ServiceLocator.LanguageProject.DefaultVernacularWritingSystem;
            ILgWritingSystem AnalysisWritingSystem   = ServiceLocator.LanguageProject.DefaultAnalysisWritingSystem;

            lfSense.Guid       = fdoSense.Guid;
            lfSense.Gloss      = ToMultiText(fdoSense.Gloss);
            lfSense.Definition = ToMultiText(fdoSense.Definition);

            // Fields below in alphabetical order by ILexSense property, except for Guid, Gloss and Definition
            lfSense.AcademicDomains        = ToStringArrayField(AcademicDomainListCode, fdoSense.DomainTypesRC);
            lfSense.AnthropologyCategories = ToStringArrayField(AnthroCodeListCode, fdoSense.AnthroCodesRC);
            lfSense.AnthropologyNote       = ToMultiText(fdoSense.AnthroNote);
            lfSense.DiscourseNote          = ToMultiText(fdoSense.DiscourseNote);
            lfSense.EncyclopedicNote       = ToMultiText(fdoSense.EncyclopedicInfo);
            if (fdoSense.ExamplesOS != null)
            {
                lfSense.Examples = new List <LfExample>(fdoSense.ExamplesOS.Select(FdoExampleToLfExample));
            }

            lfSense.GeneralNote = ToMultiText(fdoSense.GeneralNote);
            lfSense.GrammarNote = ToMultiText(fdoSense.GrammarNote);
            if (fdoSense.LIFTid == null)
            {
                lfSense.LiftId = null;
            }
            else
            {
                lfSense.LiftId = fdoSense.LIFTid.Normalize(System.Text.NormalizationForm.FormC);                  // Because LIFT files on disk are NFC and we need to make sure LiftIDs match those on disk
            }
            if (fdoSense.MorphoSyntaxAnalysisRA != null)
            {
                IPartOfSpeech secondaryPos = null;                 // Only used in derivational affixes
                IPartOfSpeech pos          = ConvertFdoToMongoPartsOfSpeech.FromMSA(fdoSense.MorphoSyntaxAnalysisRA, out secondaryPos);
                // Sometimes the part of speech can be null for legitimate reasons, so check the known class IDs before warning of an unknown MSA type
                if (pos == null && !ConvertFdoToMongoPartsOfSpeech.KnownMsaClassIds.Contains(fdoSense.MorphoSyntaxAnalysisRA.ClassID))
                {
                    Logger.Warning("Got MSA of unknown type {0} in sense {1} in project {2}",
                                   fdoSense.MorphoSyntaxAnalysisRA.GetType().Name,
                                   fdoSense.Guid,
                                   LfProject.ProjectCode);
                }
                else
                {
                    lfSense.PartOfSpeech          = ToStringField(GrammarListCode, pos);
                    lfSense.SecondaryPartOfSpeech = ToStringField(GrammarListCode, secondaryPos);                     // It's fine if secondaryPos is still null here
                }
            }
            lfSense.PhonologyNote = ToMultiText(fdoSense.PhonologyNote);
            if (fdoSense.PicturesOS != null)
            {
                lfSense.Pictures = new List <LfPicture>(fdoSense.PicturesOS.Select(FdoPictureToLfPicture));
                //Use the commented code for debugging into FdoPictureToLfPicture
                //
                //lfSense.Pictures = new List<LfPicture>();
                //foreach (var fdoPic in fdoSense.PicturesOS)
                //	lfSense.Pictures.Add(FdoPictureToLfPicture(fdoPic));
            }
            lfSense.SenseBibliography = ToMultiText(fdoSense.Bibliography);
            lfSense.SenseRestrictions = ToMultiText(fdoSense.Restrictions);

            if (fdoSense.ReversalEntriesRC != null)
            {
                IEnumerable <string> reversalEntries = fdoSense.ReversalEntriesRC.Select(fdoReversalEntry => fdoReversalEntry.LongName);
                lfSense.ReversalEntries = LfStringArrayField.FromStrings(reversalEntries);
            }
            lfSense.ScientificName = LfMultiText.FromSingleITsString(fdoSense.ScientificName, ServiceLocator.WritingSystemFactory);
            lfSense.SemanticDomain = ToStringArrayField(SemDomListCode, fdoSense.SemanticDomainsRC);
            lfSense.SemanticsNote  = ToMultiText(fdoSense.SemanticsNote);
            // fdoSense.SensesOS; // Not mapped because LF doesn't handle subsenses. TODO: When LF handles subsenses, map this one.
            lfSense.SenseType            = ToStringField(SenseTypeListCode, fdoSense.SenseTypeRA);
            lfSense.SociolinguisticsNote = ToMultiText(fdoSense.SocioLinguisticsNote);
            if (fdoSense.Source != null)
            {
                lfSense.Source = LfMultiText.FromSingleITsString(fdoSense.Source, ServiceLocator.WritingSystemFactory);
            }
            lfSense.Status = ToStringArrayField(StatusListCode, fdoSense.StatusRA);
            lfSense.Usages = ToStringArrayField(UsageTypeListCode, fdoSense.UsageTypesRC);


            /* Fields not mapped because it doesn't make sense to map them (e.g., Hvo, backreferences, etc):
             * fdoSense.AllOwnedObjects;
             * fdoSense.AllSenses;
             * fdoSense.Cache;
             * fdoSense.CanDelete;
             * fdoSense.ChooserNameTS;
             * fdoSense.ClassID;
             * fdoSense.ClassName;
             * fdoSense.Entry;
             * fdoSense.EntryID;
             * fdoSense.FullReferenceName;
             * fdoSense.GetDesiredMsaType();
             * fdoSense.Hvo;
             * fdoSense.ImportResidue;
             * fdoSense.IndexInOwner;
             * fdoSense.IsValidObject;
             * fdoSense.LexSenseReferences;
             * fdoSense.LongNameTSS;
             * fdoSense.ObjectIdName;
             * fdoSense.OwnedObjects;
             * fdoSense.Owner;
             * fdoSense.OwningFlid;
             * fdoSense.OwnOrd;
             * fdoSense.ReferringObjects;
             * fdoSense.ReversalNameForWs(wsVern);
             * fdoSense.SandboxMSA; // Set-only property
             * fdoSense.Self;
             * fdoSense.Services;
             * fdoSense.ShortName;
             * fdoSense.ShortNameTSS;
             * fdoSense.SortKey;
             * fdoSense.SortKey2;
             * fdoSense.SortKey2Alpha;
             * fdoSense.SortKeyWs;
             * fdoSense.VariantFormEntryBackRefs;
             * fdoSense.VisibleComplexFormBackRefs;
             */

            /* Fields not mapped because LanguageForge doesn't handle that data:
             * fdoSense.AppendixesRC;
             * fdoSense.ComplexFormEntries;
             * fdoSense.ComplexFormsNotSubentries;
             * fdoSense.DoNotPublishInRC;
             * fdoSense.Subentries;
             * fdoSense.ThesaurusItemsRC;
             * fdoSense.LiftResidue;
             * fdoSense.LexSenseOutline;
             * fdoSense.PublishIn;
             */

            BsonDocument customFieldsAndGuids = _convertCustomField.GetCustomFieldsForThisCmObject(fdoSense, "senses", ListConverters);
            BsonDocument customFieldsBson     = customFieldsAndGuids["customFields"].AsBsonDocument;
            BsonDocument customFieldGuids     = customFieldsAndGuids["customFieldGuids"].AsBsonDocument;

            // TODO: Role Views only set on initial clone
            if (LfProject.IsInitialClone)
            {
                ;
            }

            // If custom field was deleted in Flex, delete config here


            lfSense.CustomFields     = customFieldsBson;
            lfSense.CustomFieldGuids = customFieldGuids;

            return(lfSense);
        }
Exemple #12
0
        /// <summary>
        /// Convert FDO lex entry to LF lex entry.
        /// </summary>
        /// <returns>LF entry
        /// <param name="fdoEntry">Fdo entry.</param>
        private LfLexEntry FdoLexEntryToLfLexEntry(ILexEntry fdoEntry)
        {
            if (fdoEntry == null)
            {
                return(null);
            }

            ILgWritingSystem AnalysisWritingSystem   = ServiceLocator.LanguageProject.DefaultAnalysisWritingSystem;
            ILgWritingSystem VernacularWritingSystem = ServiceLocator.LanguageProject.DefaultVernacularWritingSystem;

            var lfEntry = new LfLexEntry();

            IMoForm fdoLexeme = fdoEntry.LexemeFormOA;

            if (fdoLexeme == null)
            {
                lfEntry.Lexeme = null;
            }
            else
            {
                lfEntry.Lexeme = ToMultiText(fdoLexeme.Form);
            }
            // Other fields of fdoLexeme (AllomorphEnvironments, LiftResidue, MorphTypeRA, etc.) not mapped

            // Fields below in alphabetical order by ILexSense property, except for Lexeme
            foreach (IMoForm allomorph in fdoEntry.AlternateFormsOS)
            {
                // Do nothing; LanguageForge doesn't currently handle allomorphs, so we don't convert them
            }
            lfEntry.EntryBibliography = ToMultiText(fdoEntry.Bibliography);
            // TODO: Consider whether to use fdoEntry.CitationFormWithAffixType instead
            // (which would produce "-s" instead of "s" for the English plural suffix, for instance)
            lfEntry.CitationForm = ToMultiText(fdoEntry.CitationForm);
            lfEntry.Note         = ToMultiText(fdoEntry.Comment);

            // DateModified and DateCreated can be confusing, because LF and FDO are doing two different
            // things with them. In FDO, there is just one DateModified and one DateCreated; simple. But
            // in LF, there is an AuthorInfo record as well, which contains its own ModifiedDate and CreatedDate
            // fields. (Note the word order: there's LfEntry.DateCreated, and LfEntry.AuthorInfo.CreatedDate).

            // The conversion we have chosen to use is: AuthorInfo will correspond to FDO. So FDO.DateCreated
            // becomes AuthorInfo.CreatedDate, and FDO.DateModified becomes AuthorInfo.ModifiedDate. The two
            // fields on the LF entry will instead refer to when the *Mongo record* was created or modified,
            // and the LfEntry.DateCreated and LfEntry.DateModified fields will never be put into FDO.

            var now = DateTime.UtcNow;

            if (LfProject.IsInitialClone)
            {
                lfEntry.DateCreated = now;
            }
            // LanguageForge needs this modified to know there is changed data
            lfEntry.DateModified = now;

            if (lfEntry.AuthorInfo == null)
            {
                lfEntry.AuthorInfo = new LfAuthorInfo();
            }
            lfEntry.AuthorInfo.CreatedByUserRef  = null;
            lfEntry.AuthorInfo.CreatedDate       = fdoEntry.DateCreated.ToUniversalTime();
            lfEntry.AuthorInfo.ModifiedByUserRef = null;
            lfEntry.AuthorInfo.ModifiedDate      = fdoEntry.DateModified.ToUniversalTime();

#if DBVERSION_7000068
            ILexEtymology fdoEtymology = fdoEntry.EtymologyOA;
#else
            // TODO: Once LF's data model is updated from a single etymology to an array,
            // convert all of them instead of just the first. E.g.,
            // foreach (ILexEtymology fdoEtymology in fdoEntry.EtymologyOS) { ... }
            ILexEtymology fdoEtymology = null;
            if (fdoEntry.EtymologyOS.Count > 0)
            {
                fdoEtymology = fdoEntry.EtymologyOS.First();
            }
#endif
            if (fdoEtymology != null)
            {
                lfEntry.Etymology        = ToMultiText(fdoEtymology.Form);
                lfEntry.EtymologyComment = ToMultiText(fdoEtymology.Comment);
                lfEntry.EtymologyGloss   = ToMultiText(fdoEtymology.Gloss);
#if DBVERSION_7000068
                lfEntry.EtymologySource = LfMultiText.FromSingleStringMapping(AnalysisWritingSystem.Id, fdoEtymology.Source);
#else
                lfEntry.EtymologySource = ToMultiText(fdoEtymology.LanguageNotes);
#endif
                // fdoEtymology.LiftResidue not mapped
            }
            lfEntry.Guid = fdoEntry.Guid;
            if (fdoEntry.LIFTid == null)
            {
                lfEntry.LiftId = null;
            }
            else
            {
                lfEntry.LiftId = fdoEntry.LIFTid.Normalize(System.Text.NormalizationForm.FormC);                  // Because LIFT files on disk are NFC and we need to make sure LiftIDs match those on disk
            }
            lfEntry.LiteralMeaning = ToMultiText(fdoEntry.LiteralMeaning);
            if (fdoEntry.PrimaryMorphType != null)
            {
                lfEntry.MorphologyType = fdoEntry.PrimaryMorphType.NameHierarchyString;
            }
            // TODO: Once LF's data model is updated from a single pronunciation to an array of pronunciations, convert all of them instead of just the first. E.g.,
            //foreach (ILexPronunciation fdoPronunciation in fdoEntry.PronunciationsOS) { ... }
            if (fdoEntry.PronunciationsOS.Count > 0)
            {
                ILexPronunciation fdoPronunciation = fdoEntry.PronunciationsOS.First();
                lfEntry.Pronunciation = ToMultiText(fdoPronunciation.Form);
                lfEntry.CvPattern     = LfMultiText.FromSingleITsString(fdoPronunciation.CVPattern, ServiceLocator.WritingSystemFactory);
                lfEntry.Tone          = LfMultiText.FromSingleITsString(fdoPronunciation.Tone, ServiceLocator.WritingSystemFactory);
                // TODO: Map fdoPronunciation.MediaFilesOS properly (converting video to sound files if necessary)
                lfEntry.Location = ToStringField(LocationListCode, fdoPronunciation.LocationRA);
            }
            lfEntry.EntryRestrictions = ToMultiText(fdoEntry.Restrictions);
            if (lfEntry.Senses == null)             // Shouldn't happen, but let's be careful
            {
                lfEntry.Senses = new List <LfSense>();
            }
            lfEntry.Senses.AddRange(fdoEntry.SensesOS.Select(FdoSenseToLfSense));
            lfEntry.SummaryDefinition = ToMultiText(fdoEntry.SummaryDefinition);

            BsonDocument customFieldsAndGuids = _convertCustomField.GetCustomFieldsForThisCmObject(fdoEntry, "entry", ListConverters);
            BsonDocument customFieldsBson     = customFieldsAndGuids["customFields"].AsBsonDocument;
            BsonDocument customFieldGuids     = customFieldsAndGuids["customFieldGuids"].AsBsonDocument;

            lfEntry.CustomFields     = customFieldsBson;
            lfEntry.CustomFieldGuids = customFieldGuids;

            return(lfEntry);

            /* Fields not mapped because it doesn't make sense to map them (e.g., Hvo, backreferences, etc):
             * fdoEntry.ComplexFormEntries;
             * fdoEntry.ComplexFormEntryRefs;
             * fdoEntry.ComplexFormsNotSubentries;
             * fdoEntry.EntryRefsOS;
             * fdoEntry.HasMoreThanOneSense;
             * fdoEntry.HeadWord; // Read-only virtual property
             * fdoEntry.IsMorphTypesMixed; // Read-only property
             * fdoEntry.LexEntryReferences;
             * fdoEntry.MainEntriesOrSensesRS;
             * fdoEntry.MinimalLexReferences;
             * fdoEntry.MorphoSyntaxAnalysesOC;
             * fdoEntry.MorphTypes;
             * fdoEntry.NumberOfSensesForEntry;
             * fdoEntry.PicturesOfSenses;
             *
             */

            /* Fields that would make sense to map, but that we don't because LF doesn't handle them (e.g., allomorphs):
             * fdoEntry.AllAllomorphs; // LF doesn't handle allomorphs, so skip all allomorph-related fields
             * fdoEntry.AlternateFormsOS;
             * fdoEntry.CitationFormWithAffixType; // Citation form already mapped
             * fdoEntry.DoNotPublishInRC;
             * fdoEntry.DoNotShowMainEntryInRC;
             * fdoEntry.DoNotUseForParsing;
             * fdoEntry.HomographForm;
             * fdoEntry.HomographFormKey;
             * fdoEntry.HomographNumber;
             * fdoEntry.ImportResidue;
             * fdoEntry.LiftResidue;
             * fdoEntry.PronunciationsOS
             * fdoEntry.PublishAsMinorEntry;
             * fdoEntry.PublishIn;
             * fdoEntry.ShowMainEntryIn;
             * fdoEntry.Subentries;
             * fdoEntry.VariantEntryRefs;
             * fdoEntry.VariantFormEntries;
             * fdoEntry.VisibleComplexFormBackRefs;
             * fdoEntry.VisibleComplexFormEntries;
             * fdoEntry.VisibleVariantEntryRefs;
             *
             */
        }
Exemple #13
0
        /// <summary>
        /// Gets the data for one custom field, and any relevant GUIDs.
        /// </summary>
        /// <param name="hvo">Hvo of object we're getting the field for.</param>
        /// <param name="flid">Flid for this field.</param>
        /// <param name="fieldSourceType">Either "entry", "senses" or "examples". Could also be "allomorphs", eventually.</param>
        /// <param name="bsonForThisField">Output of a BsonDocument with the following structure: <br />
        /// { fieldName: { "value": BsonValue, "guid": "some-guid-as-a-string" } } <br />
        /// -OR- <br />
        /// { fieldName: { "value": BsonValue, "guid": ["guid1", "guid2", "guid3"] } } <br />
        /// The format of the fieldName key will be "customField_FOO_field_name_with_underscores",
        /// where FOO is one of "entry", "senses", or "examples". <br />
        /// The type of the "guid" value (array or string) will determine whether there is a single GUID,
        /// or a list of GUIDs that happens to contain only one entry.
        /// If there is no "guid" key, that field has no need for a GUID. (E.g., a number).
        /// </param>
        /// <param name="listConverters">Dictionary of ConvertLcmToMongoOptionList instances, keyed by list code</param>
        private BsonDocument GetCustomFieldData(int hvo, int flid, string fieldSourceType,
                                                IDictionary <string, ConvertLcmToMongoOptionList> listConverters)
        {
            BsonValue             fieldValue   = null;
            BsonValue             fieldGuid    = null; // Might be a single value, might be a list (as a BsonArray)
            ISilDataAccessManaged data         = (ISilDataAccessManaged)cache.DomainDataByFlid;
            CellarPropertyType    LcmFieldType = (CellarPropertyType)LcmMetaData.GetFieldType(flid);
            var dataGuids = new List <Guid>();

            // Valid field types in Lcm are GenDate, Integer, String, OwningAtomic, ReferenceAtomic, and ReferenceCollection, so that's all we implement.
            switch (LcmFieldType)
            {
            case CellarPropertyType.GenDate:
                GenDate genDate    = data.get_GenDateProp(hvo, flid);
                string  genDateStr = genDate.ToLongString();
                // LF wants single-string fields in the format { "ws": { "value": "contents" } }
                fieldValue = String.IsNullOrEmpty(genDateStr) ? null :
                             LfMultiText.FromSingleStringMapping(
                    MagicStrings.LanguageCodeForGenDateFields, genDateStr).AsBsonDocument();
                break;
            // When parsing, will use GenDate.TryParse(str, out genDate)

            case CellarPropertyType.Integer:
                fieldValue = new BsonInt32(data.get_IntProp(hvo, flid));
                if (fieldValue.AsInt32 == default(Int32))
                {
                    fieldValue = null;                     // Suppress int fields with 0 in them, to save Mongo DB space
                }
                else
                {
                    // LF wants single-string fields in the format { "ws": { "value": "contents" } }
                    fieldValue = LfMultiText.FromSingleStringMapping(
                        MagicStrings.LanguageCodeForIntFields, fieldValue.AsInt32.ToString()).AsBsonDocument();
                }
                break;

            case CellarPropertyType.OwningAtomic:
            case CellarPropertyType.ReferenceAtomic:
                int ownedHvo = data.get_ObjectProp(hvo, flid);
                fieldValue = GetCustomReferencedObject(ownedHvo, flid, listConverters, ref dataGuids);
                if (fieldValue != null && LcmFieldType == CellarPropertyType.ReferenceAtomic)
                {
                    // Single CmPossiblity reference - LF expects format like { "value": "key of possibility" }
                    fieldValue = new BsonDocument("value", fieldValue);
                }
                fieldGuid = new BsonString(dataGuids.FirstOrDefault().ToString());
                break;

            case CellarPropertyType.MultiUnicode:
                ITsMultiString tss = data.get_MultiStringProp(hvo, flid);
                if (tss != null && tss.StringCount > 0)
                {
                    fieldValue = LfMultiText.FromMultiITsString(tss, servLoc.WritingSystemManager).AsBsonDocument();
                }
                break;

            case CellarPropertyType.OwningCollection:
            case CellarPropertyType.OwningSequence:
            case CellarPropertyType.ReferenceCollection:
            case CellarPropertyType.ReferenceSequence:
                int[] listHvos    = data.VecProp(hvo, flid);
                var   innerValues = new BsonArray(listHvos.Select(listHvo => GetCustomReferencedObject(listHvo, flid, listConverters, ref dataGuids)).Where(x => x != null));
                if (innerValues.Count == 0)
                {
                    fieldValue = null;
                }
                else
                {
                    fieldValue = new BsonDocument("values", innerValues);
                    fieldGuid  = new BsonArray(dataGuids.Select(guid => guid.ToString()));
                }
                break;

            case CellarPropertyType.String:
                ITsString iTsValue = data.get_StringProp(hvo, flid);
                if (iTsValue == null || String.IsNullOrEmpty(iTsValue.Text))
                {
                    fieldValue = null;
                }
                else
                {
                    fieldValue = LfMultiText.FromSingleITsString(iTsValue, servLoc.WritingSystemManager).AsBsonDocument();
                }
                break;

            default:
                fieldValue = null;
                if (logger != null)
                {
                    logger.Warning("Lcm CellarPropertyType.{0} not recognized for LF custom field", LcmFieldType.ToString());
                }
                break;
            }

            if (fieldValue == null)
            {
                return(null);
            }
            else
            {
                var result = new BsonDocument();
                result.Add("value", fieldValue ?? BsonNull.Value);                 // BsonValues aren't allowed to have C# nulls; they have their own null representation
                if (fieldGuid is BsonArray)
                {
                    result.Add("guid", fieldGuid, ((BsonArray)fieldGuid).Count > 0);
                }
                else
                {
                    result.Add("guid", fieldGuid, fieldGuid != null);
                }
                return(result);
            }
        }
Exemple #14
0
        public void Action_ChangedWithSampleData_ShouldUpdatePictures()
        {
            // Setup initial Mongo project has 1 picture and 2 captions
            var lfProj = _lfProj;
            var data   = new SampleData();

            _conn.UpdateMockLfLexEntry(data.bsonTestData);
            string expectedInternalFileName = Path.Combine("Pictures", data.bsonTestData["senses"][0]["pictures"][0]["fileName"].ToString());
            string expectedExternalFileName = data.bsonTestData["senses"][0]["pictures"][1]["fileName"].ToString();
            int    newMongoPictureCount     = data.bsonTestData["senses"][0]["pictures"].AsBsonArray.Count;
            int    newMongoCaptionCount     = data.bsonTestData["senses"][0]["pictures"][0]["caption"].AsBsonDocument.Count();

            Assert.That(newMongoPictureCount, Is.EqualTo(2));
            Assert.That(newMongoCaptionCount, Is.EqualTo(2));

            // Initial FDO project has 63 entries, 3 internal pictures, and 1 externally linked picture
            FdoCache            cache     = _cache;
            ILexEntryRepository entryRepo = _servLoc.GetInstance <ILexEntryRepository>();
            int originalNumOfFdoPictures  = entryRepo.AllInstances().
                                            Count(e => (e.SensesOS.Count > 0) && (e.SensesOS[0].PicturesOS.Count > 0));

            Assert.That(entryRepo.Count, Is.EqualTo(OriginalNumOfFdoEntries));
            Assert.That(originalNumOfFdoPictures, Is.EqualTo(3 + 1));
            string expectedGuidStr = data.bsonTestData["guid"].AsString;
            Guid   expectedGuid    = Guid.Parse(expectedGuidStr);
            var    entryBefore     = cache.ServiceLocator.GetObject(expectedGuid) as ILexEntry;

            Assert.That(entryBefore.SensesOS.Count, Is.GreaterThan(0));
            Assert.That(entryBefore.SensesOS.First().PicturesOS.Count, Is.EqualTo(1));

            // Exercise adding 1 picture with 2 captions. Note that the picture that was previously attached
            // to this FDO entry will end up being deleted, because it does not have a corresponding picture in LF.
            data.bsonTestData["authorInfo"]["modifiedDate"] = DateTime.UtcNow;
            _conn.UpdateMockLfLexEntry(data.bsonTestData);
            sutMongoToFdo.Run(lfProj);

            // Verify "Added" picture is now the only picture on the sense (because the "old" picture was deleted),
            // and that it has 2 captions with the expected values.
            entryRepo = _servLoc.GetInstance <ILexEntryRepository>();
            int numOfFdoPictures = entryRepo.AllInstances().
                                   Count(e => (e.SensesOS.Count > 0) && (e.SensesOS[0].PicturesOS.Count > 0));

            Assert.That(entryRepo.Count, Is.EqualTo(OriginalNumOfFdoEntries));
            Assert.That(numOfFdoPictures, Is.EqualTo(originalNumOfFdoPictures));

            var entry = cache.ServiceLocator.GetObject(expectedGuid) as ILexEntry;

            Assert.IsNotNull(entry);
            Assert.That(entry.Guid, Is.EqualTo(expectedGuid));
            Assert.That(entry.SensesOS.Count, Is.GreaterThan(0));
            Assert.That(entry.SensesOS.First().PicturesOS.Count, Is.EqualTo(2));
            Assert.That(entry.SensesOS[0].PicturesOS[0].PictureFileRA.InternalPath.ToString(),
                        Is.EqualTo(expectedInternalFileName));
            Assert.That(entry.SensesOS[0].PicturesOS[1].PictureFileRA.InternalPath.ToString(),
                        Is.EqualTo(expectedExternalFileName));

            LfMultiText expectedNewCaption = ConvertFdoToMongoLexicon.
                                             ToMultiText(entry.SensesOS[0].PicturesOS[0].Caption, cache.ServiceLocator.WritingSystemManager);
            int expectedNumOfNewCaptions = expectedNewCaption.Count();

            Assert.That(expectedNumOfNewCaptions, Is.EqualTo(2));
            string expectedNewVernacularCaption = expectedNewCaption["qaa-x-kal"].Value;
            string expectedNewAnalysisCaption   = expectedNewCaption["en"].Value;

            Assert.That(expectedNewVernacularCaption.Equals("First Vernacular caption"));
            Assert.That(expectedNewAnalysisCaption.Equals("Internal path reference"));

            var testSubEntry = cache.ServiceLocator.GetObject(Guid.Parse(TestSubEntryGuidStr)) as ILexEntry;

            Assert.That(testSubEntry, Is.Not.Null);
            Assert.That(testSubEntry.SensesOS[0].PicturesOS[0].PictureFileRA.InternalPath.ToString(),
                        Is.EqualTo("Pictures\\TestImage.tif"));
            var kenEntry = cache.ServiceLocator.GetObject(Guid.Parse(KenEntryGuidStr)) as ILexEntry;

            Assert.That(kenEntry, Is.Not.Null);
            Assert.That(kenEntry.SensesOS[0].PicturesOS[0].PictureFileRA.InternalPath.ToString(),
                        Is.EqualTo("F:\\src\\xForge\\web-languageforge\\test\\php\\common\\TestImage.jpg"));
        }
Exemple #15
0
 // Used in subclasses to help reduce size of MongoDB JSON serializations
 protected bool _ShouldSerializeLfMultiText(LfMultiText value)
 {
     return value != null && !value.IsEmpty;
 }