Skip to content

Commit

Permalink
feat: Inferrence of variables now uses org- and project-vars for exam…
Browse files Browse the repository at this point in the history
…ples
  • Loading branch information
Runar Kristoffersen committed Apr 18, 2022
1 parent 049c795 commit 6f6f831
Show file tree
Hide file tree
Showing 8 changed files with 223 additions and 47 deletions.
3 changes: 2 additions & 1 deletion bboltStorage/migrate.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ func (bb *BBolter) Migrate(hooks ...func(state types.State, wantedMigrationPoint
}
for {
l := bb.l.With().
Str("sub-label", "migration").
Interface("state", state).
Int("wanted-migration-point", wantedMigrationPoint).
Logger()
Expand Down Expand Up @@ -93,7 +94,7 @@ func (bb *BBolter) Migrate(hooks ...func(state types.State, wantedMigrationPoint
}

for i, hook := range hooks {
l.Debug().Int("hook_no", i).Int("total", len(hooks)).Msg("Running hook")
l.Debug().Int("hook-no", i).Int("total-hooks", len(hooks)).Msg("Running migration-hook")
err := hook(*state, wantedMigrationPoint)
if err != nil {
return *state, err
Expand Down
54 changes: 32 additions & 22 deletions bboltStorage/project.go
Original file line number Diff line number Diff line change
Expand Up @@ -166,34 +166,44 @@ func (bb *BBolter) GetProjectByShortName(shortName string) (*types.Project, erro
}

func (bb *BBolter) GetProjectFilter(filter ...types.Project) (*types.Project, error) {
var u *types.Project
err := bb.Iterate(BucketProject, func(key, b []byte) bool {
var uu types.Project
err := bb.Unmarshal(b, &uu)
if err != nil {
bb.l.Error().Err(err).Msg("failed to unmarshal user")
return false
}
return FindOne(bb, BucketProject, func(t types.Project) bool {
for _, f := range filter {
if f.ID != "" && f.ID != uu.ID {
continue
if f.OrganizationID == "" {
bb.l.Warn().Msg("Received a user-filter without organization-id")
}
if f.ShortName != "" && f.ShortName != uu.ShortName {
continue
if projectFilter(f, t) {
return true
}
if f.Description != "" && f.Description != uu.Description {
continue
}
u = &uu
return true
}
return false
})
if err != nil {
if err == ErrNotFound {
return nil, nil
}
func (bb *BBolter) FindProjects(max int, filter ...types.Project) (map[string]types.Project, error) {
return Find(bb, BucketProject, max, func(uu types.Project) bool {
if len(filter) == 0 {
return true
}
return nil, err
for _, f := range filter {
if projectFilter(f, uu) {
return true
}
}
return false
})
}

func projectFilter(f, uu types.Project) bool {
if f.OrganizationID != "" && f.OrganizationID != uu.OrganizationID {
return false
}
if f.ID != "" && f.ID != uu.ID {
return false
}
if f.ShortName != "" && f.ShortName != uu.ShortName {
return false
}
if f.ID != "" && f.ID != uu.ID {
return false
}
return u, err
return true
}
33 changes: 29 additions & 4 deletions handlers/apiHandler.go
Original file line number Diff line number Diff line change
Expand Up @@ -574,6 +574,12 @@ func EndpointsHandler(
rc.WriteErr(err, requestContext.CodeErrTranslation)
return
}
p, err := t.GetProject(ctx.DB)
if err != nil {
ctx.L.Error().Err(err).Msg("Project was not found for translation")
rc.WriteErr(err, requestContext.CodeErrTranslation)
return
}
if t == nil {
rc.WriteErr(ErrApiNotFound("Translation", tv.TranslationID), "")
}
Expand All @@ -588,11 +594,16 @@ func EndpointsHandler(
rc.WriteErr(ErrApiDatabase("translation", err), "translation")
return
}
o, err := importexport.CreateInterpolationMapForOrganization(ctx.DB, session.Organization.ID)
if err != nil {
ctx.L.Error().Err(err).Msg("Failed during CreateInterpolationMapForOrganization")
}
_, err = UpdateTranslationFromInferrence(
ctx.DB,
et,
[]AdditionalValue{
{Value: tv.Value, LocaleID: tv.LocaleID}},
o.ByProject(p.ID),
)
if err != nil {
ctx.L.Error().Err(err).Msg("Failed in updateTranslationFromInferrence")
Expand Down Expand Up @@ -640,6 +651,12 @@ func EndpointsHandler(
if t == nil {
rc.WriteErr(ErrApiNotFound("Translation", exTV.TranslationID), "")
}
p, err := t.GetProject(ctx.DB)
if err != nil {
ctx.L.Error().Err(err).Msg("Project was not found for translation")
rc.WriteErr(err, requestContext.CodeErrTranslation)
return
}
et, err := t.Extend(ctx.DB)
if err != nil {
rc.WriteErr(err, requestContext.CodeErrTranslation)
Expand All @@ -650,10 +667,18 @@ func EndpointsHandler(
rc.WriteErr(ErrApiDatabase("translation", err), "translation")
return
}
o, err := importexport.CreateInterpolationMapForOrganization(ctx.DB, session.Organization.ID)
if err != nil {
ctx.L.Error().Err(err).Msg("Failed during CreateInterpolationMapForOrganization")
}
_, err = UpdateTranslationFromInferrence(
ctx.DB, et, []AdditionalValue{
ctx.DB,
et,
[]AdditionalValue{
{Value: tv.Value, LocaleID: exTV.LocaleID, Context: j.ContextKey},
})
},
o.ByProject(p.ID),
)
if err != nil {
ctx.L.Error().Err(err).Msg("Failed in updateTranslationFromInferrence")
}
Expand Down Expand Up @@ -718,7 +743,7 @@ type AdditionalValue struct {
// The additionalValues are meant to be new values to consider for inferrence.
// If the Translation already has a value for the same LocaleID/Context as an additionalValue,
// the existing value will not be considered.
func UpdateTranslationFromInferrence(db types.Storage, et types.ExtendedTranslation, additionalValues []AdditionalValue) (*types.Translation, error) {
func UpdateTranslationFromInferrence(db types.Storage, et types.ExtendedTranslation, additionalValues []AdditionalValue, interpolationMaps []map[string]interface{}) (*types.Translation, error) {
var allValues []string

for _, v := range et.Values {
Expand Down Expand Up @@ -757,7 +782,7 @@ func UpdateTranslationFromInferrence(db types.Storage, et types.ExtendedTranslat
allValues = append(allValues, av.Value)
}
// Check if we can infer some more variables/refs, and if can, we may need to update the Translation.
_, variables, refs := importexport.InferVariablesFromMultiple(allValues, "???", et.ID)
_, variables, refs := importexport.InferVariablesFromMultiple(allValues, "???", et.ID, interpolationMaps)
if len(variables) == 0 && len(refs) == 0 {
return nil, nil
}
Expand Down
127 changes: 113 additions & 14 deletions importexport/import.go
Original file line number Diff line number Diff line change
Expand Up @@ -178,7 +178,7 @@ func translationFromNode(t *types.ExtendedTranslation, key string, base types.Pr

tv.CreatedBy = base.CreatedBy
tv.OrganizationID = base.OrganizationID
w, variables, refs := InferVariables(value, categoryKey, t.Key)
w, variables, refs := InferVariables(value, categoryKey, t.Key, []map[string]interface{}{interpolator.DefaultInterpolationExamples})
if len(w) != 0 {
warnings = append(warnings, w...)
}
Expand Down Expand Up @@ -241,13 +241,110 @@ var (
inferVariablesRegex = regexp.MustCompile(`{{\s*([^\s,}]*)[^}]*}}`)
)

func InferVariablesFromMultiple(translationValues []string, category, translation string) ([]Warning, map[string]interface{}, []string) {
type orgInterpolatorMap struct {
mapsByProject map[string]map[string]interface{}
orgMap map[string]interface{}
}

func (o orgInterpolatorMap) ForOrganization() []map[string]interface{} {
var m []map[string]interface{}
if len(o.orgMap) > 0 {
m = append(m, o.orgMap)
}
m = append(m, interpolator.DefaultInterpolationExamples)
return m

}
func (o orgInterpolatorMap) ByProject(id string) []map[string]interface{} {
var m []map[string]interface{}
// If there are zero or one projects, we don't want to use the projectMap,
// since it would be equal to the orgMap.
if len(o.mapsByProject) >= 2 {
projectMap := o.mapsByProject[id]
if len(projectMap) > 0 {
m = append(m, projectMap)
}
}
if len(o.orgMap) > 0 {
m = append(m, o.orgMap)
}

m = append(m, interpolator.DefaultInterpolationExamples)
return m
}

// Creates an prioritized interpolationmap from an organization
func CreateInterpolationMapForOrganization(db types.Storage, orgID string) (orgInterpolatorMap, error) {
if orgID == "" {
return orgInterpolatorMap{}, fmt.Errorf("Missing orgID")
}
o := orgInterpolatorMap{
orgMap: map[string]interface{}{},
mapsByProject: map[string]map[string]interface{}{},
}
projectFilter := types.Project{}
projectFilter.OrganizationID = orgID

projects, err := db.FindProjects(0, projectFilter)
if err != nil {
return o, err
}
hasMultipleProjects := len(projects) >= 0

catFilter := types.CategoryFilter{}
catFilter.OrganizationID = orgID
var categories map[string]types.Category
if hasMultipleProjects {
cs, err := db.FindCategories(0, catFilter)
if err != nil {
return o, err
}
categories = cs

}
whichProject := func(t types.Translation) string {
c, ok := categories[t.CategoryID]
if !ok {
return ""
}
return c.ProjectID
}

filter := types.Translation{}
filter.OrganizationID = orgID
pt, err := db.GetTranslationsFilter(0, filter)
if err != nil {
return o, err
}
for _, t := range pt {
if t.Variables == nil {
continue
}
pid := whichProject(t)
for k, v := range t.Variables {
if v == "" || v == "???" {
continue
}
o.orgMap[k] = v
if pid != "" {
if _, ok := o.mapsByProject[pid]; ok {
o.mapsByProject[pid][k] = v
} else {
o.mapsByProject[pid] = map[string]interface{}{k: v}
}
}
}
}
return o, nil
}

func InferVariablesFromMultiple(translationValues []string, category, translation string, interpolationMaps []map[string]interface{}) ([]Warning, map[string]interface{}, []string) {
w := []Warning{}
variables := make(map[string]interface{})
refs := []string{}

for _, v := range translationValues {
wx, vx, rx := InferVariables(v, category, translation)
wx, vx, rx := InferVariables(v, category, translation, interpolationMaps)
w = append(w, wx...)
loop_rx:
for _, r := range rx {
Expand All @@ -271,7 +368,7 @@ func InferVariablesFromMultiple(translationValues []string, category, translatio
return w, variables, refs

}
func InferVariables(translationValue, category, translation string) ([]Warning, map[string]interface{}, []string) {
func InferVariables(translationValue, category, translation string, interpolationMaps []map[string]interface{}) ([]Warning, map[string]interface{}, []string) {
w := []Warning{}
variables := make(map[string]interface{})
refs := []string{}
Expand All @@ -283,7 +380,7 @@ func InferVariables(translationValue, category, translation string) ([]Warning,
if len(v) < 2 {
continue
}
variables[v[1]] = getValueForVariableKey(v[1])
variables[v[1]] = getValueForVariableKey(v[1], interpolationMaps)

}
}
Expand Down Expand Up @@ -334,7 +431,7 @@ func InferVariables(translationValue, category, translation string) ([]Warning,
if _, ok := variables[key]; ok {
continue
}
variables[key] = getValueForVariableKey(key)
variables[key] = getValueForVariableKey(key, interpolationMaps)
}

}
Expand Down Expand Up @@ -391,7 +488,7 @@ func InferVariables(translationValue, category, translation string) ([]Warning,
continue

}
variables[key] = getValueForVariableKey(key)
variables[key] = getValueForVariableKey(key, interpolationMaps)
}
}
sort.Strings(refs)
Expand Down Expand Up @@ -550,14 +647,16 @@ func ImportI18NTranslation(
}
return &imp, w, nil
}
func getValueForVariableKey(key string) interface{} {
func getValueForVariableKey(key string, interpolationMaps []map[string]interface{}) interface{} {
key = strings.ToLower(key)
if val, ok := interpolator.DefaultInterpolationExamples[key]; ok {
return val
}
for k, v := range interpolator.DefaultInterpolationExamples {
if strings.HasSuffix(key, k) {
return v
for _, m := range interpolationMaps {
if val, ok := m[key]; ok {
return val
}
for k, v := range m {
if strings.HasSuffix(key, k) {
return v
}
}
}
return "???"
Expand Down
24 changes: 18 additions & 6 deletions main.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ import (
cfg "github.com/runar-rkmedia/skiver/config"
"github.com/runar-rkmedia/skiver/frontend"
"github.com/runar-rkmedia/skiver/handlers"
"github.com/runar-rkmedia/skiver/importexport"
"github.com/runar-rkmedia/skiver/localuser"
"github.com/runar-rkmedia/skiver/models"
"github.com/runar-rkmedia/skiver/requestContext"
Expand Down Expand Up @@ -380,18 +381,29 @@ func main() {
func(state types.State, wantedMigrationPoint int) error {
if state.MigrationPoint == 0 {

projects, err := db.GetProjects()
orgs, err := db.GetOrganizations()
if err != nil {
return err
}
for _, p := range projects {
ep, err := p.Extend(&db)
for _, org := range orgs {

o, err := importexport.CreateInterpolationMapForOrganization(&db, org.ID)
if err != nil {
return err
}
projects, err := db.GetProjects()
if err != nil {
return err
}
for _, ec := range ep.Categories {
for _, et := range ec.Translations {
handlers.UpdateTranslationFromInferrence(&db, et, []handlers.AdditionalValue{})
for _, p := range projects {
ep, err := p.Extend(&db)
if err != nil {
return err
}
for _, ec := range ep.Categories {
for _, et := range ec.Translations {
handlers.UpdateTranslationFromInferrence(&db, et, []handlers.AdditionalValue{}, o.ByProject(p.ID))
}
}
}
}
Expand Down
Loading

0 comments on commit 6f6f831

Please sign in to comment.