diff --git a/models/door43metadata/search.go b/models/door43metadata/search.go index 710132dab6..78a090274c 100644 --- a/models/door43metadata/search.go +++ b/models/door43metadata/search.go @@ -55,13 +55,17 @@ type SearchCatalogOptions struct { Tags []string Stage Stage Subjects []string + FlavorTypes []string + Flavors []string Resources []string + Abbreviations []string ContentFormats []string CheckingLevels []string Books []string IncludeHistory bool MetadataTypes []string MetadataVersions []string + MetadataQueries map[string][]string ShowIngredients util.OptionalBool Languages []string LanguageIsGL util.OptionalBool @@ -107,12 +111,16 @@ func SearchCatalogCondition(opts *SearchCatalogOptions) builder.Cond { cond := builder.NewCond().And( GetSubjectCond(opts.Subjects, opts.PartialMatch), + GetFlavorTypeCond(opts.FlavorTypes, opts.PartialMatch), + GetFlavorCond(opts.Flavors, opts.PartialMatch), GetResourceCond(opts.Resources), + GetAbbreviationCond(opts.Abbreviations), GetContentFormatCond(opts.ContentFormats, opts.PartialMatch), GetBookCond(opts.Books), GetLanguageCond(opts.Languages, opts.PartialMatch), GetCheckingLevelCond(opts.CheckingLevels), GetMetadataTypeCond(opts.MetadataTypes, opts.PartialMatch), + GetMetadataQueryCond(opts.MetadataQueries, opts.PartialMatch), GetTagCond(opts.Tags), repoCond, ownerCond, @@ -191,6 +199,36 @@ func GetSubjectCond(subjects []string, partialMatch bool) builder.Cond { return subjectCond } +// GetFlavorTypeCond gets the flavor type condition +func GetFlavorTypeCond(flavorTypes []string, partialMatch bool) builder.Cond { + flavorTypeCond := builder.NewCond() + for _, flavorType := range flavorTypes { + for _, v := range strings.Split(flavorType, ",") { + if partialMatch { + flavorTypeCond = flavorTypeCond.Or(builder.Like{"`door43_metadata`.flavor_type", strings.TrimSpace(v)}) + } else { + flavorTypeCond = flavorTypeCond.Or(builder.Eq{"`door43_metadata`.flavor_type": strings.TrimSpace(v)}) + } + } + } + return flavorTypeCond +} + +// GetFlavorCond gets the flavor type condition +func GetFlavorCond(flavors []string, partialMatch bool) builder.Cond { + flavorCond := builder.NewCond() + for _, flavor := range flavors { + for _, v := range strings.Split(flavor, ",") { + if partialMatch { + flavorCond = flavorCond.Or(builder.Like{"`door43_metadata`.flavor", strings.TrimSpace(v)}) + } else { + flavorCond = flavorCond.Or(builder.Eq{"`door43_metadata`.flavor": strings.TrimSpace(v)}) + } + } + } + return flavorCond +} + // GetResourceCond gets the metdata type condition func GetResourceCond(resources []string) builder.Cond { resourceCond := builder.NewCond() @@ -202,6 +240,17 @@ func GetResourceCond(resources []string) builder.Cond { return resourceCond } +// GetAbbreviationCond gets the abbreviation condition +func GetAbbreviationCond(abberviations []string) builder.Cond { + abbreviationCond := builder.NewCond() + for _, abbreviation := range abberviations { + for _, v := range strings.Split(abbreviation, ",") { + abbreviationCond = abbreviationCond.Or(builder.Eq{"`door43_metadata`.abbreviation": strings.TrimSpace(v)}) + } + } + return abbreviationCond +} + // GetContentFormatCond gets the metdata type condition func GetContentFormatCond(formats []string, partialMatch bool) builder.Cond { formatCond := builder.NewCond() @@ -243,6 +292,23 @@ func GetMetadataVersionCond(versions []string, partialMatch bool) builder.Cond { return versionCond } +// GetMetadataQueryCond gets the metdata query condition +func GetMetadataQueryCond(queries map[string][]string, partialMatch bool) builder.Cond { + metadataQueryCond := builder.NewCond() + for field, values := range queries { + for _, value := range values { + for _, v := range strings.Split(value, ",") { + if partialMatch { + metadataQueryCond = metadataQueryCond.Or(builder.Like{field, v}) + } else { + metadataQueryCond = metadataQueryCond.Or(builder.Eq{field: v}) + } + } + } + } + return metadataQueryCond +} + // GetLanguageCond gets the language condition func GetLanguageCond(languages []string, partialMatch bool) builder.Cond { langCond := builder.NewCond() diff --git a/models/repo/door43metadata.go b/models/repo/door43metadata.go index 1c5efdf80b..72fb6fb89b 100644 --- a/models/repo/door43metadata.go +++ b/models/repo/door43metadata.go @@ -41,33 +41,36 @@ func InitDoor43Metadata() error { // Door43Metadata represents the metadata of repository's release or default branch (ReleaseID = 0). type Door43Metadata struct { - ID int64 `xorm:"pk autoincr"` - RepoID int64 `xorm:"INDEX UNIQUE(repo_ref) NOT NULL"` - Repo *Repository `xorm:"-"` - ReleaseID int64 `xorm:"NOT NULL"` - Release *Release `xorm:"-"` - Ref string `xorm:"INDEX UNIQUE(repo_ref) NOT NULL"` - RefType string `xorm:"NOT NULL"` - CommitSHA string `xorm:"NOT NULL VARCHAR(40)"` - Stage door43metadata.Stage `xorm:"INDEX NOT NULL"` - MetadataType string `xorm:"INDEX NOT NULL"` - MetadataVersion string `xorm:"NOT NULL"` - Resource string `xorm:"NOT NULL"` - Subject string `xorm:"INDEX NOT NULL"` - Title string `xorm:"NOT NULL"` - Language string `xorm:"INDEX NOT NULL"` - LanguageTitle string `xorm:"NOT NULL"` - LanguageDirection string `xorm:"NOT NULL"` - LanguageIsGL bool `xorm:"NOT NULL"` - ContentFormat string `xorm:"NOT NULL"` - CheckingLevel int `xorm:"NOT NULL"` - Ingredients []*structs.Ingredient `xorm:"JSON"` - Metadata *map[string]interface{} `xorm:"JSON"` - ReleaseDateUnix timeutil.TimeStamp `xorm:"NOT NULL"` - IsLatestForStage bool `xorm:"INDEX"` - IsRepoMetadata bool `xorm:"INDEX"` - CreatedUnix timeutil.TimeStamp `xorm:"INDEX created NOT NULL"` - UpdatedUnix timeutil.TimeStamp `xorm:"INDEX updated"` + ID int64 `xorm:"pk autoincr"` + RepoID int64 `xorm:"INDEX UNIQUE(repo_ref) NOT NULL"` + Repo *Repository `xorm:"-"` + ReleaseID int64 `xorm:"NOT NULL"` + Release *Release `xorm:"-"` + Ref string `xorm:"INDEX UNIQUE(repo_ref) NOT NULL"` + RefType string `xorm:"NOT NULL"` + CommitSHA string `xorm:"NOT NULL VARCHAR(40)"` + Stage door43metadata.Stage `xorm:"INDEX NOT NULL"` + MetadataType string `xorm:"INDEX NOT NULL"` + MetadataVersion string `xorm:"NOT NULL"` + Resource string `xorm:"NOT NULL"` + Subject string `xorm:"INDEX NOT NULL"` + FlavorType string `xorm:"INDEX NOT NULL"` + Flavor string `xorm:"INDEX NOT NULL"` + Abbreviation string `xorm:"INDEX NOT NULL"` + Title string `xorm:"NOT NULL"` + Language string `xorm:"INDEX NOT NULL"` + LanguageTitle string `xorm:"NOT NULL"` + LanguageDirection string `xorm:"NOT NULL"` + LanguageIsGL bool `xorm:"NOT NULL"` + ContentFormat string `xorm:"NOT NULL"` + CheckingLevel int `xorm:"NOT NULL"` + Ingredients []*structs.Ingredient `xorm:"JSON"` + Metadata map[string]interface{} `xorm:"JSON"` + ReleaseDateUnix timeutil.TimeStamp `xorm:"NOT NULL"` + IsLatestForStage bool `xorm:"INDEX"` + IsRepoMetadata bool `xorm:"INDEX"` + CreatedUnix timeutil.TimeStamp `xorm:"INDEX created NOT NULL"` + UpdatedUnix timeutil.TimeStamp `xorm:"INDEX updated"` } func init() { diff --git a/models/repo/repo_list.go b/models/repo/repo_list.go index 7f4de09bb7..77289b544b 100644 --- a/models/repo/repo_list.go +++ b/models/repo/repo_list.go @@ -166,14 +166,19 @@ type SearchRepoOptions struct { Owners []string // DCS Customizations Repos []string // DCS Customizations Subjects []string // DCS Customizations + FlavorTypes []string // DCS Customizaitons + Flavors []string // DCS Customizations Resources []string // DCS Customizations + Abbreviations []string // DCS Customizations ContentFormats []string // DCS Customization Books []string // DCS Customizations Languages []string // DCS Customizations LanguageIsGL util.OptionalBool // DCS Customizations // query metadata type and version - MetadataTypes []string // DCS Customizations - MetadataVersions []string // DCS Customizations + MetadataTypes []string // DCS Customizations + MetadataVersions []string // DCS Customizations + MetadataQueries map[string][]string // DCS Customizations + PartialMatch bool // DCS Customizations // When specified true, apply some filters over the conditions: // - Don't show forks, when opts.Fork is OptionalBoolNone. // - Do not display repositories that don't have a description, an icon and topics. @@ -515,14 +520,18 @@ func SearchRepositoryCondition(opts *SearchRepoOptions) builder.Cond { } /*** DCS Customizations ***/ - cond = cond.And(door43metadata.GetRepoCond(opts.Repos, false), - door43metadata.GetOwnerCond(opts.Owners, false), - door43metadata.GetSubjectCond(opts.Subjects, false), + cond = cond.And(door43metadata.GetRepoCond(opts.Repos, opts.PartialMatch), + door43metadata.GetOwnerCond(opts.Owners, opts.PartialMatch), + door43metadata.GetSubjectCond(opts.Subjects, opts.PartialMatch), + door43metadata.GetFlavorTypeCond(opts.FlavorTypes, opts.PartialMatch), + door43metadata.GetFlavorCond(opts.Flavors, opts.PartialMatch), door43metadata.GetResourceCond(opts.Resources), + door43metadata.GetAbbreviationCond(opts.Abbreviations), door43metadata.GetContentFormatCond(opts.ContentFormats, false), door43metadata.GetBookCond(opts.Books), - door43metadata.GetLanguageCond(opts.Languages, false), - door43metadata.GetMetadataTypeCond(opts.MetadataTypes, false)) + door43metadata.GetLanguageCond(opts.Languages, opts.PartialMatch), + door43metadata.GetMetadataTypeCond(opts.MetadataTypes, false), + door43metadata.GetMetadataQueryCond(opts.MetadataQueries, opts.PartialMatch)) if len(opts.MetadataTypes) > 0 { cond.And(door43metadata.GetMetadataVersionCond(opts.MetadataVersions, false)) diff --git a/modules/dcs/files.go b/modules/dcs/files.go index 3f5299babb..a854d7a61e 100644 --- a/modules/dcs/files.go +++ b/modules/dcs/files.go @@ -39,23 +39,23 @@ func ReadFileFromBlob(blob *git.Blob) ([]byte, error) { } // ReadYAMLFromBlob reads a yaml file from a blob and unmarshals it -func ReadYAMLFromBlob(blob *git.Blob) (*map[string]interface{}, error) { +func ReadYAMLFromBlob(blob *git.Blob) (map[string]interface{}, error) { buf, err := ReadFileFromBlob(blob) if err != nil { return nil, err } - var result *map[string]interface{} + var result map[string]interface{} if err := yaml.Unmarshal(buf, &result); err != nil { log.Error("yaml.Unmarshal: %v", err) return nil, err } if result != nil { - for k, v := range *result { + for k, v := range result { if val, err := ToStringKeys(v); err != nil { log.Error("ToStringKeys: %v", err) } else { - (*result)[k] = val + (result)[k] = val } } } @@ -63,23 +63,23 @@ func ReadYAMLFromBlob(blob *git.Blob) (*map[string]interface{}, error) { } // ReadJSONFromBlob reads a json file from a blob and unmarshals it -func ReadJSONFromBlob(blob *git.Blob) (*map[string]interface{}, error) { +func ReadJSONFromBlob(blob *git.Blob) (map[string]interface{}, error) { buf, err := ReadFileFromBlob(blob) if err != nil { return nil, err } - var result *map[string]interface{} + var result map[string]interface{} if err := json.Unmarshal(buf, &result); err != nil { log.Error("json.Unmarshal: %v", err) return nil, err } if result != nil { - for k, v := range *result { + for k, v := range result { if val, err := ToStringKeys(v); err != nil { log.Error("ToStringKeys: %v", err) } else { - (*result)[k] = val + (result)[k] = val } } } diff --git a/modules/dcs/rc02.go b/modules/dcs/rc02.go index 3bc1097254..d435ea07bf 100644 --- a/modules/dcs/rc02.go +++ b/modules/dcs/rc02.go @@ -95,7 +95,7 @@ func ValidateMetadataTreeEntry(entry *git.TreeEntry) (*jsonschema.ValidationErro } // ValidateMapByRC02Schema Validates a map structure by the RC v0.2.0 schema and returns the result -func ValidateMapByRC02Schema(data *map[string]interface{}) (*jsonschema.ValidationError, error) { +func ValidateMapByRC02Schema(data map[string]interface{}) (*jsonschema.ValidationError, error) { if data == nil { return &jsonschema.ValidationError{Message: "file cannot be empty"}, nil } @@ -103,7 +103,7 @@ func ValidateMapByRC02Schema(data *map[string]interface{}) (*jsonschema.Validati if err != nil { return nil, err } - if err = schema.Validate(*data); err != nil { + if err = schema.Validate(data); err != nil { switch e := err.(type) { case *jsonschema.ValidationError: return e, nil diff --git a/modules/dcs/sc100.go b/modules/dcs/sb100.go similarity index 62% rename from modules/dcs/sc100.go rename to modules/dcs/sb100.go index 0293a341d4..2545b427be 100644 --- a/modules/dcs/sc100.go +++ b/modules/dcs/sb100.go @@ -37,7 +37,7 @@ func GetSBDataFromBlob(blob *git.Blob) (*SBMetadata100, error) { } // Now make a generic map of the buffer to store in the database table - sb100.Metadata = &map[string]interface{}{} + sb100.Metadata = map[string]interface{}{} if err := json.Unmarshal(buf, sb100.Metadata); err != nil { return nil, err } @@ -76,7 +76,7 @@ func GetSB100Schema(reload bool) (*jsonschema.Schema, error) { } // ValidateMapBySB100Schema Validates a map structure by the RC v0.2.0 schema and returns the result -func ValidateMapBySB100Schema(data *map[string]interface{}) (*jsonschema.ValidationError, error) { +func ValidateMapBySB100Schema(data map[string]interface{}) (*jsonschema.ValidationError, error) { if data == nil { return &jsonschema.ValidationError{Message: "file cannot be empty"}, nil } @@ -84,7 +84,7 @@ func ValidateMapBySB100Schema(data *map[string]interface{}) (*jsonschema.Validat if err != nil { return nil, err } - if err = schema.Validate(*data); err != nil { + if err = schema.Validate(data); err != nil { switch e := err.(type) { case *jsonschema.ValidationError: return e, nil @@ -101,13 +101,37 @@ type SBEncodedMetadata struct { } type SBMetadata100 struct { - Format string `json:"format"` - Meta SB100Meta `json:"meta"` - Identification SB100Identification `json:"identification"` - Languages []SB100Language `json:"languages"` - Type SB100Type `json:"type"` - LocalizedNames *map[string]SB100LocalizedName `json:"localizedNames"` - Metadata *map[string]interface{} + Format string `json:"format"` + Meta SB100Meta `json:"meta"` + Identification SB100Identification `json:"identification"` + Languages []SB100Language `json:"languages"` + Type SB100Type `json:"type"` + LocalizedNames map[string]SB100LocalizedName `json:"localizedNames"` + Metadata map[string]interface{} + Ingredients map[string]SB100Ingredient `xorm:"JSON"` +} + +type LocalizedText map[string]string + +// DetermineLocalizedTextToUse returns the value if there is an English "en" value, otherwise the first value +func (nm LocalizedText) DetermineLocalizedTextToUse() string { + if value, ok := nm["en"]; ok { + return value + } + for k := range nm { + return nm[k] + } + return "" +} + +type ScopeMap map[string][]interface{} + +// GetBookID returns the first key of the scope to be used at the book name +func (sm ScopeMap) GetBookID() string { + for k := range sm { + return k + } + return "" } type SB100Meta struct { @@ -118,17 +142,14 @@ type SB100Meta struct { } type SB100Identification struct { - Name SB100En `json:"name"` - Abbreviation SB100En `json:"abbreviation"` -} - -type SB100En struct { - En string `json:"en"` + Name LocalizedText `json:"name"` + Abbreviation LocalizedText `json:"abbreviation"` } type SB100Language struct { - Tag string `json:"tag"` - Name SB100En `json:"name"` + Tag string `json:"tag"` + Name LocalizedText `json:"name"` + ScriptDirection string `json:"scriptDirection"` } type SB100Type struct { @@ -136,8 +157,9 @@ type SB100Type struct { } type SB100FlavorType struct { - Name string `json:"name"` - Flavor SB100Flavor `json:"flavor"` + Name string `json:"name"` + Flavor SB100Flavor `json:"flavor"` + CurrentScope *ScopeMap `json:"currentScope"` } type SB100Flavor struct { @@ -145,7 +167,15 @@ type SB100Flavor struct { } type SB100LocalizedName struct { - Short SB100En `json:"short"` - Abbr SB100En `json:"abbr"` - Long SB100En `json:"long"` + Short LocalizedText `json:"short"` + Abbr LocalizedText `json:"abbr"` + Long LocalizedText `json:"long"` +} + +type SB100Ingredient struct { + Checksum map[string]string `json:"checksum"` + Mimetype string `json:"mimetype"` + Size int64 `json:"size"` + Scope *ScopeMap `json:"scope"` + Role string `json:"role"` } diff --git a/routers/api/v1/catalog/catalog.go b/routers/api/v1/catalog/catalog.go index b1f6ba39cb..63ff441eac 100644 --- a/routers/api/v1/catalog/catalog.go +++ b/routers/api/v1/catalog/catalog.go @@ -98,23 +98,42 @@ func Search(ctx *context.APIContext) { // enum: [prod,preprod,latest] // - name: subject // in: query - // description: search only for entries with the given subject(s). To match multiple, give the parameter multiple times or give a list comma delimited. Will perform an exact match (case insensitive) unlesss partialMatch=true + // description: resource subject. Multiple values are ORed. + // type: array + // collectionFormat: multi + // items: + // type: string + // - name: flavorType + // in: query + // description: resource flavorType. Multiple values are ORed. + // type: array + // collectionFormat: multi + // items: + // type: string + // - name: flavor + // in: query + // description: resource flavor. Multiple values are ORed. // type: array // collectionFormat: multi // items: // type: string - // enum: [Aligned Bible,Aramaic Grammar,Bible,Greek Grammar,Greek Lexicon,Greek New Testament,Hebrew Grammar,Hebrew Old Testament,Hebrew-Aramaic Lexicon,OBS Study Notes,OBS Study Questions,OBS Translation Notes,OBS Translation Questions,Open Bible Stories,Study Notes,Study Questions,Training Library,Translation Academy,Translation Notes,Translation Questions,Translation Words,TSV Study Notes,TSV Study Questions,TSV Translation Notes,TSV Translation Questions,TSV Translation Words Links,TSV OBS Study Notes,TSV OBS Study Questions,TSV OBS Translation Notes,TSV OBS Translation Questions,TSV OBS Translation Words Links] // - name: resource // in: query - // description: resource identifier. Multiple resources are ORed. + // description: resource identifier. Multiple values are ORed. + // type: array + // collectionFormat: multi + // items: + // type: string + // - name: abbreviation + // in: query + // description: resource abbreviation (identifier). Multiple values are ORed. // type: array // collectionFormat: multi // items: // type: string - // enum: [glt,gst,obs,obs-sn,obs-sq,obs-tn,obs-tq,obs-twl,sn,sq,ta,tn,tq,tw,twl,ugnt,uhb,ult,ust] // - name: format // in: query - // description: content format (usfm, text, markdown, etc.). Multiple formats are ORed. + // description: content format (usfm, text, markdown, etc.). Multiple values are ORed. // type: array // collectionFormat: multi // items: @@ -149,6 +168,13 @@ func Search(ctx *context.APIContext) { // collectionFormat: multi // items: // type: string + // - name: metadata.* + // in: query + // description: You can specify key=value pairs where the key is prefixed with `metadata.`. The rest of the key will be used to search the metadata for the given value. Example: metadata.type.flavorType.flavor=textStory + // type: array + // collectionFormat: multi + // items: + // type: string // - name: partialMatch // in: query // description: if true, subject, owner and repo search fields will use partial match (LIKE) when querying the catalog. Default is false @@ -238,21 +264,39 @@ func SearchOwner(ctx *context.APIContext) { // enum: [prod,preprod,latest] // - name: subject // in: query - // description: search only for entries with the given subject(s). To match multiple, give the parameter multiple times or give a list comma delimited. Will perform an exact match (case insensitive) unlesss partialMatch=true + // description: resource subject. Multiple values are ORed. + // type: array + // collectionFormat: multi + // items: + // type: string + // - name: flavorType + // in: query + // description: resource flavorType. Multiple values are ORed. + // type: array + // collectionFormat: multi + // items: + // type: string + // - name: flavor + // in: query + // description: resource flavor. Multiple values are ORed. // type: array // collectionFormat: multi // items: // type: string - // enum: [Aligned Bible,Aramaic Grammar,Bible,Greek Grammar,Greek Lexicon,Greek New Testament,Hebrew Grammar,Hebrew Old Testament,Hebrew-Aramaic Lexicon,OBS Study Notes,OBS Study Questions,OBS Translation Notes,OBS Translation Questions,Open Bible Stories,Study Notes,Study Questions,Training Library,Translation Academy,Translation Notes,Translation Questions,Translation Words,TSV Study Notes,TSV Study Questions,TSV Translation Notes,TSV Translation Questions,TSV Translation Words Links,TSV OBS Study Notes,TSV OBS Study Questions,TSV OBS Translation Notes,TSV OBS Translation Questions,TSV OBS Translation Words Links] // - name: resource // in: query - // description: resource identifier. Multiple resources are ORed. + // description: resource identifier. Multiple values are ORed. // type: array // collectionFormat: multi // items: // type: string - // enum: [glt,gst,obs,obs-sn,obs-sq,obs-tn,obs-tq,obs-twl,sn,sq,ta,tn,tq,tw,twl,ugnt,uhb,ult,ust] - // - name: format + // - name: abbreviation + // in: query + // description: resource abbreviation (identifier). Multiple values are ORed. + // type: array + // collectionFormat: multi + // items: + // type: string // - name: format // in: query // description: content format (usfm, text, markdown, etc.). Multiple formats are ORed. // type: array @@ -289,6 +333,13 @@ func SearchOwner(ctx *context.APIContext) { // collectionFormat: multi // items: // type: string + // - name: metadata.* + // in: query + // description: You can specify key=value pairs where the key is prefixed with `metadata.`. The rest of the key will be used to search the metadata for the given value. Example: metadata.type.flavorType.flavor=textStory + // type: array + // collectionFormat: multi + // items: + // type: string // - name: partialMatch // in: query // description: if true, subject, owner and repo search fields will use partial match (LIKE) when querying the catalog. Default is false @@ -387,20 +438,39 @@ func SearchRepo(ctx *context.APIContext) { // enum: [prod,preprod,latest] // - name: subject // in: query - // description: search only for entries with the given subject(s). To match multiple, give the parameter multiple times or give a list comma delimited. Will perform an exact match (case insensitive) unlesss partialMatch=true + // description: resource subject. Multiple values are ORed. + // type: array + // collectionFormat: multi + // items: + // type: string + // - name: flavorType + // in: query + // description: resource flavorType. Multiple values are ORed. + // type: array + // collectionFormat: multi + // items: + // type: string + // - name: flavor + // in: query + // description: resource flavor. Multiple values are ORed. // type: array // collectionFormat: multi // items: // type: string - // enum: [Aligned Bible,Aramaic Grammar,Bible,Greek Grammar,Greek Lexicon,Greek New Testament,Hebrew Grammar,Hebrew Old Testament,Hebrew-Aramaic Lexicon,OBS Study Notes,OBS Study Questions,OBS Translation Notes,OBS Translation Questions,Open Bible Stories,Study Notes,Study Questions,Training Library,Translation Academy,Translation Notes,Translation Questions,Translation Words,TSV Study Notes,TSV Study Questions,TSV Translation Notes,TSV Translation Questions,TSV Translation Words Links,TSV OBS Study Notes,TSV OBS Study Questions,TSV OBS Translation Notes,TSV OBS Translation Questions,TSV OBS Translation Words Links] // - name: resource // in: query - // description: resource identifier. Multiple resources are ORed. + // description: resource identifier. Multiple values are ORed. + // type: array + // collectionFormat: multi + // items: + // type: string + // - name: abbreviation + // in: query + // description: resource abbreviation (identifier). Multiple values are ORed. // type: array // collectionFormat: multi // items: // type: string - // enum: [glt,gst,obs,obs-sn,obs-sq,obs-tn,obs-tq,obs-twl,sn,sq,ta,tn,tq,tw,twl,ugnt,uhb,ult,ust] // - name: format // in: query // description: content format (usfm, text, markdown, etc.). Multiple formats are ORed. @@ -438,6 +508,13 @@ func SearchRepo(ctx *context.APIContext) { // collectionFormat: multi // items: // type: string + // - name: metadata.* + // in: query + // description: You can specify key=value pairs where the key is prefixed with `metadata.`. The rest of the key will be used to search the metadata for the given value. Example: metadata.type.flavorType.flavor=textStory + // type: array + // collectionFormat: multi + // items: + // type: string // - name: partialMatch // in: query // description: if true, subject, owner and repo search fields will use partial match (LIKE) when querying the catalog. Default is false @@ -514,20 +591,39 @@ func ListCatalogSubjects(ctx *context.APIContext) { // enum: [prod,preprod,latest] // - name: subject // in: query - // description: list only the those if they are in the catalog meeting the criteria given (e.g. way to test a given language has the given subject) + // description: resource subject. Multiple values are ORed. + // type: array + // collectionFormat: multi + // items: + // type: string + // - name: flavorType + // in: query + // description: resource flavorType. Multiple values are ORed. + // type: array + // collectionFormat: multi + // items: + // type: string + // - name: flavor + // in: query + // description: resource flavor. Multiple values are ORed. // type: array // collectionFormat: multi // items: // type: string - // enum: [Aligned Bible,Aramaic Grammar,Bible,Greek Grammar,Greek Lexicon,Greek New Testament,Hebrew Grammar,Hebrew Old Testament,Hebrew-Aramaic Lexicon,OBS Study Notes,OBS Study Questions,OBS Translation Notes,OBS Translation Questions,Open Bible Stories,Study Notes,Study Questions,Training Library,Translation Academy,Translation Notes,Translation Questions,Translation Words,TSV Study Notes,TSV Study Questions,TSV Translation Notes,TSV Translation Questions,TSV Translation Words Links,TSV OBS Study Notes,TSV OBS Study Questions,TSV OBS Translation Notes,TSV OBS Translation Questions,TSV OBS Translation Words Links] // - name: resource // in: query - // description: list only those with the given resource identifier. Multiple resources are ORed. + // description: resource identifier. Multiple values are ORed. + // type: array + // collectionFormat: multi + // items: + // type: string + // - name: abbreviation + // in: query + // description: resource abbreviation (identifier). Multiple values are ORed. // type: array // collectionFormat: multi // items: // type: string - // enum: [glt,gst,obs,obs-sn,obs-sq,obs-tn,obs-tq,obs-twl,sn,sq,ta,tn,tq,tw,twl,ugnt,uhb,ult,ust] // - name: format // in: query // description: list only those with the given content format (usfm, text, markdown, etc.). Multiple formats are ORed. @@ -562,10 +658,6 @@ func ListCatalogSubjects(ctx *context.APIContext) { // collectionFormat: multi // items: // type: string - // - name: partialMatch - // in: query - // description: if true, owner, subject and language search fields will use partial match (LIKE) when querying the catalog. Default is false - // type: boolean // responses: // "200": // description: "SearchResults of a successful catalog owner search" @@ -629,20 +721,39 @@ func ListCatalogMetadataTypes(ctx *context.APIContext) { // enum: [prod,preprod,latest] // - name: subject // in: query - // description: list only the those if they are in the catalog meeting the criteria given (e.g. way to test a given language has the given subject) + // description: resource subject. Multiple values are ORed. + // type: array + // collectionFormat: multi + // items: + // type: string + // - name: flavorType + // in: query + // description: resource flavorType. Multiple values are ORed. + // type: array + // collectionFormat: multi + // items: + // type: string + // - name: flavor + // in: query + // description: resource flavor. Multiple values are ORed. // type: array // collectionFormat: multi // items: // type: string - // enum: [Aligned Bible,Aramaic Grammar,Bible,Greek Grammar,Greek Lexicon,Greek New Testament,Hebrew Grammar,Hebrew Old Testament,Hebrew-Aramaic Lexicon,OBS Study Notes,OBS Study Questions,OBS Translation Notes,OBS Translation Questions,Open Bible Stories,Study Notes,Study Questions,Training Library,Translation Academy,Translation Notes,Translation Questions,Translation Words,TSV Study Notes,TSV Study Questions,TSV Translation Notes,TSV Translation Questions,TSV Translation Words Links,TSV OBS Study Notes,TSV OBS Study Questions,TSV OBS Translation Notes,TSV OBS Translation Questions,TSV OBS Translation Words Links] // - name: resource // in: query - // description: list only those with the given resource identifier. Multiple resources are ORed. + // description: resource identifier. Multiple values are ORed. + // type: array + // collectionFormat: multi + // items: + // type: string + // - name: abbreviation + // in: query + // description: resource abbreviation (identifier). Multiple values are ORed. // type: array // collectionFormat: multi // items: // type: string - // enum: [glt,gst,obs,obs-sn,obs-sq,obs-tn,obs-tq,obs-twl,sn,sq,ta,tn,tq,tw,twl,ugnt,uhb,ult,ust] // - name: format // in: query // description: list only those with the given content format (usfm, text, markdown, etc.). Multiple formats are ORed. @@ -677,10 +788,6 @@ func ListCatalogMetadataTypes(ctx *context.APIContext) { // collectionFormat: multi // items: // type: string - // - name: partialMatch - // in: query - // description: if true, owner, subject and language search fields will use partial match (LIKE) when querying the catalog. Default is false - // type: boolean // responses: // "200": // description: "SearchResults of a successful catalog owner search" @@ -744,20 +851,39 @@ func ListCatalogOwners(ctx *context.APIContext) { // enum: [prod,preprod,latest] // - name: subject // in: query - // description: list only the those if they are in the catalog meeting the criteria given (e.g. way to test a given language has the given subject) + // description: resource subject. Multiple values are ORed. + // type: array + // collectionFormat: multi + // items: + // type: string + // - name: flavorType + // in: query + // description: resource flavorType. Multiple values are ORed. + // type: array + // collectionFormat: multi + // items: + // type: string + // - name: flavor + // in: query + // description: resource flavor. Multiple values are ORed. // type: array // collectionFormat: multi // items: // type: string - // enum: [Aligned Bible,Aramaic Grammar,Bible,Greek Grammar,Greek Lexicon,Greek New Testament,Hebrew Grammar,Hebrew Old Testament,Hebrew-Aramaic Lexicon,OBS Study Notes,OBS Study Questions,OBS Translation Notes,OBS Translation Questions,Open Bible Stories,Study Notes,Study Questions,Training Library,Translation Academy,Translation Notes,Translation Questions,Translation Words,TSV Study Notes,TSV Study Questions,TSV Translation Notes,TSV Translation Questions,TSV Translation Words Links,TSV OBS Study Notes,TSV OBS Study Questions,TSV OBS Translation Notes,TSV OBS Translation Questions,TSV OBS Translation Words Links] // - name: resource // in: query - // description: list only those with the given resource identifier. Multiple resources are ORed. + // description: resource identifier. Multiple values are ORed. + // type: array + // collectionFormat: multi + // items: + // type: string + // - name: abbreviation + // in: query + // description: resource abbreviation (identifier). Multiple values are ORed. // type: array // collectionFormat: multi // items: // type: string - // enum: [glt,gst,obs,obs-sn,obs-sq,obs-tn,obs-tq,obs-twl,sn,sq,ta,tn,tq,tw,twl,ugnt,uhb,ult,ust] // - name: format // in: query // description: list only those with the given content format (usfm, text, markdown, etc.). Multiple formats are ORed. @@ -792,6 +918,17 @@ func ListCatalogOwners(ctx *context.APIContext) { // collectionFormat: multi // items: // type: string + // - name: metadata.* + // in: query + // description: You can specify key=value pairs where the key is prefixed with `metadata.`. The rest of the key will be used to search the metadata for the given value. Example: metadata.type.flavorType.flavor=textStory + // type: array + // collectionFormat: multi + // items: + // type: string + // - name: partialMatch + // in: query + // description: If true, many of the above fields will do a partial match, allowing characters to come before or after your given value. Default: false + // type: boolean // responses: // "200": // description: "SearchResults of a successful catalog owner search" @@ -863,20 +1000,39 @@ func ListCatalogLanguages(ctx *context.APIContext) { // enum: [prod,preprod,latest] // - name: subject // in: query - // description: list only the those if they are in the catalog meeting the criteria given (e.g. way to test a given language has the given subject) + // description: resource subject. Multiple values are ORed. + // type: array + // collectionFormat: multi + // items: + // type: string + // - name: flavorType + // in: query + // description: resource flavorType. Multiple values are ORed. + // type: array + // collectionFormat: multi + // items: + // type: string + // - name: flavor + // in: query + // description: resource flavor. Multiple values are ORed. // type: array // collectionFormat: multi // items: // type: string - // enum: [Aligned Bible,Aramaic Grammar,Bible,Greek Grammar,Greek Lexicon,Greek New Testament,Hebrew Grammar,Hebrew Old Testament,Hebrew-Aramaic Lexicon,OBS Study Notes,OBS Study Questions,OBS Translation Notes,OBS Translation Questions,Open Bible Stories,Study Notes,Study Questions,Training Library,Translation Academy,Translation Notes,Translation Questions,Translation Words,TSV Study Notes,TSV Study Questions,TSV Translation Notes,TSV Translation Questions,TSV Translation Words Links,TSV OBS Study Notes,TSV OBS Study Questions,TSV OBS Translation Notes,TSV OBS Translation Questions,TSV OBS Translation Words Links] // - name: resource // in: query - // description: list only those with the given resource identifier. Multiple resources are ORed. + // description: resource identifier. Multiple values are ORed. + // type: array + // collectionFormat: multi + // items: + // type: string + // - name: abbreviation + // in: query + // description: resource abbreviation (identifier). Multiple values are ORed. // type: array // collectionFormat: multi // items: // type: string - // enum: [glt,gst,obs,obs-sn,obs-sq,obs-tn,obs-tq,obs-twl,sn,sq,ta,tn,tq,tw,twl,ugnt,uhb,ult,ust] // - name: format // in: query // description: list only those with the given content format (usfm, text, markdown, etc.). Multiple formats are ORed. @@ -911,6 +1067,17 @@ func ListCatalogLanguages(ctx *context.APIContext) { // collectionFormat: multi // items: // type: string + // - name: metadata.* + // in: query + // description: You can specify key=value pairs where the key is prefixed with `metadata.`. The rest of the key will be used to search the metadata for the given value. Example: metadata.type.flavorType.flavor=textStory + // type: array + // collectionFormat: multi + // items: + // type: string + // - name: partialMatch + // in: query + // description: If true, many of the above fields will do a partial match, allowing characters to come before or after your given value. Default: false + // type: boolean // responses: // "200": // description: "SearchResults of a successful catalog owner search" @@ -1081,6 +1248,13 @@ func searchCatalog(ctx *context.APIContext) { metadataTypes := QueryStrings(ctx, "metadataType") metadataVersions := QueryStrings(ctx, "metadataVersion") + metadataQueries := map[string][]string{} + for k := range ctx.Req.Form { + if strings.HasPrefix("metadata.", k) { + metadataQueries["$."+strings.TrimPrefix("metadata.", k)] = ctx.FormStrings(k) + } + } + keywords := []string{} query := strings.Trim(ctx.FormString("q"), " ") if query != "" { @@ -1113,6 +1287,7 @@ func searchCatalog(ctx *context.APIContext) { ShowIngredients: ctx.FormOptionalBool("showIngredients"), MetadataTypes: metadataTypes, MetadataVersions: metadataVersions, + MetadataQueries: metadataQueries, PartialMatch: ctx.FormBool("partialMatch"), } diff --git a/routers/api/v1/repo/repo.go b/routers/api/v1/repo/repo.go index 5a9782fea0..0baf3d5fee 100644 --- a/routers/api/v1/repo/repo.go +++ b/routers/api/v1/repo/repo.go @@ -103,15 +103,15 @@ func Search(ctx *context.APIContext) { // type: boolean // - name: repo // in: query - // description: name of the repo. Multiple repos are ORed. + // description: name of the repo. Multiple values are ORed. // type: string // - name: owner // in: query - // description: owner of the repo. Multiple owners are ORed. + // description: owner of the repo. Multiple values are ORed. // type: string // - name: lang // in: query - // description: if the repo is a resource of the given language(s), the repo will be in the results. Multiple langs are ORed. + // description: if the repo is a resource of the given language(s), the repo will be in the results. Multiple values are ORed. // type: array // collectionFormat: multi // items: @@ -122,28 +122,47 @@ func Search(ctx *context.APIContext) { // type: boolean // - name: subject // in: query - // description: resource subject. Multiple subjects are ORed. + // description: resource subject. Multiple values are ORed. + // type: array + // collectionFormat: multi + // items: + // type: string + // - name: flavorType + // in: query + // description: resource flavorType. Multiple values are ORed. + // type: array + // collectionFormat: multi + // items: + // type: string + // - name: flavor + // in: query + // description: resource flavor. Multiple values are ORed. // type: array // collectionFormat: multi // items: // type: string - // enum: [Aligned Bible,Aramaic Grammar,Bible,Greek Grammar,Greek Lexicon,Greek New Testament,Hebrew Grammar,Hebrew Old Testament,Hebrew-Aramaic Lexicon,OBS Study Notes,OBS Study Questions,OBS Translation Notes,OBS Translation Questions,Open Bible Stories,Study Notes,Study Questions,Training Library,Translation Academy,Translation Notes,Translation Questions,Translation Words,TSV Study Notes,TSV Study Questions,TSV Translation Notes,TSV Translation Questions,TSV Translation Words Links,TSV OBS Study Notes,TSV OBS Study Questions,TSV OBS Translation Notes,TSV OBS Translation Questions,TSV OBS Translation Words Links] // - name: resource // in: query - // description: resource identifier. Multiple resources are ORed. + // description: resource identifier. Multiple values are ORed. + // type: array + // collectionFormat: multi + // items: + // type: string + // - name: abbreviation + // in: query + // description: resource abbreviation (identifier). Multiple values are ORed. // type: array // collectionFormat: multi // items: // type: string - // enum: [glt,gst,obs,obs-sn,obs-sq,obs-tn,obs-tq,obs-twl,sn,sq,ta,tn,tq,tw,twl,ugnt,uhb,ult,ust] // - name: format // in: query - // description: content format (usfm, text, markdown, etc.). Multiple formats are ORed. + // description: content format (usfm, text, markdown, etc.). Multiple values are ORed. // type: string // - name: book // in: query // description: book (project id or ingredients id) that exist in a resource. If the resource contains the - // the book, its repository will be included in the results. Multiple books are ORed. + // the book, its repository will be included in the results. Multiple values are ORed. // type: array // collectionFormat: multi // items: @@ -163,6 +182,17 @@ func Search(ctx *context.APIContext) { // collectionFormat: multi // items: // type: string + // - name: metadata.* + // in: query + // description: You can specify key=value pairs where the key is prefixed with `metadata.`. The rest of the key will be used to search the metadata for the given value. Example: metadata.type.flavorType.flavor=textStory + // type: array + // collectionFormat: multi + // items: + // type: string + // - name: partialMatch + // in: query + // description: If true, many of the above fields will do a partial match, allowing characters to come before or after your given value. Default: false + // type: boolean // - name: sort // in: query // description: sort repos by attribute. Supported values are @@ -188,6 +218,13 @@ func Search(ctx *context.APIContext) { // "422": // "$ref": "#/responses/validationError" + metadataQueries := map[string][]string{} + for k := range ctx.Req.Form { + if strings.HasPrefix("metadata.", k) { + metadataQueries["$."+strings.TrimPrefix("metadata.", k)] = ctx.FormStrings(k) + } + } + opts := &repo_model.SearchRepoOptions{ ListOptions: utils.GetListOptions(ctx), Actor: ctx.Doer, @@ -206,12 +243,17 @@ func Search(ctx *context.APIContext) { Repos: catalog.QueryStrings(ctx, "repo"), Owners: catalog.QueryStrings(ctx, "owner"), Subjects: catalog.QueryStrings(ctx, "subject"), + FlavorTypes: catalog.QueryStrings(ctx, "flavorType"), + Flavors: catalog.QueryStrings(ctx, "flavor"), Resources: catalog.QueryStrings(ctx, "resource"), + Abbreviations: catalog.QueryStrings(ctx, "abbreviations"), ContentFormats: catalog.QueryStrings(ctx, "format"), Books: catalog.QueryStrings(ctx, "book"), MetadataTypes: catalog.QueryStrings(ctx, "metadataType"), MetadataVersions: catalog.QueryStrings(ctx, "metadataVersion"), LanguageIsGL: ctx.FormOptionalBool("is_gl"), + MetadataQueries: metadataQueries, + PartialMatch: ctx.FormBool("partialMatch"), /*** END DCS Customizations ***/ } diff --git a/services/door43metadata/door43metadata.go b/services/door43metadata/door43metadata.go index df16cdcbc8..235671d90e 100644 --- a/services/door43metadata/door43metadata.go +++ b/services/door43metadata/door43metadata.go @@ -9,6 +9,7 @@ import ( "fmt" "io" "net/http" + "path/filepath" "regexp" "strconv" "strings" @@ -223,21 +224,24 @@ func GetBookAlignmentCount(bookPath string, commit *git.Commit) (int, error) { } // GetBooks get the books of the manifest -func GetBooks(manifest *map[string]interface{}) []string { +func GetBooks(manifest map[string]interface{}) []string { var books []string - if len((*manifest)["projects"].([]interface{})) > 0 { - for _, prod := range (*manifest)["projects"].([]interface{}) { + if len((manifest)["projects"].([]interface{})) > 0 { + for _, prod := range (manifest)["projects"].([]interface{}) { books = append(books, prod.(map[string]interface{})["identifier"].(string)) } } return books } -func GetDoor43MetadataFromRCManifest(dm *repo_model.Door43Metadata, manifest *map[string]interface{}, repo *repo_model.Repository, commit *git.Commit) error { +func GetDoor43MetadataFromRCManifest(dm *repo_model.Door43Metadata, manifest map[string]interface{}, repo *repo_model.Repository, commit *git.Commit) error { var metadataType string var metadataVersion string var subject string + var flavorType string + var flavor string var resource string + var abbreviation string var title string var language string var languageTitle string @@ -249,7 +253,7 @@ func GetDoor43MetadataFromRCManifest(dm *repo_model.Door43Metadata, manifest *ma var ingredients []*structs.Ingredient re := regexp.MustCompile("^([^0-9]+)(.*)$") - matches := re.FindStringSubmatch((*manifest)["dublin_core"].(map[string]interface{})["conformsto"].(string)) + matches := re.FindStringSubmatch(manifest["dublin_core"].(map[string]interface{})["conformsto"].(string)) if len(matches) == 3 { metadataType = matches[1] metadataVersion = matches[2] @@ -258,16 +262,17 @@ func GetDoor43MetadataFromRCManifest(dm *repo_model.Door43Metadata, manifest *ma metadataType = "rc" metadataVersion = "0.2" } - subject = (*manifest)["dublin_core"].(map[string]interface{})["subject"].(string) - resource = (*manifest)["dublin_core"].(map[string]interface{})["identifier"].(string) - title = (*manifest)["dublin_core"].(map[string]interface{})["title"].(string) - language = (*manifest)["dublin_core"].(map[string]interface{})["language"].(map[string]interface{})["identifier"].(string) - languageTitle = (*manifest)["dublin_core"].(map[string]interface{})["language"].(map[string]interface{})["title"].(string) - format = (*manifest)["dublin_core"].(map[string]interface{})["format"].(string) + subject = manifest["dublin_core"].(map[string]interface{})["subject"].(string) + resource = manifest["dublin_core"].(map[string]interface{})["identifier"].(string) + abbreviation = resource + title = manifest["dublin_core"].(map[string]interface{})["title"].(string) + language = manifest["dublin_core"].(map[string]interface{})["language"].(map[string]interface{})["identifier"].(string) + languageTitle = manifest["dublin_core"].(map[string]interface{})["language"].(map[string]interface{})["title"].(string) + format = manifest["dublin_core"].(map[string]interface{})["format"].(string) languageDirection = dcs.GetLanguageDirection(language) languageIsGL = dcs.LanguageIsGL(language) var bookPath string - for _, prod := range (*manifest)["projects"].([]interface{}) { + for _, prod := range manifest["projects"].([]interface{}) { if prodMap, ok := prod.(map[string]interface{}); ok { ingredient := convert.ToIngredient(prodMap) book := ingredient.Identifier @@ -283,23 +288,35 @@ func GetDoor43MetadataFromRCManifest(dm *repo_model.Door43Metadata, manifest *ma } if subject == "Bible" || subject == "Aligned Bible" || subject == "Greek New Testament" || subject == "Hebrew Old Testament" { contentFormat = "usfm" + flavorType = "scripture" + flavor = "textTranslation" } else if strings.HasPrefix(subject, "TSV ") { if strings.HasPrefix(fmt.Sprintf("./%s_", resource), bookPath) { contentFormat = "tsv7" } else { contentFormat = "tsv9" } - } else if strings.Contains(format, "/") { - contentFormat = strings.Split(format, "/")[1] - } else if repo.PrimaryLanguage != nil { - contentFormat = strings.ToLower(repo.PrimaryLanguage.Language) - } else { + flavorType = "parascriptural" + flavor = "x-" + strings.Replace(strings.TrimPrefix("TSV ", subject), " ", "", -1) + } else if subject == "Open Bible Stories" { contentFormat = "markdown" + flavorType = "gloss" + flavor = "textStories" + } else { + if strings.Contains(format, "/") { + contentFormat = strings.Split(format, "/")[1] + } else if repo.PrimaryLanguage != nil { + contentFormat = strings.ToLower(repo.PrimaryLanguage.Language) + } else { + contentFormat = "markdown" + } + flavor = "gloss" + flavor = "x-" + strings.Replace(subject, " ", "", -1) } var ok bool - checkingLevel, ok = (*manifest)["checking"].(map[string]interface{})["checking_level"].(int) + checkingLevel, ok = manifest["checking"].(map[string]interface{})["checking_level"].(int) if !ok { - cL, ok := (*manifest)["checking"].(map[string]interface{})["checking_level"].(string) + cL, ok := manifest["checking"].(map[string]interface{})["checking_level"].(string) if !ok { checkingLevel = 1 } else { @@ -315,8 +332,11 @@ func GetDoor43MetadataFromRCManifest(dm *repo_model.Door43Metadata, manifest *ma dm.MetadataType = metadataType dm.MetadataVersion = metadataVersion dm.Subject = subject + dm.FlavorType = flavorType + dm.Flavor = flavor dm.Title = title dm.Resource = resource + dm.Abbreviation = abbreviation dm.Language = language dm.LanguageTitle = languageTitle dm.LanguageDirection = languageDirection @@ -333,8 +353,11 @@ func GetDoor43MetadataFromRCManifest(dm *repo_model.Door43Metadata, manifest *ma func GetDoor43MetadataFromSBMetadata(dm *repo_model.Door43Metadata, sbMetadata *dcs.SBMetadata100, repo *repo_model.Repository, commit *git.Commit) error { var metadataType string var metadataVersion string - subject := "unknown" + var subject string + var flavorType string + var flavor string var resource string + var abbreviation string var title string var language string var languageTitle string @@ -346,23 +369,68 @@ func GetDoor43MetadataFromSBMetadata(dm *repo_model.Door43Metadata, sbMetadata * metadataType = "sb" metadataVersion = sbMetadata.Meta.Version - title = sbMetadata.Identification.Name.En + title = sbMetadata.Identification.Name.DetermineLocalizedTextToUse() + flavorType = sbMetadata.Type.FlavorType.Name + flavor = sbMetadata.Type.FlavorType.Flavor.Name switch sbMetadata.Type.FlavorType.Name { case "scripture": - subject = "Bible" - resource = strings.ToLower(sbMetadata.Identification.Abbreviation.En) - contentFormat = "usfm" - if sbMetadata.LocalizedNames != nil { - for book, ln := range *sbMetadata.LocalizedNames { - bookPath := "./ingredients/" + book + ".usfm" - count, _ := GetBookAlignmentCount(bookPath, commit) + if strings.HasPrefix("x-", flavor) { + subject = strings.ToTitle(strings.TrimPrefix("x-", flavor)) + } else if flavor == "textTranslation" { + subject = "Bible" + } else { + subject = flavor + } + resource = strings.ToLower(sbMetadata.Identification.Abbreviation.DetermineLocalizedTextToUse()) + abbreviation = resource + var contentFormat string + if sbMetadata.Ingredients != nil { + for filePath, ingredient := range sbMetadata.Ingredients { + if ingredient.Scope != nil && len(*ingredient.Scope) > 0 { + bookID := ingredient.Scope.GetBookID() + var ln *dcs.SB100LocalizedName + if value, ok := sbMetadata.LocalizedNames[bookID]; ok { + ln = &value + } + if ln == nil { + continue + } + filePath = "./" + filePath + count := 0 + if strings.HasSuffix(".usfm", filePath) { + count, _ = GetBookAlignmentCount(filePath, commit) + if count > 0 && subject == "Bible" { + subject = "Aligned Bible" + } + contentFormat = "usfm" + } else if contentFormat == "" { + contentFormat = strings.TrimPrefix(".", filepath.Ext(filePath)) + } + ingredients = append(ingredients, &structs.Ingredient{ + Categories: dcs.GetBookCategories(bookID), + Identifier: bookID, + Title: ln.Short.DetermineLocalizedTextToUse(), + Path: filePath, + Sort: dcs.GetBookSort(bookID), + AlignmentCount: &count, + }) + } + } + } else if sbMetadata.LocalizedNames != nil { + contentFormat = "usfm" + for bookID, localizedName := range sbMetadata.LocalizedNames { + filePath := "./ingredients/" + bookID + ".usfm" + count, _ := GetBookAlignmentCount(filePath, commit) + if count > 0 { + subject = "Aligned Bible" + } ingredients = append(ingredients, &structs.Ingredient{ - Categories: dcs.GetBookCategories(book), - Identifier: book, - Title: ln.Short.En, - Path: bookPath, - Sort: dcs.GetBookSort(book), + Categories: dcs.GetBookCategories(bookID), + Identifier: bookID, + Title: localizedName.Short.DetermineLocalizedTextToUse(), + Path: filePath, + Sort: dcs.GetBookSort(bookID), AlignmentCount: &count, }) } @@ -385,7 +453,7 @@ func GetDoor43MetadataFromSBMetadata(dm *repo_model.Door43Metadata, sbMetadata * language = sbMetadata.Languages[0].Tag languageTitle = dcs.GetLanguageTitle(language) if languageTitle == "" { - languageTitle = sbMetadata.Languages[0].Name.En + languageTitle = sbMetadata.Languages[0].Name.DetermineLocalizedTextToUse() } languageDirection = dcs.GetLanguageDirection(language) languageIsGL = dcs.LanguageIsGL(language) @@ -395,8 +463,11 @@ func GetDoor43MetadataFromSBMetadata(dm *repo_model.Door43Metadata, sbMetadata * dm.MetadataType = metadataType dm.MetadataVersion = metadataVersion dm.Subject = subject + dm.FlavorType = flavorType + dm.Flavor = flavor dm.Title = title dm.Resource = resource + dm.Abbreviation = abbreviation dm.Language = language dm.LanguageTitle = languageTitle dm.LanguageDirection = languageDirection @@ -410,7 +481,7 @@ func GetDoor43MetadataFromSBMetadata(dm *repo_model.Door43Metadata, sbMetadata * } func GetRCDoor43Metadata(dm *repo_model.Door43Metadata, repo *repo_model.Repository, commit *git.Commit) error { - var manifest *map[string]interface{} + var manifest map[string]interface{} blob, err := commit.GetBlobByPath("manifest.yaml") if err != nil { @@ -503,7 +574,7 @@ func GetTcOrTsDoor43Metadata(dm *repo_model.Door43Metadata, repo *repo_model.Rep } func GetSBDoor43Metadata(dm *repo_model.Door43Metadata, repo *repo_model.Repository, commit *git.Commit) error { - var metadata *map[string]interface{} + var metadata map[string]interface{} blob, err := commit.GetBlobByPath("metadata.json") if err != nil {