diff --git a/automation/service/access_control.gen.go b/automation/service/access_control.gen.go index f71c7a3e5..cf82ddf98 100644 --- a/automation/service/access_control.gen.go +++ b/automation/service/access_control.gen.go @@ -117,6 +117,11 @@ func (svc accessControl) List() (out []map[string]string) { "any": types.ComponentRbacResource(), "op": "workflows.search", }, + { + "type": types.ComponentResourceType, + "any": types.ComponentRbacResource(), + "op": "resource-translations.manage", + }, } func(svc interface{}) { @@ -263,6 +268,13 @@ func (svc accessControl) CanSearchWorkflows(ctx context.Context) bool { return svc.can(ctx, "workflows.search", &types.Component{}) } +// CanManageResourceTranslations checks if current user can list, search, create, or update resource translations +// +// This function is auto-generated +func (svc accessControl) CanManageResourceTranslations(ctx context.Context) bool { + return svc.can(ctx, "resource-translations.manage", &types.Component{}) +} + // rbacResourceValidator validates known component's resource by routing it to the appropriate validator // // This function is auto-generated @@ -294,11 +306,12 @@ func rbacResourceOperations(r string) map[string]bool { } case types.ComponentResourceType: return map[string]bool{ - "grant": true, - "workflow.create": true, - "triggers.search": true, - "sessions.search": true, - "workflows.search": true, + "grant": true, + "workflow.create": true, + "triggers.search": true, + "sessions.search": true, + "workflows.search": true, + "resource-translations.manage": true, } } diff --git a/automation/service/locale.gen.go b/automation/service/locale.gen.go index d39c7f036..510fc74df 100644 --- a/automation/service/locale.gen.go +++ b/automation/service/locale.gen.go @@ -11,10 +11,12 @@ package service import ( "context" + "github.com/cortezaproject/corteza-server/automation/types" "github.com/cortezaproject/corteza-server/pkg/actionlog" intAuth "github.com/cortezaproject/corteza-server/pkg/auth" + "github.com/cortezaproject/corteza-server/pkg/errors" "github.com/cortezaproject/corteza-server/pkg/locale" "github.com/cortezaproject/corteza-server/store" systemTypes "github.com/cortezaproject/corteza-server/system/types" @@ -29,7 +31,7 @@ type ( } localeAccessController interface { - // CanManageResourceTranslation(context.Context) bool + CanManageResourceTranslations(context.Context) bool } ResourceTranslationsManagerService interface { @@ -40,6 +42,8 @@ type ( } ) +var ErrNotAllowedToManageResourceTranslations = errors.Unauthorized("not allowed to manage resource translations") + func ResourceTranslationsManager(ls locale.Resource) *resourceTranslationsManager { return &resourceTranslationsManager{ actionlog: DefaultActionlog, @@ -50,10 +54,15 @@ func ResourceTranslationsManager(ls locale.Resource) *resourceTranslationsManage } func (svc resourceTranslationsManager) Upsert(ctx context.Context, rr locale.ResourceTranslationSet) (err error) { - // @todo AC - //if (!svc.ac.CanManageResourceTranslation(ctx)) { - // return *****ErrNotAllowedToCreate() - //} + // User is allowed to manage resource translations when: + // - managed resource translation strings are all for default language + // or + // - user is allowed to manage resource translations + if rr.ContainsForeign(svc.Locale().Default().Tag) { + if !svc.ac.CanManageResourceTranslations(ctx) { + return ErrNotAllowedToManageResourceTranslations + } + } // @todo validation diff --git a/compose/service/access_control.gen.go b/compose/service/access_control.gen.go index 1223df014..ad891f7c6 100644 --- a/compose/service/access_control.gen.go +++ b/compose/service/access_control.gen.go @@ -217,6 +217,11 @@ func (svc accessControl) List() (out []map[string]string) { "any": types.ComponentRbacResource(), "op": "namespaces.search", }, + { + "type": types.ComponentResourceType, + "any": types.ComponentRbacResource(), + "op": "resource-translations.manage", + }, } func(svc interface{}) { @@ -496,6 +501,13 @@ func (svc accessControl) CanSearchNamespaces(ctx context.Context) bool { return svc.can(ctx, "namespaces.search", &types.Component{}) } +// CanManageResourceTranslations checks if current user can list, search, create, or update resource translations +// +// This function is auto-generated +func (svc accessControl) CanManageResourceTranslations(ctx context.Context) bool { + return svc.can(ctx, "resource-translations.manage", &types.Component{}) +} + // rbacResourceValidator validates known component's resource by routing it to the appropriate validator // // This function is auto-generated @@ -571,11 +583,12 @@ func rbacResourceOperations(r string) map[string]bool { } case types.ComponentResourceType: return map[string]bool{ - "grant": true, - "settings.read": true, - "settings.manage": true, - "namespace.create": true, - "namespaces.search": true, + "grant": true, + "settings.read": true, + "settings.manage": true, + "namespace.create": true, + "namespaces.search": true, + "resource-translations.manage": true, } } diff --git a/compose/service/locale.gen.go b/compose/service/locale.gen.go index d1376c1f7..fc5e4db1d 100644 --- a/compose/service/locale.gen.go +++ b/compose/service/locale.gen.go @@ -14,10 +14,12 @@ package service import ( "context" + "github.com/cortezaproject/corteza-server/compose/types" "github.com/cortezaproject/corteza-server/pkg/actionlog" intAuth "github.com/cortezaproject/corteza-server/pkg/auth" + "github.com/cortezaproject/corteza-server/pkg/errors" "github.com/cortezaproject/corteza-server/pkg/locale" "github.com/cortezaproject/corteza-server/store" systemTypes "github.com/cortezaproject/corteza-server/system/types" @@ -32,7 +34,7 @@ type ( } localeAccessController interface { - // CanManageResourceTranslation(context.Context) bool + CanManageResourceTranslations(context.Context) bool } ResourceTranslationsManagerService interface { @@ -46,6 +48,8 @@ type ( } ) +var ErrNotAllowedToManageResourceTranslations = errors.Unauthorized("not allowed to manage resource translations") + func ResourceTranslationsManager(ls locale.Resource) *resourceTranslationsManager { return &resourceTranslationsManager{ actionlog: DefaultActionlog, @@ -56,10 +60,15 @@ func ResourceTranslationsManager(ls locale.Resource) *resourceTranslationsManage } func (svc resourceTranslationsManager) Upsert(ctx context.Context, rr locale.ResourceTranslationSet) (err error) { - // @todo AC - //if (!svc.ac.CanManageResourceTranslation(ctx)) { - // return *****ErrNotAllowedToCreate() - //} + // User is allowed to manage resource translations when: + // - managed resource translation strings are all for default language + // or + // - user is allowed to manage resource translations + if rr.ContainsForeign(svc.Locale().Default().Tag) { + if !svc.ac.CanManageResourceTranslations(ctx) { + return ErrNotAllowedToManageResourceTranslations + } + } // @todo validation diff --git a/compose/service/service.go b/compose/service/service.go index db05a6a1b..75fb20e80 100644 --- a/compose/service/service.go +++ b/compose/service/service.go @@ -99,8 +99,8 @@ func Initialize(ctx context.Context, log *zap.Logger, s store.Storer, c Config) DefaultActionlog = actionlog.NewService(DefaultStore, log, tee, policy) } - DefaultResourceTranslation = ResourceTranslationsManager(locale.Global()) DefaultAccessControl = AccessControl() + DefaultResourceTranslation = ResourceTranslationsManager(locale.Global()) if DefaultObjectStore == nil { const svcPath = "compose" diff --git a/def/automation.yaml b/def/automation.yaml index c3595f1a9..94c8974b9 100644 --- a/def/automation.yaml +++ b/def/automation.yaml @@ -16,3 +16,6 @@ rbac: workflows.search: description: List, search or filter workflows + + resource-translations.manage: + description: List, search, create, or update resource translations diff --git a/def/compose.yaml b/def/compose.yaml index 284169a8f..271a509f2 100644 --- a/def/compose.yaml +++ b/def/compose.yaml @@ -14,3 +14,6 @@ rbac: description: Create namespace namespaces.search: description: List, search or filter namespaces + + resource-translations.manage: + description: List, search, create, or update resource translations diff --git a/def/system.yaml b/def/system.yaml index 5abaae81e..3fa71f29a 100644 --- a/def/system.yaml +++ b/def/system.yaml @@ -65,5 +65,5 @@ rbac: apigw-filters.search: description: List, search or filter API gateway filters - resource-translation.Manage: - description: List, search, create, or update resource translations \ No newline at end of file + resource-translations.manage: + description: List, search, create, or update resource translations diff --git a/pkg/codegen-v3/assets/templates/gocode/locale/service.go.tpl b/pkg/codegen-v3/assets/templates/gocode/locale/service.go.tpl index e1d8822cb..a85e194d4 100644 --- a/pkg/codegen-v3/assets/templates/gocode/locale/service.go.tpl +++ b/pkg/codegen-v3/assets/templates/gocode/locale/service.go.tpl @@ -12,6 +12,7 @@ import ( "github.com/cortezaproject/corteza-server/pkg/actionlog" intAuth "github.com/cortezaproject/corteza-server/pkg/auth" + "github.com/cortezaproject/corteza-server/pkg/errors" "github.com/cortezaproject/corteza-server/pkg/locale" "github.com/cortezaproject/corteza-server/store" systemTypes "github.com/cortezaproject/corteza-server/system/types" @@ -26,7 +27,7 @@ type ( } localeAccessController interface { - // CanManageResourceTranslation(context.Context) bool + CanManageResourceTranslations(context.Context) bool } ResourceTranslationsManagerService interface { @@ -39,6 +40,8 @@ type ( } ) +var ErrNotAllowedToManageResourceTranslations = errors.Unauthorized("not allowed to manage resource translations") + func ResourceTranslationsManager(ls locale.Resource) *resourceTranslationsManager { return &resourceTranslationsManager{ actionlog: DefaultActionlog, @@ -49,10 +52,15 @@ func ResourceTranslationsManager(ls locale.Resource) *resourceTranslationsManage } func (svc resourceTranslationsManager) Upsert(ctx context.Context, rr locale.ResourceTranslationSet) (err error) { - // @todo AC - //if (!svc.ac.CanManageResourceTranslation(ctx)) { - // return *****ErrNotAllowedToCreate() - //} + // User is allowed to manage resource translations when: + // - managed resource translation strings are all for default language + // or + // - user is allowed to manage resource translations + if rr.ContainsForeign(svc.Locale().Default().Tag) { + if !svc.ac.CanManageResourceTranslations(ctx) { + return ErrNotAllowedToManageResourceTranslations + } + } // @todo validation diff --git a/pkg/locale/resource.go b/pkg/locale/resource.go index 4c5ada788..c09aa7999 100644 --- a/pkg/locale/resource.go +++ b/pkg/locale/resource.go @@ -23,11 +23,25 @@ func ContentID(cID uint64, i int) uint64 { } func (rr ResourceTranslationSet) SetLanguage(tag language.Tag) { + str := tag.String() for _, r := range rr { - r.Lang = tag.String() + r.Lang = str } } +// Returns true if resource translation set contains foreign (non-native) languages +func (rr ResourceTranslationSet) ContainsForeign(native language.Tag) bool { + str := native.String() + + for _, r := range rr { + if r.Lang != str { + return true + } + } + + return false +} + func (rx ResourceTranslationIndex) FindByKey(k string) *ResourceTranslation { return rx[k] } diff --git a/pkg/locale/service.go b/pkg/locale/service.go index f1b3a0606..07edbe3bc 100644 --- a/pkg/locale/service.go +++ b/pkg/locale/service.go @@ -31,6 +31,7 @@ type ( TResourceFor(tag language.Tag, ns, key string, rr ...string) string Tags() []language.Tag ResourceTranslations(code language.Tag, resource string) ResourceTranslationIndex + Default() *Language } service struct { diff --git a/system/service/access_control.gen.go b/system/service/access_control.gen.go index 122b0b7c1..672defaaa 100644 --- a/system/service/access_control.gen.go +++ b/system/service/access_control.gen.go @@ -357,7 +357,7 @@ func (svc accessControl) List() (out []map[string]string) { { "type": types.ComponentResourceType, "any": types.ComponentRbacResource(), - "op": "resource-translation.Manage", + "op": "resource-translations.manage", }, } @@ -827,11 +827,11 @@ func (svc accessControl) CanSearchApigwFilters(ctx context.Context) bool { return svc.can(ctx, "apigw-filters.search", &types.Component{}) } -// CanManageResourceTranslation checks if current user can list, search, create, or update resource translations +// CanManageResourceTranslations checks if current user can list, search, create, or update resource translations // // This function is auto-generated -func (svc accessControl) CanManageResourceTranslation(ctx context.Context) bool { - return svc.can(ctx, "resource-translation.Manage", &types.Component{}) +func (svc accessControl) CanManageResourceTranslations(ctx context.Context) bool { + return svc.can(ctx, "resource-translations.manage", &types.Component{}) } // rbacResourceValidator validates known component's resource by routing it to the appropriate validator @@ -926,32 +926,32 @@ func rbacResourceOperations(r string) map[string]bool { } case types.ComponentResourceType: return map[string]bool{ - "grant": true, - "action-log.read": true, - "settings.read": true, - "settings.manage": true, - "auth-client.create": true, - "auth-clients.search": true, - "role.create": true, - "roles.search": true, - "user.create": true, - "users.search": true, - "application.create": true, - "applications.search": true, - "application.flag.self": true, - "application.flag.global": true, - "template.create": true, - "templates.search": true, - "report.create": true, - "reports.search": true, - "reminder.assign": true, - "queue.create": true, - "queues.search": true, - "apigw-route.create": true, - "apigw-routes.search": true, - "apigw-filter.create": true, - "apigw-filters.search": true, - "resource-translation.Manage": true, + "grant": true, + "action-log.read": true, + "settings.read": true, + "settings.manage": true, + "auth-client.create": true, + "auth-clients.search": true, + "role.create": true, + "roles.search": true, + "user.create": true, + "users.search": true, + "application.create": true, + "applications.search": true, + "application.flag.self": true, + "application.flag.global": true, + "template.create": true, + "templates.search": true, + "report.create": true, + "reports.search": true, + "reminder.assign": true, + "queue.create": true, + "queues.search": true, + "apigw-route.create": true, + "apigw-routes.search": true, + "apigw-filter.create": true, + "apigw-filters.search": true, + "resource-translations.manage": true, } } diff --git a/system/service/locale.gen.go b/system/service/locale.gen.go index 8962ecd2e..aaefefcd8 100644 --- a/system/service/locale.gen.go +++ b/system/service/locale.gen.go @@ -11,10 +11,12 @@ package service import ( "context" + "github.com/cortezaproject/corteza-server/system/types" "github.com/cortezaproject/corteza-server/pkg/actionlog" intAuth "github.com/cortezaproject/corteza-server/pkg/auth" + "github.com/cortezaproject/corteza-server/pkg/errors" "github.com/cortezaproject/corteza-server/pkg/locale" "github.com/cortezaproject/corteza-server/store" systemTypes "github.com/cortezaproject/corteza-server/system/types" @@ -29,7 +31,7 @@ type ( } localeAccessController interface { - // CanManageResourceTranslation(context.Context) bool + CanManageResourceTranslations(context.Context) bool } ResourceTranslationsManagerService interface { @@ -40,6 +42,8 @@ type ( } ) +var ErrNotAllowedToManageResourceTranslations = errors.Unauthorized("not allowed to manage resource translations") + func ResourceTranslationsManager(ls locale.Resource) *resourceTranslationsManager { return &resourceTranslationsManager{ actionlog: DefaultActionlog, @@ -50,10 +54,15 @@ func ResourceTranslationsManager(ls locale.Resource) *resourceTranslationsManage } func (svc resourceTranslationsManager) Upsert(ctx context.Context, rr locale.ResourceTranslationSet) (err error) { - // @todo AC - //if (!svc.ac.CanManageResourceTranslation(ctx)) { - // return *****ErrNotAllowedToCreate() - //} + // User is allowed to manage resource translations when: + // - managed resource translation strings are all for default language + // or + // - user is allowed to manage resource translations + if rr.ContainsForeign(svc.Locale().Default().Tag) { + if !svc.ac.CanManageResourceTranslations(ctx) { + return ErrNotAllowedToManageResourceTranslations + } + } // @todo validation diff --git a/system/service/resource_translation.go b/system/service/resource_translation.go index 447369f18..9ee0c5354 100644 --- a/system/service/resource_translation.go +++ b/system/service/resource_translation.go @@ -17,7 +17,7 @@ type ( } resourceTranslationAccessController interface { - CanManageResourceTranslation(context.Context) bool + CanManageResourceTranslations(context.Context) bool } ResourceTranslationService interface { @@ -48,7 +48,7 @@ func (svc resourceTranslation) Read(ctx context.Context, ID uint64) (cc *types.R return TemplateErrInvalidID() } - if !svc.ac.CanManageResourceTranslation(ctx) { + if !svc.ac.CanManageResourceTranslations(ctx) { return ResourceTranslationErrNotAllowedToManage() } @@ -70,7 +70,7 @@ func (svc resourceTranslation) List(ctx context.Context, filter types.ResourceTr ) err = func() error { - if !svc.ac.CanManageResourceTranslation(ctx) { + if !svc.ac.CanManageResourceTranslations(ctx) { return ResourceTranslationErrNotAllowedToManage() } @@ -90,7 +90,7 @@ func (svc resourceTranslation) Create(ctx context.Context, new *types.ResourceTr ) err = func() (err error) { - if !svc.ac.CanManageResourceTranslation(ctx) { + if !svc.ac.CanManageResourceTranslations(ctx) { return ResourceTranslationErrNotAllowedToManage() } @@ -123,7 +123,7 @@ func (svc resourceTranslation) Update(ctx context.Context, upd *types.ResourceTr return ResourceTranslationErrInvalidID() } - if !svc.ac.CanManageResourceTranslation(ctx) { + if !svc.ac.CanManageResourceTranslations(ctx) { return ResourceTranslationErrNotAllowedToManage() } @@ -164,7 +164,7 @@ func (svc resourceTranslation) Delete(ctx context.Context, ID uint64) (err error return ResourceTranslationErrInvalidID() } - if !svc.ac.CanManageResourceTranslation(ctx) { + if !svc.ac.CanManageResourceTranslations(ctx) { return ResourceTranslationErrNotAllowedToManage() } @@ -198,7 +198,7 @@ func (svc resourceTranslation) Undelete(ctx context.Context, ID uint64) (err err return ResourceTranslationErrInvalidID() } - if !svc.ac.CanManageResourceTranslation(ctx) { + if !svc.ac.CanManageResourceTranslations(ctx) { return ResourceTranslationErrNotAllowedToManage() }