Apply namespace changes to all layers of modules
This commit is contained in:
+21
-2
@@ -185,7 +185,7 @@
|
||||
},
|
||||
{
|
||||
"title": "Pages",
|
||||
"description": "Compose module pages",
|
||||
"description": "Compose pages",
|
||||
"entrypoint": "page",
|
||||
"path": "/namespace/{namespaceID}/page",
|
||||
"authentication": [],
|
||||
@@ -432,7 +432,8 @@
|
||||
{
|
||||
"imports": [
|
||||
"sqlxTypes github.com/jmoiron/sqlx/types",
|
||||
"github.com/crusttech/crust/compose/types"
|
||||
"github.com/crusttech/crust/compose/types",
|
||||
"time"
|
||||
]
|
||||
}
|
||||
],
|
||||
@@ -449,6 +450,18 @@
|
||||
"name": "query",
|
||||
"required": false,
|
||||
"title": "Search query"
|
||||
},
|
||||
{
|
||||
"name": "page",
|
||||
"type": "uint",
|
||||
"required": false,
|
||||
"title": "Page number (0 based)"
|
||||
},
|
||||
{
|
||||
"name": "perPage",
|
||||
"type": "uint",
|
||||
"required": false,
|
||||
"title": "Returned items per page (default 50)"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -529,6 +542,12 @@
|
||||
"name": "meta",
|
||||
"required": true,
|
||||
"title": "Module meta data"
|
||||
},
|
||||
{
|
||||
"type": "*time.Time",
|
||||
"name": "updatedAt",
|
||||
"required": false,
|
||||
"title": "Last update (or creation) date"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
@@ -6,7 +6,8 @@
|
||||
{
|
||||
"imports": [
|
||||
"sqlxTypes github.com/jmoiron/sqlx/types",
|
||||
"github.com/crusttech/crust/compose/types"
|
||||
"github.com/crusttech/crust/compose/types",
|
||||
"time"
|
||||
]
|
||||
}
|
||||
],
|
||||
@@ -36,6 +37,18 @@
|
||||
"required": false,
|
||||
"title": "Search query",
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"name": "page",
|
||||
"required": false,
|
||||
"title": "Page number (0 based)",
|
||||
"type": "uint"
|
||||
},
|
||||
{
|
||||
"name": "perPage",
|
||||
"required": false,
|
||||
"title": "Returned items per page (default 50)",
|
||||
"type": "uint"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -116,6 +129,12 @@
|
||||
"required": true,
|
||||
"title": "Module meta data",
|
||||
"type": "sqlxTypes.JSONText"
|
||||
},
|
||||
{
|
||||
"name": "updatedAt",
|
||||
"required": false,
|
||||
"title": "Last update (or creation) date",
|
||||
"type": "*time.Time"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"Title": "Pages",
|
||||
"Description": "Compose module pages",
|
||||
"Description": "Compose pages",
|
||||
"Interface": "Page",
|
||||
"Struct": [
|
||||
{
|
||||
|
||||
@@ -7,6 +7,7 @@ import (
|
||||
"github.com/jmoiron/sqlx"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/titpetric/factory"
|
||||
"gopkg.in/Masterminds/squirrel.v1"
|
||||
|
||||
"github.com/crusttech/crust/compose/types"
|
||||
)
|
||||
@@ -15,11 +16,12 @@ type (
|
||||
ModuleRepository interface {
|
||||
With(ctx context.Context, db *factory.DB) ModuleRepository
|
||||
|
||||
FindByID(id uint64) (*types.Module, error)
|
||||
Find() (types.ModuleSet, error)
|
||||
FindByID(namespaceID, moduleID uint64) (*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)
|
||||
Update(mod *types.Module) (*types.Module, error)
|
||||
DeleteByID(id uint64) error
|
||||
DeleteByID(namespaceID, moduleID uint64) error
|
||||
}
|
||||
|
||||
module struct {
|
||||
@@ -28,60 +30,81 @@ type (
|
||||
)
|
||||
|
||||
const (
|
||||
sqlModuleColumns = `
|
||||
id, name, json,
|
||||
created_at, updated_at, deleted_at
|
||||
`
|
||||
sqlModuleSelect = `
|
||||
SELECT ` + sqlModuleColumns + ` FROM compose_module WHERE deleted_at IS NULL
|
||||
`
|
||||
ErrModuleNotFound = repositoryError("ModuleNotFound")
|
||||
)
|
||||
|
||||
func Module(ctx context.Context, db *factory.DB) ModuleRepository {
|
||||
return (&module{}).With(ctx, db)
|
||||
}
|
||||
|
||||
func (r *module) With(ctx context.Context, db *factory.DB) ModuleRepository {
|
||||
func (r module) With(ctx context.Context, db *factory.DB) ModuleRepository {
|
||||
return &module{
|
||||
repository: r.repository.With(ctx, db),
|
||||
}
|
||||
}
|
||||
|
||||
// @todo: update to accepted DeletedAt column semantics from Messaging
|
||||
|
||||
func (r *module) FindByID(id uint64) (mod *types.Module, err error) {
|
||||
mod = &types.Module{}
|
||||
|
||||
if err = r.db().Get(mod, sqlModuleSelect+" AND id = ? ", id); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
if mod.Fields, err = r.fields(id); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
return
|
||||
func (r module) table() string {
|
||||
return "compose_module"
|
||||
}
|
||||
|
||||
func (r *module) Find() (mm types.ModuleSet, err error) {
|
||||
if err = r.db().Select(&mm, sqlModuleSelect+" ORDER BY id ASC"); err != nil {
|
||||
return
|
||||
func (r module) columns() []string {
|
||||
return []string{
|
||||
"id", "rel_namespace", "name", "json",
|
||||
"created_at", "updated_at", "deleted_at",
|
||||
}
|
||||
|
||||
var ff types.ModuleFieldSet
|
||||
if ff, err = r.fields(mm.IDs()...); err != nil {
|
||||
return
|
||||
} else {
|
||||
_ = ff.Walk(func(f *types.ModuleField) error {
|
||||
mm.FindByID(f.ModuleID).Fields = append(mm.FindByID(f.ModuleID).Fields, f)
|
||||
return nil
|
||||
})
|
||||
}
|
||||
|
||||
return mm, nil
|
||||
}
|
||||
|
||||
func (r *module) Create(mod *types.Module) (*types.Module, error) {
|
||||
func (r module) query() squirrel.SelectBuilder {
|
||||
return squirrel.
|
||||
Select().
|
||||
From(r.table()).
|
||||
Where("deleted_at IS NULL")
|
||||
|
||||
}
|
||||
|
||||
func (r module) FindByID(namespaceID, moduleID uint64) (*types.Module, error) {
|
||||
var (
|
||||
query = r.query().
|
||||
Columns(r.columns()...).
|
||||
Where("id = ?", moduleID)
|
||||
|
||||
c = &types.Module{}
|
||||
)
|
||||
|
||||
if namespaceID > 0 {
|
||||
query = query.Where("rel_namespace = ?", namespaceID)
|
||||
}
|
||||
|
||||
return c, isFound(r.fetchOne(c, query), c.ID > 0, ErrModuleNotFound)
|
||||
}
|
||||
|
||||
func (r module) Find(filter types.ModuleFilter) (set types.ModuleSet, f types.ModuleFilter, err error) {
|
||||
f = filter
|
||||
f.PerPage = normalizePerPage(f.PerPage, 5, 100, 50)
|
||||
|
||||
query := r.query()
|
||||
|
||||
if filter.NamespaceID > 0 {
|
||||
query = query.Where("a.rel_namespace = ?", filter.NamespaceID)
|
||||
}
|
||||
|
||||
if f.Query != "" {
|
||||
q := "%" + f.Query + "%"
|
||||
query = query.Where("name like ?", q)
|
||||
}
|
||||
|
||||
if f.Count, err = r.count(query); err != nil || f.Count == 0 {
|
||||
return
|
||||
}
|
||||
|
||||
query = query.
|
||||
Columns(r.columns()...).
|
||||
OrderBy("id ASC")
|
||||
|
||||
return set, f, r.fetchPaged(&set, query, f.Page, f.PerPage)
|
||||
}
|
||||
|
||||
func (r module) Create(mod *types.Module) (*types.Module, error) {
|
||||
mod.ID = factory.Sonyflake.NextID()
|
||||
mod.CreatedAt = time.Now()
|
||||
|
||||
@@ -89,10 +112,10 @@ func (r *module) Create(mod *types.Module) (*types.Module, error) {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return mod, r.db().Insert("compose_module", mod)
|
||||
return mod, r.db().Insert(r.table(), mod)
|
||||
}
|
||||
|
||||
func (r *module) Update(mod *types.Module) (*types.Module, error) {
|
||||
func (r module) Update(mod *types.Module) (*types.Module, error) {
|
||||
now := time.Now()
|
||||
mod.UpdatedAt = &now
|
||||
|
||||
@@ -100,10 +123,10 @@ func (r *module) Update(mod *types.Module) (*types.Module, error) {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return mod, r.db().Replace("compose_module", mod)
|
||||
return mod, r.db().Replace(r.table(), mod)
|
||||
}
|
||||
|
||||
func (r *module) updateFields(moduleID uint64, ff types.ModuleFieldSet) error {
|
||||
func (r module) updateFields(moduleID uint64, ff types.ModuleFieldSet) error {
|
||||
// @todo be more selective when deleting
|
||||
if _, err := r.db().Exec("DELETE FROM compose_module_form WHERE module_id = ?", moduleID); err != nil {
|
||||
return errors.Wrap(err, "Error updating module fields")
|
||||
@@ -120,32 +143,24 @@ func (r *module) updateFields(moduleID uint64, ff types.ModuleFieldSet) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (r *module) DeleteByID(id uint64) error {
|
||||
_, err := r.db().Exec("DELETE FROM compose_module WHERE id=?", id)
|
||||
func (r module) DeleteByID(namespaceID, attachmentID uint64) error {
|
||||
_, err := r.db().Exec(
|
||||
"UPDATE "+r.table()+" SET deleted_at = NOW() WHERE rel_namespace = ? AND id = ?",
|
||||
namespaceID,
|
||||
attachmentID,
|
||||
)
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
func (r *module) fields(IDs ...uint64) (ff types.ModuleFieldSet, err error) {
|
||||
if len(IDs) == 0 {
|
||||
func (r module) FindFields(moduleIDs ...uint64) (ff types.ModuleFieldSet, err error) {
|
||||
if len(moduleIDs) == 0 {
|
||||
return
|
||||
}
|
||||
|
||||
if sql, args, err := sqlx.In("SELECT * FROM compose_module_form WHERE module_id IN (?) ORDER BY module_id AND place", IDs); err != nil {
|
||||
if sql, args, err := sqlx.In("SELECT * FROM compose_module_form WHERE module_id IN (?) ORDER BY module_id AND place", moduleIDs); err != nil {
|
||||
return nil, err
|
||||
} else {
|
||||
return ff, r.db().Select(&ff, sql, args...)
|
||||
}
|
||||
}
|
||||
|
||||
// // FieldNames returns a slice of field names, used for ordering record row columns
|
||||
// func (r *module) FieldNames(mod *types.Module) ([]string, error) {
|
||||
// if fields, err := r.Fields(mod.ID); err != nil {
|
||||
// return []string{}, err
|
||||
// } else {
|
||||
// result := make([]string, len(fields))
|
||||
// for k, v := range fields {
|
||||
// result[k] = v.Name
|
||||
// }
|
||||
// return result, nil
|
||||
// }
|
||||
// }
|
||||
|
||||
@@ -114,7 +114,7 @@ func (svc attachment) Find(filter types.AttachmentFilter) (types.AttachmentSet,
|
||||
}
|
||||
|
||||
if filter.ModuleID > 0 {
|
||||
if _, err := svc.moduleSvc.FindByID(filter.ModuleID); err != nil {
|
||||
if _, err := svc.moduleSvc.FindByID(filter.NamespaceID, filter.ModuleID); err != nil {
|
||||
return nil, filter, err
|
||||
}
|
||||
}
|
||||
@@ -174,7 +174,7 @@ func (svc attachment) CreateRecordAttachment(namespaceID uint64, name string, si
|
||||
|
||||
var currentUserID uint64 = auth.GetIdentityFromContext(svc.ctx).Identity()
|
||||
|
||||
if _, err := svc.moduleSvc.FindByID(moduleID); err != nil {
|
||||
if _, err := svc.moduleSvc.FindByID(namespaceID, moduleID); err != nil {
|
||||
return nil, err
|
||||
} else if r, err := svc.recordSvc.FindByID(recordID); err != nil {
|
||||
return nil, err
|
||||
|
||||
@@ -3,7 +3,6 @@ package service
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
"github.com/titpetric/factory"
|
||||
|
||||
"github.com/crusttech/crust/compose/internal/repository"
|
||||
@@ -24,12 +23,12 @@ type (
|
||||
ModuleService interface {
|
||||
With(ctx context.Context) ModuleService
|
||||
|
||||
FindByID(moduleID uint64) (*types.Module, error)
|
||||
Find() (types.ModuleSet, error)
|
||||
FindByID(namespaceID, moduleID uint64) (*types.Module, error)
|
||||
Find(filter types.ModuleFilter) (set types.ModuleSet, f types.ModuleFilter, err error)
|
||||
|
||||
Create(module *types.Module) (*types.Module, error)
|
||||
Update(module *types.Module) (*types.Module, error)
|
||||
DeleteByID(moduleID uint64) error
|
||||
DeleteByID(namespaceID, moduleID uint64) error
|
||||
}
|
||||
)
|
||||
|
||||
@@ -52,75 +51,96 @@ func (svc *module) With(ctx context.Context) ModuleService {
|
||||
}
|
||||
}
|
||||
|
||||
func (svc *module) FindByID(id uint64) (m *types.Module, err error) {
|
||||
if m, err = svc.moduleRepo.FindByID(id); err != nil {
|
||||
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 {
|
||||
return
|
||||
} else if !svc.prmSvc.CanReadModule(m) {
|
||||
return nil, errors.New("not allowed to access this module")
|
||||
return nil, ErrNoReadPermissions.withStack()
|
||||
}
|
||||
|
||||
var ff types.ModuleFieldSet
|
||||
if ff, err = svc.moduleRepo.FindFields(m.ID); err != nil {
|
||||
return
|
||||
} else {
|
||||
_ = ff.Walk(func(f *types.ModuleField) error {
|
||||
m.Fields = append(m.Fields, f)
|
||||
return nil
|
||||
})
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func (svc *module) Find() (mm types.ModuleSet, err error) {
|
||||
if mm, err = svc.moduleRepo.Find(); err != nil {
|
||||
return nil, err
|
||||
func (svc *module) Find(filter types.ModuleFilter) (set types.ModuleSet, f types.ModuleFilter, err error) {
|
||||
set, f, err = svc.moduleRepo.Find(filter)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
set, _ = set.Filter(func(m *types.Module) (bool, error) {
|
||||
return svc.prmSvc.CanReadModule(m), nil
|
||||
})
|
||||
|
||||
// Preload all fields and update all modules
|
||||
var ff types.ModuleFieldSet
|
||||
if ff, err = svc.moduleRepo.FindFields(set.IDs()...); err != nil {
|
||||
return
|
||||
} else {
|
||||
return mm.Filter(func(m *types.Module) (bool, error) {
|
||||
return svc.prmSvc.CanReadModule(m), nil
|
||||
_ = ff.Walk(func(f *types.ModuleField) error {
|
||||
set.FindByID(f.ModuleID).Fields = append(set.FindByID(f.ModuleID).Fields, f)
|
||||
return nil
|
||||
})
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func (svc *module) Create(mod *types.Module) (*types.Module, error) {
|
||||
if !svc.prmSvc.CanCreateModule(crmNamespace()) {
|
||||
return nil, errors.New("not allowed to create this module")
|
||||
}
|
||||
|
||||
if len(mod.Fields) == 0 {
|
||||
return nil, errors.New("Error creating module: no fields")
|
||||
return nil, ErrNoCreatePermissions.withStack()
|
||||
}
|
||||
|
||||
return svc.moduleRepo.Create(mod)
|
||||
}
|
||||
|
||||
func (svc *module) Update(module *types.Module) (m *types.Module, err error) {
|
||||
validate := func() error {
|
||||
if module.ID == 0 {
|
||||
return errors.New("Error updating module: invalid ID")
|
||||
} else if m, err = svc.moduleRepo.FindByID(module.ID); err != nil {
|
||||
return errors.Wrap(err, "Error while loading module for update")
|
||||
} else {
|
||||
if !svc.prmSvc.CanUpdateModule(m) {
|
||||
return errors.New("not allowed to update this module")
|
||||
}
|
||||
|
||||
module.CreatedAt = m.CreatedAt
|
||||
}
|
||||
|
||||
if len(module.Fields) == 0 {
|
||||
return errors.New("Error updating module: no fields")
|
||||
}
|
||||
|
||||
return nil
|
||||
func (svc *module) Update(mod *types.Module) (m *types.Module, err error) {
|
||||
if mod.ID == 0 {
|
||||
return nil, ErrInvalidID.withStack()
|
||||
}
|
||||
|
||||
if err = validate(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return m, svc.db.Transaction(func() (err error) {
|
||||
m, err = svc.moduleRepo.Update(module)
|
||||
if m, err = svc.moduleRepo.FindByID(mod.NamespaceID, mod.ID); err != nil {
|
||||
return
|
||||
})
|
||||
}
|
||||
|
||||
func (svc *module) DeleteByID(ID uint64) error {
|
||||
if m, err := svc.moduleRepo.FindByID(ID); err != nil {
|
||||
return errors.Wrap(err, "could not delete module")
|
||||
} else if !svc.prmSvc.CanDeleteModule(m) {
|
||||
return errors.New("not allowed to delete this module")
|
||||
}
|
||||
|
||||
return svc.moduleRepo.DeleteByID(ID)
|
||||
if isStale(mod.UpdatedAt, m.UpdatedAt, m.CreatedAt) {
|
||||
return nil, ErrStaleData.withStack()
|
||||
}
|
||||
|
||||
if !svc.prmSvc.CanUpdateModule(m) {
|
||||
return nil, ErrNoUpdatePermissions.withStack()
|
||||
}
|
||||
|
||||
m.Name = mod.Name
|
||||
m.Meta = mod.Meta
|
||||
m.Fields = mod.Fields
|
||||
|
||||
return svc.moduleRepo.Update(m)
|
||||
}
|
||||
|
||||
func (svc *module) DeleteByID(namespaceID, moduleID uint64) error {
|
||||
if namespaceID == 0 {
|
||||
return ErrNamespaceRequired.withStack()
|
||||
}
|
||||
|
||||
if c, err := svc.moduleRepo.FindByID(namespaceID, moduleID); err != nil {
|
||||
return err
|
||||
} else if !svc.prmSvc.CanDeleteModule(c) {
|
||||
return ErrNoDeletePermissions.withStack()
|
||||
}
|
||||
|
||||
return svc.moduleRepo.DeleteByID(namespaceID, moduleID)
|
||||
}
|
||||
|
||||
@@ -85,9 +85,10 @@ func (svc *record) FindByID(recordID uint64) (r *types.Record, err error) {
|
||||
|
||||
func (svc *record) Report(moduleID uint64, metrics, dimensions, filter string) (out interface{}, err error) {
|
||||
var module *types.Module
|
||||
var namespaceID uint64 = 0
|
||||
|
||||
err = svc.db.Transaction(func() (err error) {
|
||||
if module, err = svc.moduleRepo.FindByID(moduleID); err != nil {
|
||||
if module, err = svc.moduleRepo.FindByID(namespaceID, moduleID); err != nil {
|
||||
return
|
||||
} else if !svc.prmSvc.CanReadRecord(module) {
|
||||
return errors.New("not allowed to access this record")
|
||||
@@ -102,9 +103,10 @@ func (svc *record) Report(moduleID uint64, metrics, dimensions, filter string) (
|
||||
|
||||
func (svc *record) Find(moduleID uint64, filter, sort string, page, perPage int) (rsp *repository.FindResponse, err error) {
|
||||
var module *types.Module
|
||||
var namespaceID uint64 = 0
|
||||
|
||||
err = svc.db.Transaction(func() (err error) {
|
||||
if module, err = svc.moduleRepo.FindByID(moduleID); err != nil {
|
||||
if module, err = svc.moduleRepo.FindByID(namespaceID, moduleID); err != nil {
|
||||
return
|
||||
} else if !svc.prmSvc.CanReadRecord(module) {
|
||||
return errors.New("not allowed to access this record")
|
||||
@@ -129,7 +131,7 @@ func (svc *record) Create(in *types.Record) (record *types.Record, err error) {
|
||||
var module *types.Module
|
||||
|
||||
err = svc.db.Transaction(func() (err error) {
|
||||
if module, err = svc.moduleRepo.FindByID(in.ModuleID); err != nil {
|
||||
if module, err = svc.moduleRepo.FindByID(in.NamespaceID, in.ModuleID); err != nil {
|
||||
return
|
||||
} else if !svc.prmSvc.CanCreateRecord(module) {
|
||||
return errors.New("not allowed to create records for this module")
|
||||
@@ -174,7 +176,7 @@ func (svc *record) Update(updated *types.Record) (record *types.Record, err erro
|
||||
return errors.New("not allowed to update this record")
|
||||
}
|
||||
|
||||
if module, err = svc.moduleRepo.FindByID(updated.ModuleID); err != nil {
|
||||
if module, err = svc.moduleRepo.FindByID(updated.NamespaceID, updated.ModuleID); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
+86
-17
@@ -11,29 +11,50 @@ import (
|
||||
)
|
||||
|
||||
type (
|
||||
modulePayload struct {
|
||||
*types.Module
|
||||
|
||||
CanUpdateModule bool `json:"canUpdateModule"`
|
||||
CanDeleteModule bool `json:"canDeleteModule"`
|
||||
CanCreateRecord bool `json:"canCreateRecord"`
|
||||
CanReadRecord bool `json:"canReadRecord"`
|
||||
CanUpdateRecord bool `json:"canUpdateRecord"`
|
||||
CanDeleteRecord bool `json:"canDeleteRecord"`
|
||||
}
|
||||
|
||||
moduleSetPayload struct {
|
||||
Filter types.ModuleFilter `json:"filter"`
|
||||
Set []*modulePayload `json:"set"`
|
||||
}
|
||||
|
||||
Module struct {
|
||||
module service.ModuleService
|
||||
record service.RecordService
|
||||
module service.ModuleService
|
||||
record service.RecordService
|
||||
permissions service.PermissionsService
|
||||
}
|
||||
)
|
||||
|
||||
func (Module) New() *Module {
|
||||
return &Module{
|
||||
module: service.DefaultModule,
|
||||
record: service.DefaultRecord,
|
||||
module: service.DefaultModule,
|
||||
record: service.DefaultRecord,
|
||||
permissions: service.DefaultPermissions,
|
||||
}
|
||||
}
|
||||
|
||||
func (ctrl *Module) List(ctx context.Context, r *request.ModuleList) (interface{}, error) {
|
||||
return ctrl.module.With(ctx).Find()
|
||||
f := types.ModuleFilter{
|
||||
Query: r.Query,
|
||||
PerPage: r.PerPage,
|
||||
Page: r.Page,
|
||||
}
|
||||
|
||||
set, filter, err := ctrl.module.With(ctx).Find(f)
|
||||
return ctrl.makeFilterPayload(ctx, set, filter, err)
|
||||
}
|
||||
|
||||
func (ctrl *Module) Read(ctx context.Context, r *request.ModuleRead) (interface{}, error) {
|
||||
return ctrl.module.With(ctx).FindByID(r.ModuleID)
|
||||
}
|
||||
|
||||
func (ctrl *Module) Delete(ctx context.Context, r *request.ModuleDelete) (interface{}, error) {
|
||||
return resputil.OK(), ctrl.module.With(ctx).DeleteByID(r.ModuleID)
|
||||
return ctrl.module.With(ctx).FindByID(r.NamespaceID, r.ModuleID)
|
||||
}
|
||||
|
||||
func (ctrl *Module) Create(ctx context.Context, r *request.ModuleCreate) (interface{}, error) {
|
||||
@@ -46,11 +67,59 @@ func (ctrl *Module) Create(ctx context.Context, r *request.ModuleCreate) (interf
|
||||
}
|
||||
|
||||
func (ctrl *Module) Update(ctx context.Context, r *request.ModuleUpdate) (interface{}, error) {
|
||||
item := &types.Module{
|
||||
ID: r.ModuleID,
|
||||
Name: r.Name,
|
||||
Fields: r.Fields,
|
||||
Meta: r.Meta,
|
||||
}
|
||||
return ctrl.module.With(ctx).Update(item)
|
||||
var (
|
||||
m = &types.Module{}
|
||||
err error
|
||||
)
|
||||
|
||||
m.ID = r.ModuleID
|
||||
m.Name = r.Name
|
||||
m.Meta = r.Meta
|
||||
m.NamespaceID = r.NamespaceID
|
||||
m.UpdatedAt = r.UpdatedAt
|
||||
|
||||
m, err = ctrl.module.With(ctx).Update(m)
|
||||
return ctrl.makePayload(ctx, m, err)
|
||||
}
|
||||
|
||||
func (ctrl *Module) Delete(ctx context.Context, r *request.ModuleDelete) (interface{}, error) {
|
||||
_, err := ctrl.module.With(ctx).FindByID(r.NamespaceID, r.ModuleID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return resputil.OK(), ctrl.module.With(ctx).DeleteByID(r.NamespaceID, r.ModuleID)
|
||||
}
|
||||
|
||||
func (ctrl Module) makePayload(ctx context.Context, m *types.Module, err error) (*modulePayload, error) {
|
||||
if err != nil || m == nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
perm := ctrl.permissions.With(ctx)
|
||||
|
||||
return &modulePayload{
|
||||
Module: m,
|
||||
|
||||
CanUpdateModule: perm.CanUpdateModule(m),
|
||||
CanDeleteModule: perm.CanDeleteModule(m),
|
||||
CanCreateRecord: perm.CanCreateRecord(m),
|
||||
CanReadRecord: perm.CanReadRecord(m),
|
||||
CanUpdateRecord: perm.CanUpdateRecord(m),
|
||||
CanDeleteRecord: perm.CanDeleteRecord(m),
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (ctrl Module) makeFilterPayload(ctx context.Context, nn types.ModuleSet, f types.ModuleFilter, err error) (*moduleSetPayload, error) {
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
msp := &moduleSetPayload{Filter: f, Set: make([]*modulePayload, len(nn))}
|
||||
|
||||
for i := range nn {
|
||||
msp.Set[i], _ = ctrl.makePayload(ctx, nn[i], nil)
|
||||
}
|
||||
|
||||
return msp, nil
|
||||
}
|
||||
|
||||
@@ -28,6 +28,7 @@ import (
|
||||
|
||||
"github.com/crusttech/crust/compose/types"
|
||||
sqlxTypes "github.com/jmoiron/sqlx/types"
|
||||
"time"
|
||||
)
|
||||
|
||||
var _ = chi.URLParam
|
||||
@@ -36,6 +37,8 @@ var _ = multipart.FileHeader{}
|
||||
// Module list request parameters
|
||||
type ModuleList struct {
|
||||
Query string
|
||||
Page uint
|
||||
PerPage uint
|
||||
NamespaceID uint64 `json:",string"`
|
||||
}
|
||||
|
||||
@@ -74,6 +77,14 @@ func (mReq *ModuleList) Fill(r *http.Request) (err error) {
|
||||
|
||||
mReq.Query = val
|
||||
}
|
||||
if val, ok := get["page"]; ok {
|
||||
|
||||
mReq.Page = parseUint(val)
|
||||
}
|
||||
if val, ok := get["perPage"]; ok {
|
||||
|
||||
mReq.PerPage = parseUint(val)
|
||||
}
|
||||
mReq.NamespaceID = parseUInt64(chi.URLParam(r, "namespaceID"))
|
||||
|
||||
return err
|
||||
@@ -189,6 +200,7 @@ type ModuleUpdate struct {
|
||||
Name string
|
||||
Fields types.ModuleFieldSet
|
||||
Meta sqlxTypes.JSONText
|
||||
UpdatedAt *time.Time
|
||||
}
|
||||
|
||||
func NewModuleUpdate() *ModuleUpdate {
|
||||
@@ -234,6 +246,12 @@ func (mReq *ModuleUpdate) Fill(r *http.Request) (err error) {
|
||||
return err
|
||||
}
|
||||
}
|
||||
if val, ok := post["updatedAt"]; ok {
|
||||
|
||||
if mReq.UpdatedAt, err = parseISODatePtrWithErr(val); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -22,6 +22,15 @@ type (
|
||||
UpdatedAt *time.Time `db:"updated_at" json:"updatedAt,omitempty"`
|
||||
DeletedAt *time.Time `db:"deleted_at" json:"deletedAt,omitempty"`
|
||||
}
|
||||
|
||||
ModuleFilter struct {
|
||||
NamespaceID uint64 `json:"namespaceID,string"`
|
||||
Query string `json:"query"`
|
||||
Page uint `json:"page"`
|
||||
PerPage uint `json:"perPage"`
|
||||
// Sort string `json:"sort"`
|
||||
Count uint `json:"count"`
|
||||
}
|
||||
)
|
||||
|
||||
// Resource returns a system resource ID for this type
|
||||
|
||||
@@ -232,6 +232,8 @@ Compose module definitions
|
||||
| Parameter | Type | Method | Description | Default | Required? |
|
||||
| --------- | ---- | ------ | ----------- | ------- | --------- |
|
||||
| query | string | GET | Search query | N/A | NO |
|
||||
| page | uint | GET | Page number (0 based) | N/A | NO |
|
||||
| perPage | uint | GET | Returned items per page (default 50) | N/A | NO |
|
||||
| namespaceID | uint64 | PATH | Namespace ID | N/A | YES |
|
||||
|
||||
## Create module
|
||||
@@ -283,6 +285,7 @@ Compose module definitions
|
||||
| name | string | POST | Module Name | N/A | YES |
|
||||
| fields | types.ModuleFieldSet | POST | Fields JSON | N/A | YES |
|
||||
| meta | sqlxTypes.JSONText | POST | Module meta data | N/A | YES |
|
||||
| updatedAt | *time.Time | POST | Last update (or creation) date | N/A | NO |
|
||||
|
||||
## Delete module
|
||||
|
||||
@@ -432,7 +435,7 @@ Compose Notifications
|
||||
|
||||
# Pages
|
||||
|
||||
Compose module pages
|
||||
Compose pages
|
||||
|
||||
| Method | Endpoint | Purpose |
|
||||
| ------ | -------- | ------- |
|
||||
|
||||
Reference in New Issue
Block a user