Add support for handle, fix tests
This commit is contained in:
@@ -7,6 +7,7 @@ import (
|
||||
"github.com/spf13/cobra"
|
||||
"github.com/titpetric/factory"
|
||||
|
||||
"github.com/cortezaproject/corteza-server/compose/commands"
|
||||
migrate "github.com/cortezaproject/corteza-server/compose/db"
|
||||
"github.com/cortezaproject/corteza-server/compose/rest"
|
||||
"github.com/cortezaproject/corteza-server/compose/service"
|
||||
@@ -63,6 +64,15 @@ func Configure() *cli.Config {
|
||||
rest.MountRoutes,
|
||||
},
|
||||
|
||||
AdtSubCommands: cli.CommandMakers{
|
||||
func(ctx context.Context, c *cli.Config) *cobra.Command {
|
||||
return commands.Importer(ctx, c)
|
||||
},
|
||||
func(ctx context.Context, c *cli.Config) *cobra.Command {
|
||||
return commands.Exporter(ctx, c)
|
||||
},
|
||||
},
|
||||
|
||||
ProvisionMigrateDatabase: cli.Runners{
|
||||
func(ctx context.Context, cmd *cobra.Command, c *cli.Config) error {
|
||||
var db, err = factory.Database.Get(compose)
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -0,0 +1,3 @@
|
||||
ALTER TABLE `compose_module` ADD `handle` VARCHAR(200) NOT NULL AFTER `id`;
|
||||
ALTER TABLE `compose_page` ADD `handle` VARCHAR(200) NOT NULL AFTER `id`;
|
||||
ALTER TABLE `compose_chart` ADD `handle` VARCHAR(200) NOT NULL AFTER `id`;
|
||||
@@ -15,6 +15,7 @@ type (
|
||||
With(ctx context.Context, db *factory.DB) ChartRepository
|
||||
|
||||
FindByID(namespaceID, chartID uint64) (*types.Chart, error)
|
||||
FindByHandle(namespaceID uint64, handle string) (c *types.Chart, err error)
|
||||
Find(filter types.ChartFilter) (set types.ChartSet, f types.ChartFilter, err error)
|
||||
Create(mod *types.Chart) (*types.Chart, error)
|
||||
Update(mod *types.Chart) (*types.Chart, error)
|
||||
@@ -27,7 +28,8 @@ type (
|
||||
)
|
||||
|
||||
const (
|
||||
ErrChartNotFound = repositoryError("ChartNotFound")
|
||||
ErrChartNotFound = repositoryError("ChartNotFound")
|
||||
ErrChartHandleNotUnique = repositoryError("ChartHandleNotUnique")
|
||||
)
|
||||
|
||||
func Chart(ctx context.Context, db *factory.DB) ChartRepository {
|
||||
@@ -46,7 +48,7 @@ func (r chart) table() string {
|
||||
|
||||
func (r chart) columns() []string {
|
||||
return []string{
|
||||
"id", "rel_namespace", "name", "config",
|
||||
"id", "rel_namespace", "handle", "name", "config",
|
||||
"created_at", "updated_at", "deleted_at",
|
||||
}
|
||||
}
|
||||
@@ -74,6 +76,22 @@ func (r chart) FindByID(namespaceID, chartID uint64) (*types.Chart, error) {
|
||||
return c, isFound(r.fetchOne(c, query), c.ID > 0, ErrChartNotFound)
|
||||
}
|
||||
|
||||
func (r chart) FindByHandle(namespaceID uint64, handle string) (*types.Chart, error) {
|
||||
var (
|
||||
query = r.query().
|
||||
Columns(r.columns()...).
|
||||
Where("handle = ?", handle)
|
||||
|
||||
c = &types.Chart{}
|
||||
)
|
||||
|
||||
if namespaceID > 0 {
|
||||
query = query.Where("rel_namespace = ?", namespaceID)
|
||||
}
|
||||
|
||||
return c, isFound(r.fetchOne(c, query), c.ID > 0, ErrChartNotFound)
|
||||
}
|
||||
|
||||
func (r chart) Find(filter types.ChartFilter) (set types.ChartSet, f types.ChartFilter, err error) {
|
||||
f = filter
|
||||
|
||||
|
||||
@@ -19,6 +19,8 @@ type (
|
||||
With(ctx context.Context, db *factory.DB) ModuleRepository
|
||||
|
||||
FindByID(namespaceID, moduleID uint64) (*types.Module, error)
|
||||
FindByName(namespaceID uint64, name string) (*types.Module, error)
|
||||
FindByHandle(namespaceID uint64, handle string) (*types.Module, error)
|
||||
Find(filter types.ModuleFilter) (set types.ModuleSet, f types.ModuleFilter, err error)
|
||||
FindFields(moduleIDs ...uint64) (ff types.ModuleFieldSet, err error)
|
||||
Create(mod *types.Module) (*types.Module, error)
|
||||
@@ -32,8 +34,9 @@ type (
|
||||
)
|
||||
|
||||
const (
|
||||
ErrModuleNotFound = repositoryError("ModuleNotFound")
|
||||
ErrModuleNameNotUnique = repositoryError("ModuleNameNotUnique")
|
||||
ErrModuleNotFound = repositoryError("ModuleNotFound")
|
||||
ErrModuleNameNotUnique = repositoryError("ModuleNameNotUnique")
|
||||
ErrModuleHandleNotUnique = repositoryError("ModuleHandleNotUnique")
|
||||
)
|
||||
|
||||
func Module(ctx context.Context, db *factory.DB) ModuleRepository {
|
||||
@@ -56,7 +59,7 @@ func (r module) tableFields() string {
|
||||
|
||||
func (r module) columns() []string {
|
||||
return []string{
|
||||
"id", "rel_namespace", "name", "json",
|
||||
"id", "rel_namespace", "handle", "name", "json",
|
||||
"created_at", "updated_at", "deleted_at",
|
||||
}
|
||||
}
|
||||
@@ -70,19 +73,32 @@ func (r module) query() squirrel.SelectBuilder {
|
||||
}
|
||||
|
||||
func (r module) FindByID(namespaceID, moduleID uint64) (*types.Module, error) {
|
||||
var (
|
||||
query = r.query().
|
||||
Columns(r.columns()...).
|
||||
Where("id = ?", moduleID)
|
||||
return r.findOneBy(namespaceID, "id", moduleID)
|
||||
}
|
||||
|
||||
c = &types.Module{}
|
||||
func (r module) FindByHandle(namespaceID uint64, handle string) (*types.Module, error) {
|
||||
return r.findOneBy(namespaceID, "LOWER(handle)", strings.ToLower(strings.TrimSpace(handle)))
|
||||
}
|
||||
|
||||
func (r module) FindByName(namespaceID uint64, name string) (*types.Module, error) {
|
||||
return r.findOneBy(namespaceID, "LOWER(name)", strings.ToLower(strings.TrimSpace(name)))
|
||||
}
|
||||
|
||||
func (r module) findOneBy(namespaceID uint64, field string, value interface{}) (*types.Module, error) {
|
||||
var m = &types.Module{}
|
||||
|
||||
err := r.findOneInNamespaceBy(
|
||||
namespaceID,
|
||||
r.query().Columns(r.columns()...),
|
||||
squirrel.Eq{field: value},
|
||||
m,
|
||||
)
|
||||
|
||||
if namespaceID > 0 {
|
||||
query = query.Where("rel_namespace = ?", namespaceID)
|
||||
if err == nil && m.ID == 0 {
|
||||
return nil, ErrModuleNotFound
|
||||
}
|
||||
|
||||
return c, isFound(r.fetchOne(c, query), c.ID > 0, ErrModuleNotFound)
|
||||
return m, nil
|
||||
}
|
||||
|
||||
func (r module) Find(filter types.ModuleFilter) (set types.ModuleSet, f types.ModuleFilter, err error) {
|
||||
@@ -118,10 +134,6 @@ func (r module) Find(filter types.ModuleFilter) (set types.ModuleSet, f types.Mo
|
||||
func (r module) Create(mod *types.Module) (*types.Module, error) {
|
||||
var err error
|
||||
|
||||
if err = r.checkName(mod.NamespaceID, 0, mod.Name); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
mod.ID = factory.Sonyflake.NextID()
|
||||
mod.CreatedAt = time.Now().Truncate(time.Second)
|
||||
|
||||
@@ -137,10 +149,6 @@ func (r module) Create(mod *types.Module) (*types.Module, error) {
|
||||
}
|
||||
|
||||
func (r module) Update(mod *types.Module) (*types.Module, error) {
|
||||
if err := r.checkName(mod.NamespaceID, 0, mod.Name); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
now := time.Now().Truncate(time.Second)
|
||||
mod.UpdatedAt = &now
|
||||
|
||||
@@ -245,22 +253,3 @@ func (r module) FindFields(moduleIDs ...uint64) (ff types.ModuleFieldSet, err er
|
||||
return ff, r.db().Select(&ff, sql, args...)
|
||||
}
|
||||
}
|
||||
|
||||
// Checks if there is another module in the namespace with the same name
|
||||
func (r module) checkName(namespaceID, moduleID uint64, name string) error {
|
||||
mm, f, err := r.Find(types.ModuleFilter{
|
||||
NamespaceID: namespaceID,
|
||||
Name: name,
|
||||
PerPage: 1,
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if f.Count == 0 || mm.FindByID(moduleID) == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
return ErrModuleNameNotUnique
|
||||
}
|
||||
|
||||
@@ -28,7 +28,9 @@ type (
|
||||
)
|
||||
|
||||
const (
|
||||
ErrNamespaceNotFound = repositoryError("NamespaceNotFound")
|
||||
ErrNamespaceNotFound = repositoryError("NamespaceNotFound")
|
||||
ErrNamespaceSlugNotUnique = repositoryError("NamespaceSlugNotUnique")
|
||||
ErrNamespaceInvalidSlugFormat = repositoryError("NamespaceInvalidSlugFormat")
|
||||
)
|
||||
|
||||
func Namespace(ctx context.Context, db *factory.DB) NamespaceRepository {
|
||||
|
||||
@@ -15,6 +15,7 @@ type (
|
||||
With(ctx context.Context, db *factory.DB) PageRepository
|
||||
|
||||
FindByID(namespaceID, pageID uint64) (*types.Page, error)
|
||||
FindByHandle(namespaceID uint64, handle string) (*types.Page, error)
|
||||
FindByModuleID(namespaceID, moduleID uint64) (*types.Page, error)
|
||||
Find(filter types.PageFilter) (set types.PageSet, f types.PageFilter, err error)
|
||||
|
||||
@@ -31,7 +32,8 @@ type (
|
||||
)
|
||||
|
||||
const (
|
||||
ErrPageNotFound = repositoryError("PageNotFound")
|
||||
ErrPageNotFound = repositoryError("PageNotFound")
|
||||
ErrPageHandleNotUnique = repositoryError("PageHandleNotUnique")
|
||||
)
|
||||
|
||||
func Page(ctx context.Context, db *factory.DB) PageRepository {
|
||||
@@ -50,7 +52,8 @@ func (r page) table() string {
|
||||
|
||||
func (r page) columns() []string {
|
||||
return []string{
|
||||
"id", "rel_namespace", "self_id", "rel_module", "title",
|
||||
"id", "rel_namespace", "self_id", "rel_module",
|
||||
"handle", "title",
|
||||
"blocks", "description", "visible", "weight",
|
||||
"created_at", "updated_at", "deleted_at",
|
||||
}
|
||||
@@ -79,6 +82,22 @@ func (r page) FindByID(namespaceID, pageID uint64) (*types.Page, error) {
|
||||
return c, isFound(r.fetchOne(c, query), c.ID > 0, ErrPageNotFound)
|
||||
}
|
||||
|
||||
func (r page) FindByHandle(namespaceID uint64, handle string) (*types.Page, error) {
|
||||
var (
|
||||
query = r.query().
|
||||
Columns(r.columns()...).
|
||||
Where("handle = ?", handle)
|
||||
|
||||
c = &types.Page{}
|
||||
)
|
||||
|
||||
if namespaceID > 0 {
|
||||
query = query.Where("rel_namespace = ?", namespaceID)
|
||||
}
|
||||
|
||||
return c, isFound(r.fetchOne(c, query), c.ID > 0, ErrPageNotFound)
|
||||
}
|
||||
|
||||
func (r page) FindByModuleID(namespaceID, moduleID uint64) (*types.Page, error) {
|
||||
var (
|
||||
query = r.query().
|
||||
|
||||
@@ -48,6 +48,21 @@ func (r *repository) db() *factory.DB {
|
||||
return DB(r.ctx)
|
||||
}
|
||||
|
||||
func (r repository) findOneInNamespaceBy(namespaceID uint64, q squirrel.SelectBuilder, eq squirrel.Eq, row interface{}) error {
|
||||
q = q.Where(eq)
|
||||
|
||||
if namespaceID > 0 {
|
||||
q = q.Where("rel_namespace = ?", namespaceID)
|
||||
}
|
||||
|
||||
if err := r.fetchOne(row, q); err != nil {
|
||||
row = nil
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Fetches single row from table
|
||||
func (r repository) fetchOne(one interface{}, q squirrel.SelectBuilder) (err error) {
|
||||
return rh.FetchOne(r.db(), q, one)
|
||||
|
||||
@@ -8,6 +8,7 @@ import (
|
||||
|
||||
"github.com/cortezaproject/corteza-server/compose/repository"
|
||||
"github.com/cortezaproject/corteza-server/compose/types"
|
||||
"github.com/cortezaproject/corteza-server/pkg/handle"
|
||||
)
|
||||
|
||||
type (
|
||||
@@ -34,6 +35,7 @@ type (
|
||||
With(ctx context.Context) ChartService
|
||||
|
||||
FindByID(namespaceID, chartID uint64) (*types.Chart, error)
|
||||
FindByHandle(namespaceID uint64, handle string) (*types.Chart, error)
|
||||
Find(filter types.ChartFilter) (set types.ChartSet, f types.ChartFilter, err error)
|
||||
|
||||
Create(chart *types.Chart) (*types.Chart, error)
|
||||
@@ -69,17 +71,29 @@ func (svc chart) With(ctx context.Context) ChartService {
|
||||
// }
|
||||
|
||||
func (svc chart) FindByID(namespaceID, chartID uint64) (c *types.Chart, err error) {
|
||||
if namespaceID == 0 {
|
||||
return nil, ErrNamespaceRequired
|
||||
}
|
||||
|
||||
if c, err = svc.chartRepo.FindByID(namespaceID, chartID); err != nil {
|
||||
if _, err = svc.loadNamespace(namespaceID); err != nil {
|
||||
return
|
||||
} else {
|
||||
return svc.checkPermissions(svc.chartRepo.FindByID(namespaceID, chartID))
|
||||
}
|
||||
}
|
||||
|
||||
func (svc chart) FindByHandle(namespaceID uint64, handle string) (c *types.Chart, err error) {
|
||||
if _, err = svc.loadNamespace(namespaceID); err != nil {
|
||||
return
|
||||
} else {
|
||||
return svc.checkPermissions(svc.chartRepo.FindByHandle(namespaceID, handle))
|
||||
}
|
||||
}
|
||||
|
||||
func (svc chart) checkPermissions(c *types.Chart, err error) (*types.Chart, error) {
|
||||
if err != nil {
|
||||
return nil, err
|
||||
} else if !svc.ac.CanReadChart(svc.ctx, c) {
|
||||
return nil, ErrNoReadPermissions.withStack()
|
||||
}
|
||||
|
||||
return
|
||||
return c, err
|
||||
}
|
||||
|
||||
func (svc chart) Find(filter types.ChartFilter) (set types.ChartSet, f types.ChartFilter, err error) {
|
||||
@@ -96,16 +110,28 @@ func (svc chart) Find(filter types.ChartFilter) (set types.ChartSet, f types.Cha
|
||||
}
|
||||
|
||||
func (svc chart) Create(mod *types.Chart) (c *types.Chart, err error) {
|
||||
if !handle.IsValid(mod.Handle) {
|
||||
return nil, ErrInvalidHandle
|
||||
}
|
||||
|
||||
if ns, err := svc.loadNamespace(mod.NamespaceID); err != nil {
|
||||
return nil, err
|
||||
} else if !svc.ac.CanCreateChart(svc.ctx, ns) {
|
||||
return nil, ErrNoCreatePermissions.withStack()
|
||||
}
|
||||
|
||||
if err = svc.UniqueCheck(mod); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
return svc.chartRepo.Create(mod)
|
||||
}
|
||||
|
||||
func (svc chart) Update(mod *types.Chart) (c *types.Chart, err error) {
|
||||
if !handle.IsValid(mod.Handle) {
|
||||
return nil, ErrInvalidHandle
|
||||
}
|
||||
|
||||
if mod.ID == 0 {
|
||||
return nil, ErrInvalidID.withStack()
|
||||
}
|
||||
@@ -118,6 +144,10 @@ func (svc chart) Update(mod *types.Chart) (c *types.Chart, err error) {
|
||||
return nil, ErrStaleData.withStack()
|
||||
}
|
||||
|
||||
if err = svc.UniqueCheck(mod); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
if !svc.ac.CanUpdateChart(svc.ctx, c) {
|
||||
return nil, ErrNoUpdatePermissions.withStack()
|
||||
}
|
||||
@@ -146,6 +176,16 @@ func (svc chart) DeleteByID(namespaceID, chartID uint64) error {
|
||||
return svc.chartRepo.DeleteByID(namespaceID, chartID)
|
||||
}
|
||||
|
||||
func (svc chart) UniqueCheck(c *types.Chart) (err error) {
|
||||
if c.Handle != "" {
|
||||
if e, _ := svc.chartRepo.FindByHandle(c.NamespaceID, c.Handle); e != nil && e.ID != c.ID {
|
||||
return repository.ErrChartHandleNotUnique
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (svc chart) loadNamespace(namespaceID uint64) (ns *types.Namespace, err error) {
|
||||
if namespaceID == 0 {
|
||||
return nil, ErrNamespaceRequired.withStack()
|
||||
|
||||
@@ -10,6 +10,7 @@ type (
|
||||
|
||||
const (
|
||||
ErrInvalidID serviceError = "InvalidID"
|
||||
ErrInvalidHandle serviceError = "InvalidHandle"
|
||||
ErrStaleData serviceError = "StaleData"
|
||||
ErrNoPermissions serviceError = "NoPermissions"
|
||||
ErrNoGrantPermissions serviceError = "NoGrantPermissions"
|
||||
|
||||
@@ -8,6 +8,7 @@ import (
|
||||
|
||||
"github.com/cortezaproject/corteza-server/compose/repository"
|
||||
"github.com/cortezaproject/corteza-server/compose/types"
|
||||
"github.com/cortezaproject/corteza-server/pkg/handle"
|
||||
)
|
||||
|
||||
type (
|
||||
@@ -35,6 +36,8 @@ type (
|
||||
With(ctx context.Context) ModuleService
|
||||
|
||||
FindByID(namespaceID, moduleID uint64) (*types.Module, error)
|
||||
FindByName(namespaceID uint64, name string) (*types.Module, error)
|
||||
FindByHandle(namespaceID uint64, handle string) (*types.Module, error)
|
||||
Find(filter types.ModuleFilter) (set types.ModuleSet, f types.ModuleFilter, err error)
|
||||
|
||||
Create(module *types.Module) (*types.Module, error)
|
||||
@@ -71,19 +74,39 @@ func (svc module) With(ctx context.Context) ModuleService {
|
||||
// }
|
||||
|
||||
func (svc module) FindByID(namespaceID, moduleID uint64) (m *types.Module, err error) {
|
||||
if namespaceID == 0 {
|
||||
return nil, ErrNamespaceRequired
|
||||
}
|
||||
|
||||
if m, err = svc.moduleRepo.FindByID(namespaceID, moduleID); err != nil {
|
||||
if _, err = svc.loadNamespace(namespaceID); err != nil {
|
||||
return
|
||||
} else {
|
||||
return svc.loader(svc.moduleRepo.FindByID(namespaceID, moduleID))
|
||||
}
|
||||
}
|
||||
|
||||
func (svc module) FindByName(namespaceID uint64, name string) (m *types.Module, err error) {
|
||||
if _, err = svc.loadNamespace(namespaceID); err != nil {
|
||||
return
|
||||
} else {
|
||||
return svc.loader(svc.moduleRepo.FindByName(namespaceID, name))
|
||||
}
|
||||
}
|
||||
|
||||
func (svc module) FindByHandle(namespaceID uint64, handle string) (m *types.Module, err error) {
|
||||
if _, err = svc.loadNamespace(namespaceID); err != nil {
|
||||
return
|
||||
} else {
|
||||
return svc.loader(svc.moduleRepo.FindByHandle(namespaceID, handle))
|
||||
}
|
||||
}
|
||||
|
||||
func (svc module) loader(m *types.Module, err error) (*types.Module, error) {
|
||||
if err != nil {
|
||||
return nil, err
|
||||
} else if !svc.ac.CanReadModule(svc.ctx, m) {
|
||||
return nil, ErrNoReadPermissions.withStack()
|
||||
}
|
||||
|
||||
var ff types.ModuleFieldSet
|
||||
if ff, err = svc.moduleRepo.FindFields(m.ID); err != nil {
|
||||
return
|
||||
return nil, err
|
||||
} else {
|
||||
_ = ff.Walk(func(f *types.ModuleField) error {
|
||||
m.Fields = append(m.Fields, f)
|
||||
@@ -91,7 +114,7 @@ func (svc module) FindByID(namespaceID, moduleID uint64) (m *types.Module, err e
|
||||
})
|
||||
}
|
||||
|
||||
return
|
||||
return m, err
|
||||
}
|
||||
|
||||
func (svc module) Find(filter types.ModuleFilter) (set types.ModuleSet, f types.ModuleFilter, err error) {
|
||||
@@ -119,11 +142,17 @@ func (svc module) Find(filter types.ModuleFilter) (set types.ModuleSet, f types.
|
||||
}
|
||||
|
||||
func (svc module) Create(mod *types.Module) (*types.Module, error) {
|
||||
|
||||
if !handle.IsValid(mod.Handle) {
|
||||
return nil, ErrInvalidHandle
|
||||
}
|
||||
if mod.NamespaceID == 0 {
|
||||
return nil, ErrNamespaceRequired.withStack()
|
||||
}
|
||||
|
||||
if err := svc.UniqueCheck(mod); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if ns, err := svc.loadNamespace(mod.NamespaceID); err != nil {
|
||||
return nil, err
|
||||
} else if !svc.ac.CanCreateModule(svc.ctx, ns) {
|
||||
@@ -138,10 +167,18 @@ func (svc module) Update(mod *types.Module) (m *types.Module, err error) {
|
||||
return nil, ErrInvalidID.withStack()
|
||||
}
|
||||
|
||||
if !handle.IsValid(mod.Handle) {
|
||||
return nil, ErrInvalidHandle
|
||||
}
|
||||
|
||||
if m, err = svc.moduleRepo.FindByID(mod.NamespaceID, mod.ID); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
if err = svc.UniqueCheck(mod); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
if isStale(mod.UpdatedAt, m.UpdatedAt, m.CreatedAt) {
|
||||
return nil, ErrStaleData.withStack()
|
||||
}
|
||||
@@ -175,6 +212,22 @@ func (svc module) DeleteByID(namespaceID, moduleID uint64) error {
|
||||
return svc.moduleRepo.DeleteByID(namespaceID, moduleID)
|
||||
}
|
||||
|
||||
func (svc module) UniqueCheck(m *types.Module) (err error) {
|
||||
if m.Handle != "" {
|
||||
if e, _ := svc.moduleRepo.FindByHandle(m.NamespaceID, m.Handle); e != nil && e.ID > 0 && e.ID != m.ID {
|
||||
return repository.ErrModuleHandleNotUnique
|
||||
}
|
||||
}
|
||||
|
||||
if m.Name != "" {
|
||||
if e, _ := svc.moduleRepo.FindByName(m.NamespaceID, m.Name); e != nil && e.ID > 0 && e.ID != m.ID {
|
||||
return repository.ErrModuleNameNotUnique
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (svc module) loadNamespace(namespaceID uint64) (ns *types.Namespace, err error) {
|
||||
if namespaceID == 0 {
|
||||
return nil, ErrNamespaceRequired.withStack()
|
||||
|
||||
@@ -3,12 +3,14 @@ package service
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/davecgh/go-spew/spew"
|
||||
"github.com/titpetric/factory"
|
||||
"go.uber.org/zap"
|
||||
|
||||
"github.com/cortezaproject/corteza-server/compose/repository"
|
||||
"github.com/cortezaproject/corteza-server/compose/types"
|
||||
"github.com/cortezaproject/corteza-server/internal/permissions"
|
||||
"github.com/cortezaproject/corteza-server/pkg/handle"
|
||||
)
|
||||
|
||||
type (
|
||||
@@ -35,6 +37,7 @@ type (
|
||||
With(ctx context.Context) NamespaceService
|
||||
|
||||
FindByID(namespaceID uint64) (*types.Namespace, error)
|
||||
FindByHandle(handle string) (*types.Namespace, error)
|
||||
Find(types.NamespaceFilter) (types.NamespaceSet, types.NamespaceFilter, error)
|
||||
|
||||
Create(namespace *types.Namespace) (*types.Namespace, error)
|
||||
@@ -69,27 +72,25 @@ func (svc namespace) With(ctx context.Context) NamespaceService {
|
||||
// }
|
||||
|
||||
func (svc namespace) FindByID(ID uint64) (ns *types.Namespace, err error) {
|
||||
if ID == 0 {
|
||||
return nil, ErrInvalidID.withStack()
|
||||
}
|
||||
return svc.checkPermissions(svc.namespaceRepo.FindByID(ID))
|
||||
}
|
||||
|
||||
if ns, err = svc.namespaceRepo.FindByID(ID); err != nil {
|
||||
return
|
||||
} else if !svc.ac.CanReadNamespace(svc.ctx, ns) {
|
||||
return nil, ErrNoReadPermissions.withStack()
|
||||
}
|
||||
|
||||
return
|
||||
func (svc namespace) FindByHandle(handle string) (ns *types.Namespace, err error) {
|
||||
return svc.checkPermissions(svc.namespaceRepo.FindBySlug(handle))
|
||||
}
|
||||
|
||||
func (svc namespace) FindBySlug(slug string) (ns *types.Namespace, err error) {
|
||||
if ns, err = svc.namespaceRepo.FindBySlug(slug); err != nil {
|
||||
return
|
||||
} else if !svc.ac.CanReadNamespace(svc.ctx, ns) {
|
||||
return svc.checkPermissions(svc.namespaceRepo.FindBySlug(slug))
|
||||
}
|
||||
|
||||
func (svc namespace) checkPermissions(p *types.Namespace, err error) (*types.Namespace, error) {
|
||||
if err != nil {
|
||||
return nil, err
|
||||
} else if !svc.ac.CanReadNamespace(svc.ctx, p) {
|
||||
return nil, ErrNoReadPermissions.withStack()
|
||||
}
|
||||
|
||||
return
|
||||
return p, err
|
||||
}
|
||||
|
||||
func (svc namespace) Find(filter types.NamespaceFilter) (set types.NamespaceSet, f types.NamespaceFilter, err error) {
|
||||
@@ -107,6 +108,11 @@ func (svc namespace) Find(filter types.NamespaceFilter) (set types.NamespaceSet,
|
||||
|
||||
// Create adds namespace and presets access rules for role everyone
|
||||
func (svc namespace) Create(mod *types.Namespace) (*types.Namespace, error) {
|
||||
if !handle.IsValid(mod.Slug) {
|
||||
spew.Dump(mod.Slug)
|
||||
return nil, ErrInvalidHandle
|
||||
}
|
||||
|
||||
if !svc.ac.CanCreateNamespace(svc.ctx) {
|
||||
return nil, ErrNoCreatePermissions.withStack()
|
||||
}
|
||||
@@ -119,6 +125,11 @@ func (svc namespace) Update(mod *types.Namespace) (ns *types.Namespace, err erro
|
||||
return nil, ErrInvalidID.withStack()
|
||||
}
|
||||
|
||||
if !handle.IsValid(mod.Slug) {
|
||||
spew.Dump(mod.Slug)
|
||||
return nil, ErrInvalidHandle
|
||||
}
|
||||
|
||||
ns, err = svc.FindByID(mod.ID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -153,3 +164,13 @@ func (svc namespace) DeleteByID(namespaceID uint64) error {
|
||||
|
||||
return svc.namespaceRepo.DeleteByID(namespaceID)
|
||||
}
|
||||
|
||||
func (svc namespace) UniqueCheck(ns *types.Namespace) (err error) {
|
||||
if ns.Slug != "" {
|
||||
if e, _ := svc.namespaceRepo.FindBySlug(ns.Slug); e != nil && e.ID != ns.ID {
|
||||
return repository.ErrNamespaceSlugNotUnique
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
+40
-13
@@ -3,12 +3,12 @@ package service
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
"github.com/titpetric/factory"
|
||||
"go.uber.org/zap"
|
||||
|
||||
"github.com/cortezaproject/corteza-server/compose/repository"
|
||||
"github.com/cortezaproject/corteza-server/compose/types"
|
||||
"github.com/cortezaproject/corteza-server/pkg/handle"
|
||||
)
|
||||
|
||||
type (
|
||||
@@ -36,6 +36,7 @@ type (
|
||||
With(ctx context.Context) PageService
|
||||
|
||||
FindByID(namespaceID, pageID uint64) (*types.Page, error)
|
||||
FindByHandle(namespaceID uint64, handle string) (*types.Page, error)
|
||||
FindByModuleID(namespaceID, moduleID uint64) (*types.Page, error)
|
||||
FindBySelfID(namespaceID, selfID uint64) (pages types.PageSet, f types.PageFilter, err error)
|
||||
Find(filter types.PageFilter) (set types.PageSet, f types.PageFilter, err error)
|
||||
@@ -77,18 +78,34 @@ func (svc page) With(ctx context.Context) PageService {
|
||||
// }
|
||||
|
||||
func (svc page) FindByID(namespaceID, pageID uint64) (p *types.Page, err error) {
|
||||
return svc.checkPermissions(svc.pageRepo.FindByID(namespaceID, pageID))
|
||||
if _, err = svc.loadNamespace(namespaceID); err != nil {
|
||||
return
|
||||
} else {
|
||||
return svc.checkPermissions(svc.pageRepo.FindByID(namespaceID, pageID))
|
||||
}
|
||||
}
|
||||
|
||||
func (svc page) FindByHandle(namespaceID uint64, handle string) (c *types.Page, err error) {
|
||||
if _, err = svc.loadNamespace(namespaceID); err != nil {
|
||||
return
|
||||
} else {
|
||||
return svc.checkPermissions(svc.pageRepo.FindByHandle(namespaceID, handle))
|
||||
}
|
||||
}
|
||||
|
||||
func (svc page) FindByModuleID(namespaceID, moduleID uint64) (p *types.Page, err error) {
|
||||
return svc.checkPermissions(svc.pageRepo.FindByModuleID(namespaceID, moduleID))
|
||||
if _, err = svc.loadNamespace(namespaceID); err != nil {
|
||||
return
|
||||
} else {
|
||||
return svc.checkPermissions(svc.pageRepo.FindByModuleID(namespaceID, moduleID))
|
||||
}
|
||||
}
|
||||
|
||||
func (svc page) checkPermissions(p *types.Page, err error) (*types.Page, error) {
|
||||
if err != nil {
|
||||
return nil, err
|
||||
} else if !svc.ac.CanReadPage(svc.ctx, p) {
|
||||
return nil, errors.New("not allowed to access this page")
|
||||
return nil, ErrNoReadPermissions.withStack()
|
||||
}
|
||||
|
||||
return p, err
|
||||
@@ -190,13 +207,17 @@ func (svc page) Reorder(namespaceID, selfID uint64, pageIDs []uint64) error {
|
||||
func (svc page) Create(mod *types.Page) (p *types.Page, err error) {
|
||||
mod.ID = 0
|
||||
|
||||
if !handle.IsValid(mod.Handle) {
|
||||
return nil, ErrInvalidHandle
|
||||
}
|
||||
|
||||
if ns, err := svc.loadNamespace(mod.NamespaceID); err != nil {
|
||||
return nil, err
|
||||
} else if !svc.ac.CanCreatePage(svc.ctx, ns) {
|
||||
return nil, ErrNoCreatePermissions.withStack()
|
||||
}
|
||||
|
||||
if err = svc.checkModulePage(mod); err != nil {
|
||||
if err = svc.UniqueCheck(mod); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
@@ -209,6 +230,10 @@ func (svc page) Update(mod *types.Page) (p *types.Page, err error) {
|
||||
return nil, ErrInvalidID.withStack()
|
||||
}
|
||||
|
||||
if !handle.IsValid(mod.Handle) {
|
||||
return nil, ErrInvalidHandle
|
||||
}
|
||||
|
||||
if _, err = svc.loadNamespace(mod.NamespaceID); err != nil {
|
||||
return
|
||||
}
|
||||
@@ -225,7 +250,7 @@ func (svc page) Update(mod *types.Page) (p *types.Page, err error) {
|
||||
return nil, ErrNoUpdatePermissions.withStack()
|
||||
}
|
||||
|
||||
if err = svc.checkModulePage(mod); err != nil {
|
||||
if err = svc.UniqueCheck(mod); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
@@ -241,13 +266,15 @@ func (svc page) Update(mod *types.Page) (p *types.Page, err error) {
|
||||
return
|
||||
}
|
||||
|
||||
func (svc page) checkModulePage(mod *types.Page) error {
|
||||
if mod.ModuleID > 0 {
|
||||
if p, err := svc.pageRepo.FindByModuleID(mod.NamespaceID, mod.ModuleID); err != nil {
|
||||
if err.Error() != repository.ErrPageNotFound.Error() {
|
||||
return err
|
||||
}
|
||||
} else if p.ID > 0 && mod.ID != p.ID {
|
||||
func (svc page) UniqueCheck(p *types.Page) (err error) {
|
||||
if p.Handle != "" {
|
||||
if e, _ := svc.pageRepo.FindByHandle(p.NamespaceID, p.Handle); e != nil && e.ID != p.ID {
|
||||
return repository.ErrPageHandleNotUnique
|
||||
}
|
||||
}
|
||||
|
||||
if p.ModuleID > 0 {
|
||||
if p, _ := svc.pageRepo.FindByModuleID(p.NamespaceID, p.ModuleID); p.ID > 0 && p.ID != p.ID {
|
||||
return ErrModulePageExists
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,8 +3,9 @@ package types
|
||||
import (
|
||||
"time"
|
||||
|
||||
"github.com/cortezaproject/corteza-server/internal/permissions"
|
||||
"github.com/jmoiron/sqlx/types"
|
||||
|
||||
"github.com/cortezaproject/corteza-server/internal/permissions"
|
||||
)
|
||||
|
||||
type (
|
||||
|
||||
@@ -10,6 +10,7 @@ type (
|
||||
|
||||
const (
|
||||
ErrInvalidID serviceError = "InvalidID"
|
||||
ErrInvalidHandle serviceError = "InvalidHandle"
|
||||
ErrNoPermissions serviceError = "NoPermissions"
|
||||
ErrNoGrantPermissions serviceError = "NoGrantPermissions"
|
||||
ErrNoCreatePermissions serviceError = "NoCreatePermissions"
|
||||
|
||||
+17
-28
@@ -7,6 +7,7 @@ import (
|
||||
"github.com/titpetric/factory"
|
||||
"go.uber.org/zap"
|
||||
|
||||
"github.com/cortezaproject/corteza-server/pkg/handle"
|
||||
"github.com/cortezaproject/corteza-server/system/repository"
|
||||
"github.com/cortezaproject/corteza-server/system/types"
|
||||
)
|
||||
@@ -127,6 +128,11 @@ func (svc role) FindByHandle(handle string) (*types.Role, error) {
|
||||
}
|
||||
|
||||
func (svc role) Create(mod *types.Role) (t *types.Role, err error) {
|
||||
|
||||
if !handle.IsValid(mod.Handle) {
|
||||
return nil, ErrInvalidHandle
|
||||
}
|
||||
|
||||
if !svc.ac.CanCreateRole(svc.ctx) {
|
||||
return nil, ErrNoCreatePermissions.withStack()
|
||||
}
|
||||
@@ -146,6 +152,10 @@ func (svc role) Update(mod *types.Role) (t *types.Role, err error) {
|
||||
return nil, ErrInvalidID
|
||||
}
|
||||
|
||||
if !handle.IsValid(mod.Handle) {
|
||||
return nil, ErrInvalidHandle
|
||||
}
|
||||
|
||||
if !svc.ac.CanUpdateRole(svc.ctx, mod) {
|
||||
return nil, ErrNoUpdatePermissions.withStack()
|
||||
}
|
||||
@@ -174,36 +184,15 @@ func (svc role) Update(mod *types.Role) (t *types.Role, err error) {
|
||||
}
|
||||
|
||||
func (svc role) UniqueCheck(r *types.Role) (err error) {
|
||||
var (
|
||||
e *types.Role
|
||||
|
||||
checks = []struct {
|
||||
query string
|
||||
find func(string) (*types.Role, error)
|
||||
err error
|
||||
}{
|
||||
// Checking scenario:
|
||||
// if email/username/handle is found on another user, error is thrown
|
||||
{r.Name, svc.FindByName, ErrRoleNameNotUnique},
|
||||
{r.Handle, svc.FindByHandle, ErrRoleHandleNotUnique},
|
||||
if r.Handle != "" {
|
||||
if ex, _ := svc.role.FindByHandle(r.Handle); ex.ID > 0 && ex.ID != r.ID {
|
||||
return ErrRoleHandleNotUnique
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
for _, c := range checks {
|
||||
if c.query == "" {
|
||||
// Skip empty values
|
||||
continue
|
||||
}
|
||||
|
||||
e, err = c.find(c.query)
|
||||
if err == repository.ErrRoleNotFound {
|
||||
// User not found, proceed to next check
|
||||
continue
|
||||
}
|
||||
|
||||
if e.ID > 0 && e.ID != r.ID {
|
||||
// User found, throw configured error
|
||||
return c.err
|
||||
if r.Name != "" {
|
||||
if ex, _ := svc.role.FindByName(r.Name); ex.ID > 0 && ex.ID != r.ID {
|
||||
return ErrRoleNameNotUnique
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+11
-27
@@ -196,37 +196,21 @@ func (svc user) Update(mod *types.User) (u *types.User, err error) {
|
||||
}
|
||||
|
||||
func (svc user) UniqueCheck(u *types.User) (err error) {
|
||||
var (
|
||||
e *types.User
|
||||
|
||||
checks = []struct {
|
||||
query string
|
||||
find func(string) (*types.User, error)
|
||||
err error
|
||||
}{
|
||||
// Checking scenario:
|
||||
// if email/username/handle is found on another user, error is thrown
|
||||
{u.Email, svc.FindByEmail, ErrUserEmailNotUnique},
|
||||
{u.Username, svc.FindByUsername, ErrUserUsernameNotUnique},
|
||||
{u.Handle, svc.FindByHandle, ErrUserHandleNotUnique},
|
||||
if u.Email != "" {
|
||||
if ex, _ := svc.user.FindByEmail(u.Email); ex.ID > 0 && ex.ID != u.ID {
|
||||
return ErrUserEmailNotUnique
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
for _, c := range checks {
|
||||
if c.query == "" {
|
||||
// Skip empty values
|
||||
continue
|
||||
if u.Username != "" {
|
||||
if ex, _ := svc.user.FindByUsername(u.Username); ex.ID > 0 && ex.ID != u.ID {
|
||||
return ErrUserUsernameNotUnique
|
||||
}
|
||||
}
|
||||
|
||||
e, err = c.find(c.query)
|
||||
if err == repository.ErrUserNotFound {
|
||||
// User not found, proceed to next check
|
||||
continue
|
||||
}
|
||||
|
||||
if e.ID > 0 && e.ID != u.ID {
|
||||
// User found, throw configured error
|
||||
return c.err
|
||||
if u.Handle != "" {
|
||||
if ex, _ := svc.user.FindByHandle(u.Handle); ex.ID > 0 && ex.ID != u.ID {
|
||||
return ErrUserHandleNotUnique
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -123,6 +123,9 @@ func Configure() *cli.Config {
|
||||
func(ctx context.Context, c *cli.Config) *cobra.Command {
|
||||
return commands.Auth(ctx, c)
|
||||
},
|
||||
func(ctx context.Context, c *cli.Config) *cobra.Command {
|
||||
return commands.Importer(ctx, c)
|
||||
},
|
||||
func(ctx context.Context, c *cli.Config) *cobra.Command {
|
||||
return commands.Users(ctx, c)
|
||||
},
|
||||
|
||||
@@ -9,6 +9,7 @@ import (
|
||||
jsonpath "github.com/steinfletcher/apitest-jsonpath"
|
||||
|
||||
"github.com/cortezaproject/corteza-server/compose/repository"
|
||||
"github.com/cortezaproject/corteza-server/compose/service"
|
||||
"github.com/cortezaproject/corteza-server/compose/types"
|
||||
"github.com/cortezaproject/corteza-server/tests/helpers"
|
||||
)
|
||||
@@ -20,7 +21,7 @@ func (h helper) repoChart() repository.ChartRepository {
|
||||
func (h helper) repoMakeChart(ns *types.Namespace, name string) *types.Chart {
|
||||
m, err := h.
|
||||
repoChart().
|
||||
Create(&types.Chart{Name: name, NamespaceID: ns.ID})
|
||||
Create(&types.Chart{Name: name, Handle: name, NamespaceID: ns.ID})
|
||||
h.a.NoError(err)
|
||||
|
||||
return m
|
||||
@@ -44,6 +45,22 @@ func TestChartRead(t *testing.T) {
|
||||
End()
|
||||
}
|
||||
|
||||
func TestChartReadByHandle(t *testing.T) {
|
||||
h := newHelper(t)
|
||||
|
||||
h.allow(types.NamespacePermissionResource.AppendWildcard(), "read")
|
||||
h.allow(types.ChartPermissionResource.AppendWildcard(), "read")
|
||||
ns := h.repoMakeNamespace("some-namespace")
|
||||
c := h.repoMakeChart(ns, "some-chart")
|
||||
|
||||
cbh, err := service.DefaultChart.With(h.secCtx()).FindByHandle(ns.ID, c.Handle)
|
||||
|
||||
h.a.NoError(err)
|
||||
h.a.NotNil(cbh)
|
||||
h.a.Equal(cbh.ID, c.ID)
|
||||
h.a.Equal(cbh.Handle, c.Handle)
|
||||
}
|
||||
|
||||
func TestChartList(t *testing.T) {
|
||||
h := newHelper(t)
|
||||
|
||||
|
||||
@@ -9,6 +9,7 @@ import (
|
||||
jsonpath "github.com/steinfletcher/apitest-jsonpath"
|
||||
|
||||
"github.com/cortezaproject/corteza-server/compose/repository"
|
||||
"github.com/cortezaproject/corteza-server/compose/service"
|
||||
"github.com/cortezaproject/corteza-server/compose/types"
|
||||
"github.com/cortezaproject/corteza-server/tests/helpers"
|
||||
)
|
||||
@@ -44,6 +45,22 @@ func TestModuleRead(t *testing.T) {
|
||||
End()
|
||||
}
|
||||
|
||||
func TestModuleReadByHandle(t *testing.T) {
|
||||
h := newHelper(t)
|
||||
|
||||
h.allow(types.NamespacePermissionResource.AppendWildcard(), "read")
|
||||
h.allow(types.ModulePermissionResource.AppendWildcard(), "read")
|
||||
ns := h.repoMakeNamespace("some-namespace")
|
||||
c := h.repoMakeModule(ns, "some-module")
|
||||
|
||||
cbh, err := service.DefaultModule.With(h.secCtx()).FindByHandle(ns.ID, c.Handle)
|
||||
|
||||
h.a.NoError(err)
|
||||
h.a.NotNil(cbh)
|
||||
h.a.Equal(cbh.ID, c.ID)
|
||||
h.a.Equal(cbh.Handle, c.Handle)
|
||||
}
|
||||
|
||||
func TestModuleList(t *testing.T) {
|
||||
h := newHelper(t)
|
||||
|
||||
|
||||
@@ -9,7 +9,9 @@ import (
|
||||
jsonpath "github.com/steinfletcher/apitest-jsonpath"
|
||||
|
||||
"github.com/cortezaproject/corteza-server/compose/repository"
|
||||
"github.com/cortezaproject/corteza-server/compose/service"
|
||||
"github.com/cortezaproject/corteza-server/compose/types"
|
||||
"github.com/cortezaproject/corteza-server/internal/rand"
|
||||
"github.com/cortezaproject/corteza-server/tests/helpers"
|
||||
)
|
||||
|
||||
@@ -20,7 +22,7 @@ func (h helper) repoNamespace() repository.NamespaceRepository {
|
||||
func (h helper) repoMakeNamespace(name string) *types.Namespace {
|
||||
ns, err := h.
|
||||
repoNamespace().
|
||||
Create(&types.Namespace{Name: name})
|
||||
Create(&types.Namespace{Name: name, Slug: name})
|
||||
h.a.NoError(err)
|
||||
|
||||
return ns
|
||||
@@ -41,6 +43,21 @@ func TestNamespaceRead(t *testing.T) {
|
||||
End()
|
||||
}
|
||||
|
||||
func TestNamespaceReadByHandle(t *testing.T) {
|
||||
h := newHelper(t)
|
||||
|
||||
h.allow(types.NamespacePermissionResource.AppendWildcard(), "read")
|
||||
h.allow(types.NamespacePermissionResource.AppendWildcard(), "read")
|
||||
ns := h.repoMakeNamespace("some-namespace-" + string(rand.Bytes(20)))
|
||||
|
||||
nsbh, err := service.DefaultNamespace.With(h.secCtx()).FindByHandle(ns.Slug)
|
||||
|
||||
h.a.NoError(err)
|
||||
h.a.NotNil(nsbh)
|
||||
h.a.Equal(nsbh.ID, ns.ID)
|
||||
h.a.Equal(nsbh.Slug, ns.Slug)
|
||||
}
|
||||
|
||||
func TestNamespaceList(t *testing.T) {
|
||||
h := newHelper(t)
|
||||
|
||||
|
||||
@@ -9,6 +9,7 @@ import (
|
||||
jsonpath "github.com/steinfletcher/apitest-jsonpath"
|
||||
|
||||
"github.com/cortezaproject/corteza-server/compose/repository"
|
||||
"github.com/cortezaproject/corteza-server/compose/service"
|
||||
"github.com/cortezaproject/corteza-server/compose/types"
|
||||
"github.com/cortezaproject/corteza-server/tests/helpers"
|
||||
)
|
||||
@@ -44,6 +45,22 @@ func TestPageRead(t *testing.T) {
|
||||
End()
|
||||
}
|
||||
|
||||
func TestPageReadByHandle(t *testing.T) {
|
||||
h := newHelper(t)
|
||||
|
||||
h.allow(types.NamespacePermissionResource.AppendWildcard(), "read")
|
||||
h.allow(types.PagePermissionResource.AppendWildcard(), "read")
|
||||
ns := h.repoMakeNamespace("some-namespace")
|
||||
c := h.repoMakePage(ns, "some-page")
|
||||
|
||||
cbh, err := service.DefaultPage.With(h.secCtx()).FindByHandle(ns.ID, c.Handle)
|
||||
|
||||
h.a.NoError(err)
|
||||
h.a.NotNil(cbh)
|
||||
h.a.Equal(cbh.ID, c.ID)
|
||||
h.a.Equal(cbh.Handle, c.Handle)
|
||||
}
|
||||
|
||||
func TestPageList(t *testing.T) {
|
||||
h := newHelper(t)
|
||||
|
||||
|
||||
@@ -43,6 +43,16 @@ var (
|
||||
p = permissions.NewTestService()
|
||||
)
|
||||
|
||||
// random string, 10 chars long by default
|
||||
func rs(a ...int) string {
|
||||
var l = 10
|
||||
if len(a) > 0 {
|
||||
l = a[0]
|
||||
}
|
||||
|
||||
return string(rand.Bytes(l))
|
||||
}
|
||||
|
||||
func db() *factory.DB {
|
||||
return factory.Database.MustGet("system").With(context.Background())
|
||||
}
|
||||
|
||||
+54
-15
@@ -6,9 +6,9 @@ import (
|
||||
"net/http"
|
||||
"testing"
|
||||
|
||||
"github.com/davecgh/go-spew/spew"
|
||||
jsonpath "github.com/steinfletcher/apitest-jsonpath"
|
||||
|
||||
"github.com/cortezaproject/corteza-server/internal/rand"
|
||||
"github.com/cortezaproject/corteza-server/system/repository"
|
||||
"github.com/cortezaproject/corteza-server/system/types"
|
||||
"github.com/cortezaproject/corteza-server/tests/helpers"
|
||||
@@ -18,19 +18,32 @@ func (h helper) repoRole() repository.RoleRepository {
|
||||
return repository.Role(context.Background(), db())
|
||||
}
|
||||
|
||||
func (h helper) repoMakeRole(name string) *types.Role {
|
||||
u, err := h.
|
||||
func (h helper) repoMakeRole(ss ...string) *types.Role {
|
||||
var r = &types.Role{}
|
||||
if len(ss) > 1 {
|
||||
r.Handle = ss[1]
|
||||
} else {
|
||||
r.Handle = rs()
|
||||
|
||||
}
|
||||
if len(ss) > 0 {
|
||||
r.Name = ss[0]
|
||||
} else {
|
||||
r.Name = rs()
|
||||
}
|
||||
|
||||
r, err := h.
|
||||
repoRole().
|
||||
Create(&types.Role{Name: name})
|
||||
Create(r)
|
||||
h.a.NoError(err)
|
||||
|
||||
return u
|
||||
return r
|
||||
}
|
||||
|
||||
func TestRoleRead(t *testing.T) {
|
||||
h := newHelper(t)
|
||||
|
||||
u := h.repoMakeRole(string(rand.Bytes(10)))
|
||||
u := h.repoMakeRole()
|
||||
|
||||
h.apiInit().
|
||||
Get(fmt.Sprintf("/roles/%d", u.ID)).
|
||||
@@ -61,21 +74,47 @@ func TestRoleCreateForbidden(t *testing.T) {
|
||||
|
||||
h.apiInit().
|
||||
Post("/roles/").
|
||||
FormData("name", string(rand.Bytes(10))).
|
||||
FormData("name", rs()).
|
||||
Expect(t).
|
||||
Status(http.StatusOK).
|
||||
Assert(helpers.AssertError("system.service.NoCreatePermissions")).
|
||||
End()
|
||||
}
|
||||
|
||||
func TestRoleCreateNotUnique(t *testing.T) {
|
||||
h := newHelper(t)
|
||||
h.allow(types.SystemPermissionResource, "role.create")
|
||||
|
||||
role := h.repoMakeRole()
|
||||
spew.Dump(role)
|
||||
h.apiInit().
|
||||
Post("/roles/").
|
||||
FormData("name", rs()).
|
||||
FormData("handle", role.Handle).
|
||||
Expect(t).
|
||||
Status(http.StatusOK).
|
||||
Assert(helpers.AssertError("system.service.RoleHandleNotUnique")).
|
||||
End()
|
||||
|
||||
h.apiInit().
|
||||
Post("/roles/").
|
||||
FormData("name", role.Name).
|
||||
FormData("handle", rs()).
|
||||
Expect(t).
|
||||
Status(http.StatusOK).
|
||||
Assert(helpers.AssertError("system.service.RoleNameNotUnique")).
|
||||
End()
|
||||
|
||||
}
|
||||
|
||||
func TestRoleCreate(t *testing.T) {
|
||||
h := newHelper(t)
|
||||
h.allow(types.SystemPermissionResource, "role.create")
|
||||
|
||||
h.apiInit().
|
||||
Post("/roles/").
|
||||
FormData("name", string(rand.Bytes(10))).
|
||||
FormData("handle", string(rand.Bytes(10))).
|
||||
FormData("name", rs()).
|
||||
FormData("handle", rs()).
|
||||
Expect(t).
|
||||
Status(http.StatusOK).
|
||||
Assert(helpers.AssertNoErrors).
|
||||
@@ -84,7 +123,7 @@ func TestRoleCreate(t *testing.T) {
|
||||
|
||||
func TestRoleUpdateForbidden(t *testing.T) {
|
||||
h := newHelper(t)
|
||||
u := h.repoMakeRole(string(rand.Bytes(10)))
|
||||
u := h.repoMakeRole()
|
||||
|
||||
h.apiInit().
|
||||
Put(fmt.Sprintf("/roles/%d", u.ID)).
|
||||
@@ -97,11 +136,11 @@ func TestRoleUpdateForbidden(t *testing.T) {
|
||||
|
||||
func TestRoleUpdate(t *testing.T) {
|
||||
h := newHelper(t)
|
||||
u := h.repoMakeRole(string(rand.Bytes(10)))
|
||||
u := h.repoMakeRole()
|
||||
h.allow(types.RolePermissionResource.AppendWildcard(), "update")
|
||||
|
||||
newName := "updated-" + string(rand.Bytes(10))
|
||||
newHandle := "updated-" + string(rand.Bytes(10))
|
||||
newName := "updated-" + rs()
|
||||
newHandle := "updated-" + rs()
|
||||
|
||||
h.apiInit().
|
||||
Put(fmt.Sprintf("/roles/%d", u.ID)).
|
||||
@@ -121,7 +160,7 @@ func TestRoleUpdate(t *testing.T) {
|
||||
|
||||
func TestRoleDeleteForbidden(t *testing.T) {
|
||||
h := newHelper(t)
|
||||
u := h.repoMakeRole(string(rand.Bytes(10)))
|
||||
u := h.repoMakeRole()
|
||||
|
||||
h.apiInit().
|
||||
Delete(fmt.Sprintf("/roles/%d", u.ID)).
|
||||
@@ -135,7 +174,7 @@ func TestRoleDelete(t *testing.T) {
|
||||
h := newHelper(t)
|
||||
h.allow(types.RolePermissionResource.AppendWildcard(), "delete")
|
||||
|
||||
u := h.repoMakeRole(string(rand.Bytes(10)))
|
||||
u := h.repoMakeRole()
|
||||
|
||||
h.apiInit().
|
||||
Delete(fmt.Sprintf("/roles/%d", u.ID)).
|
||||
|
||||
@@ -7,7 +7,6 @@ import (
|
||||
"testing"
|
||||
|
||||
jsonpath "github.com/steinfletcher/apitest-jsonpath"
|
||||
"github.com/titpetric/factory"
|
||||
|
||||
"github.com/cortezaproject/corteza-server/system/repository"
|
||||
"github.com/cortezaproject/corteza-server/system/types"
|
||||
@@ -15,7 +14,7 @@ import (
|
||||
)
|
||||
|
||||
func (h helper) randEmail() string {
|
||||
return fmt.Sprintf("%d@test.tld", factory.Sonyflake.NextID())
|
||||
return fmt.Sprintf("%s@test.tld", rs())
|
||||
}
|
||||
|
||||
func (h helper) repoUser() repository.UserRepository {
|
||||
|
||||
Reference in New Issue
Block a user