Apply namespace changes to all layers of pages
This commit is contained in:
@@ -219,6 +219,24 @@
|
||||
"name": "selfID",
|
||||
"required": false,
|
||||
"title": "Parent page ID"
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"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)"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
@@ -35,6 +35,24 @@
|
||||
"required": false,
|
||||
"title": "Parent page ID",
|
||||
"type": "uint64"
|
||||
},
|
||||
{
|
||||
"name": "query",
|
||||
"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"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -0,0 +1,6 @@
|
||||
ALTER TABLE `compose_page`
|
||||
ADD COLUMN `created_at` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
ADD COLUMN `updated_at` DATETIME DEFAULT NULL,
|
||||
ADD COLUMN `deleted_at` DATETIME DEFAULT NULL;
|
||||
|
||||
ALTER TABLE `compose_page` CHANGE COLUMN `module_id` `rel_module` BIGINT UNSIGNED NOT NULL DEFAULT 0;
|
||||
@@ -14,11 +14,11 @@ type (
|
||||
ChartRepository interface {
|
||||
With(ctx context.Context, db *factory.DB) ChartRepository
|
||||
|
||||
FindByID(namespaceID, attachmentID uint64) (*types.Chart, error)
|
||||
FindByID(namespaceID, chartID uint64) (*types.Chart, 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)
|
||||
DeleteByID(namespaceID, attachmentID uint64) error
|
||||
DeleteByID(namespaceID, chartID uint64) error
|
||||
}
|
||||
|
||||
chart struct {
|
||||
@@ -81,7 +81,7 @@ func (r chart) Find(filter types.ChartFilter) (set types.ChartSet, f types.Chart
|
||||
query := r.query()
|
||||
|
||||
if filter.NamespaceID > 0 {
|
||||
query = query.Where("a.rel_namespace = ?", filter.NamespaceID)
|
||||
query = query.Where("rel_namespace = ?", filter.NamespaceID)
|
||||
}
|
||||
|
||||
if f.Query != "" {
|
||||
@@ -113,11 +113,11 @@ func (r chart) Update(mod *types.Chart) (*types.Chart, error) {
|
||||
return mod, r.db().Replace(r.table(), mod)
|
||||
}
|
||||
|
||||
func (r chart) DeleteByID(namespaceID, attachmentID uint64) error {
|
||||
func (r chart) DeleteByID(namespaceID, chartID uint64) error {
|
||||
_, err := r.db().Exec(
|
||||
"UPDATE "+r.table()+" SET deleted_at = NOW() WHERE rel_namespace = ? AND id = ?",
|
||||
namespaceID,
|
||||
attachmentID,
|
||||
chartID,
|
||||
)
|
||||
|
||||
return err
|
||||
|
||||
@@ -85,7 +85,7 @@ func (r module) Find(filter types.ModuleFilter) (set types.ModuleSet, f types.Mo
|
||||
query := r.query()
|
||||
|
||||
if filter.NamespaceID > 0 {
|
||||
query = query.Where("a.rel_namespace = ?", filter.NamespaceID)
|
||||
query = query.Where("rel_namespace = ?", filter.NamespaceID)
|
||||
}
|
||||
|
||||
if f.Query != "" {
|
||||
@@ -143,11 +143,11 @@ func (r module) updateFields(moduleID uint64, ff types.ModuleFieldSet) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (r module) DeleteByID(namespaceID, attachmentID uint64) error {
|
||||
func (r module) DeleteByID(namespaceID, moduleID uint64) error {
|
||||
_, err := r.db().Exec(
|
||||
"UPDATE "+r.table()+" SET deleted_at = NOW() WHERE rel_namespace = ? AND id = ?",
|
||||
namespaceID,
|
||||
attachmentID,
|
||||
moduleID,
|
||||
)
|
||||
|
||||
return err
|
||||
|
||||
@@ -2,8 +2,10 @@ package repository
|
||||
|
||||
import (
|
||||
"context"
|
||||
"time"
|
||||
|
||||
"github.com/titpetric/factory"
|
||||
"gopkg.in/Masterminds/squirrel.v1"
|
||||
|
||||
"github.com/crusttech/crust/compose/types"
|
||||
)
|
||||
@@ -12,17 +14,15 @@ type (
|
||||
PageRepository interface {
|
||||
With(ctx context.Context, db *factory.DB) PageRepository
|
||||
|
||||
FindByID(id uint64) (*types.Page, error)
|
||||
FindByModuleID(id uint64) (*types.Page, error)
|
||||
FindBySelfID(selfID uint64) (types.PageSet, error)
|
||||
Find() (types.PageSet, error)
|
||||
FindRecordPages() (types.PageSet, error)
|
||||
FindByID(namespaceID, pageID uint64) (*types.Page, error)
|
||||
FindByModuleID(namespaceID, pageID uint64) (*types.Page, error)
|
||||
Find(filter types.PageFilter) (set types.PageSet, f types.PageFilter, err error)
|
||||
|
||||
Create(mod *types.Page) (*types.Page, error)
|
||||
Update(mod *types.Page) (*types.Page, error)
|
||||
DeleteByID(id uint64) error
|
||||
DeleteByID(namespaceID, pageID uint64) error
|
||||
|
||||
Reorder(selfID uint64, pageIDs []uint64) error
|
||||
Reorder(namespaceID, selfID uint64, pageIDs []uint64) error
|
||||
}
|
||||
|
||||
page struct {
|
||||
@@ -30,51 +30,108 @@ type (
|
||||
}
|
||||
)
|
||||
|
||||
const (
|
||||
ErrPageNotFound = repositoryError("PageNotFound")
|
||||
)
|
||||
|
||||
func Page(ctx context.Context, db *factory.DB) PageRepository {
|
||||
return (&page{}).With(ctx, db)
|
||||
}
|
||||
|
||||
func (r *page) With(ctx context.Context, db *factory.DB) PageRepository {
|
||||
func (r page) With(ctx context.Context, db *factory.DB) PageRepository {
|
||||
return &page{
|
||||
repository: r.repository.With(ctx, db),
|
||||
}
|
||||
}
|
||||
|
||||
func (r *page) FindByID(id uint64) (*types.Page, error) {
|
||||
page := &types.Page{}
|
||||
if err := r.db().Get(page, "SELECT * FROM compose_page WHERE id=?", id); err != nil {
|
||||
return page, err
|
||||
func (r page) table() string {
|
||||
return "compose_page"
|
||||
}
|
||||
|
||||
func (r page) columns() []string {
|
||||
return []string{
|
||||
"id", "rel_namespace", "self_id", "rel_module", "title",
|
||||
"blocks", "description", "visible", "weight",
|
||||
"created_at", "updated_at", "deleted_at",
|
||||
}
|
||||
return page, nil
|
||||
}
|
||||
|
||||
func (r *page) FindByModuleID(id uint64) (*types.Page, error) {
|
||||
page := &types.Page{}
|
||||
if err := r.db().Get(page, "SELECT * FROM compose_page WHERE module_id=?", id); err != nil {
|
||||
return nil, err
|
||||
func (r page) query() squirrel.SelectBuilder {
|
||||
return squirrel.
|
||||
Select().
|
||||
From(r.table()).
|
||||
Where("deleted_at IS NULL")
|
||||
}
|
||||
|
||||
func (r page) FindByID(namespaceID, pageID uint64) (*types.Page, error) {
|
||||
var (
|
||||
query = r.query().
|
||||
Columns(r.columns()...).
|
||||
Where("id = ?", pageID)
|
||||
|
||||
c = &types.Page{}
|
||||
)
|
||||
|
||||
if namespaceID > 0 {
|
||||
query = query.Where("rel_namespace = ?", namespaceID)
|
||||
}
|
||||
return page, nil
|
||||
|
||||
return c, isFound(r.fetchOne(c, query), c.ID > 0, ErrPageNotFound)
|
||||
}
|
||||
|
||||
func (r *page) FindRecordPages() (set types.PageSet, err error) {
|
||||
return set, r.db().Select(&set, "SELECT * FROM compose_page WHERE module_id > 0")
|
||||
}
|
||||
func (r page) FindByModuleID(namespaceID, moduleID uint64) (*types.Page, error) {
|
||||
var (
|
||||
query = r.query().
|
||||
Columns(r.columns()...).
|
||||
Where("rel_module = ?", moduleID)
|
||||
|
||||
func (r *page) FindBySelfID(selfID uint64) (types.PageSet, error) {
|
||||
pages := types.PageSet{}
|
||||
if err := r.db().Select(&pages, "SELECT * FROM compose_page WHERE self_id = ? ORDER BY weight ASC", selfID); err != nil {
|
||||
return pages, err
|
||||
c = &types.Page{}
|
||||
)
|
||||
|
||||
if namespaceID > 0 {
|
||||
query = query.Where("rel_namespace = ?", namespaceID)
|
||||
}
|
||||
return pages, nil
|
||||
|
||||
return c, isFound(r.fetchOne(c, query), c.ID > 0, ErrPageNotFound)
|
||||
}
|
||||
|
||||
func (r *page) Find() (set types.PageSet, err error) {
|
||||
return set, r.db().Select(&set, "SELECT * FROM compose_page ORDER BY self_id, weight ASC")
|
||||
func (r page) Find(filter types.PageFilter) (set types.PageSet, f types.PageFilter, err error) {
|
||||
f = filter
|
||||
f.PerPage = normalizePerPage(f.PerPage, 5, 100, 50)
|
||||
|
||||
query := r.query()
|
||||
|
||||
if filter.NamespaceID > 0 {
|
||||
query = query.Where("rel_namespace = ?", filter.NamespaceID)
|
||||
}
|
||||
|
||||
if filter.ParentID > 0 {
|
||||
query = query.Where("self_id = ?", filter.ParentID)
|
||||
}
|
||||
|
||||
if f.Query != "" {
|
||||
q := "%" + f.Query + "%"
|
||||
query = query.Where("title LIKE ? OR description LIKE ?", q, q)
|
||||
}
|
||||
|
||||
if f.Count, err = r.count(query); err != nil || f.Count == 0 {
|
||||
return
|
||||
}
|
||||
|
||||
query = query.
|
||||
Columns(r.columns()...).
|
||||
OrderBy("weight ASC")
|
||||
|
||||
return set, f, r.fetchPaged(&set, query, f.Page, f.PerPage)
|
||||
}
|
||||
|
||||
func (r *page) Reorder(selfID uint64, pageIDs []uint64) error {
|
||||
pageMap := map[uint64]bool{}
|
||||
if pages, err := r.FindBySelfID(selfID); err != nil {
|
||||
func (r page) Reorder(namespaceID, parentID uint64, pageIDs []uint64) error {
|
||||
var (
|
||||
pageMap = map[uint64]bool{}
|
||||
filter = types.PageFilter{NamespaceID: namespaceID, ParentID: parentID}
|
||||
)
|
||||
|
||||
if pages, _, err := r.Find(filter); err != nil {
|
||||
return nil
|
||||
} else {
|
||||
for _, page := range pages {
|
||||
@@ -87,7 +144,7 @@ func (r *page) Reorder(selfID uint64, pageIDs []uint64) error {
|
||||
for _, pageID := range pageIDs {
|
||||
if pageMap[pageID] {
|
||||
pageMap[pageID] = false
|
||||
if _, err := db.Exec("UPDATE compose_page set weight=? where id=? and self_id=?", weight, pageID, selfID); err != nil {
|
||||
if _, err := db.Exec("UPDATE compose_page SET weight = ? WHERE id = ? AND self_id = ?", weight, pageID, parentID); err != nil {
|
||||
return err
|
||||
}
|
||||
weight++
|
||||
@@ -95,7 +152,7 @@ func (r *page) Reorder(selfID uint64, pageIDs []uint64) error {
|
||||
}
|
||||
for pageID, update := range pageMap {
|
||||
if update {
|
||||
if _, err := db.Exec("UPDATE compose_page set weight=? where id=? and self_id=?", weight, pageID, selfID); err != nil {
|
||||
if _, err := db.Exec("UPDATE compose_page SET weight = ? WHERE id = ? AND self_id = ?", weight, pageID, parentID); err != nil {
|
||||
return err
|
||||
}
|
||||
weight++
|
||||
@@ -104,19 +161,25 @@ func (r *page) Reorder(selfID uint64, pageIDs []uint64) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (r *page) Create(item *types.Page) (*types.Page, error) {
|
||||
page := &types.Page{}
|
||||
*page = *item
|
||||
func (r page) Create(mod *types.Page) (*types.Page, error) {
|
||||
mod.ID = factory.Sonyflake.NextID()
|
||||
mod.CreatedAt = time.Now()
|
||||
|
||||
page.ID = factory.Sonyflake.NextID()
|
||||
return page, r.db().Insert("compose_page", page)
|
||||
return mod, r.db().Insert(r.table(), mod)
|
||||
}
|
||||
|
||||
func (r *page) Update(page *types.Page) (*types.Page, error) {
|
||||
return page, r.db().Replace("compose_page", page)
|
||||
func (r page) Update(mod *types.Page) (*types.Page, error) {
|
||||
now := time.Now()
|
||||
mod.UpdatedAt = &now
|
||||
return mod, r.db().Replace(r.table(), mod)
|
||||
}
|
||||
|
||||
func (r *page) DeleteByID(id uint64) error {
|
||||
_, err := r.db().Exec("DELETE FROM compose_page WHERE id=?", id)
|
||||
func (r page) DeleteByID(namespaceID, pageID uint64) error {
|
||||
_, err := r.db().Exec(
|
||||
"UPDATE "+r.table()+" SET deleted_at = NOW() WHERE rel_namespace = ? AND id = ?",
|
||||
namespaceID,
|
||||
pageID,
|
||||
)
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -14,11 +14,11 @@ type (
|
||||
TriggerRepository interface {
|
||||
With(ctx context.Context, db *factory.DB) TriggerRepository
|
||||
|
||||
FindByID(namespaceID, attachmentID uint64) (*types.Trigger, error)
|
||||
FindByID(namespaceID, triggerID uint64) (*types.Trigger, error)
|
||||
Find(filter types.TriggerFilter) (set types.TriggerSet, f types.TriggerFilter, err error)
|
||||
Create(mod *types.Trigger) (*types.Trigger, error)
|
||||
Update(mod *types.Trigger) (*types.Trigger, error)
|
||||
DeleteByID(namespaceID, attachmentID uint64) error
|
||||
DeleteByID(namespaceID, triggerID uint64) error
|
||||
}
|
||||
|
||||
trigger struct {
|
||||
@@ -82,7 +82,7 @@ func (r trigger) Find(filter types.TriggerFilter) (set types.TriggerSet, f types
|
||||
query := r.query()
|
||||
|
||||
if filter.NamespaceID > 0 {
|
||||
query = query.Where("a.rel_namespace = ?", filter.NamespaceID)
|
||||
query = query.Where("rel_namespace = ?", filter.NamespaceID)
|
||||
}
|
||||
|
||||
if f.Query != "" {
|
||||
@@ -114,11 +114,11 @@ func (r trigger) Update(mod *types.Trigger) (*types.Trigger, error) {
|
||||
return mod, r.db().Replace(r.table(), mod)
|
||||
}
|
||||
|
||||
func (r trigger) DeleteByID(namespaceID, attachmentID uint64) error {
|
||||
func (r trigger) DeleteByID(namespaceID, triggerID uint64) error {
|
||||
_, err := r.db().Exec(
|
||||
"UPDATE "+r.table()+" SET deleted_at = NOW() WHERE rel_namespace = ? AND id = ?",
|
||||
namespaceID,
|
||||
attachmentID,
|
||||
triggerID,
|
||||
)
|
||||
|
||||
return err
|
||||
|
||||
@@ -108,7 +108,7 @@ func (svc attachment) Find(filter types.AttachmentFilter) (types.AttachmentSet,
|
||||
}
|
||||
|
||||
if filter.PageID > 0 {
|
||||
if _, err := svc.pageSvc.FindByID(filter.PageID); err != nil {
|
||||
if _, err := svc.pageSvc.FindByID(filter.NamespaceID, filter.PageID); err != nil {
|
||||
return nil, filter, err
|
||||
}
|
||||
}
|
||||
@@ -151,7 +151,7 @@ func (svc attachment) CreatePageAttachment(namespaceID uint64, name string, size
|
||||
|
||||
var currentUserID uint64 = auth.GetIdentityFromContext(svc.ctx).Identity()
|
||||
|
||||
if p, err := svc.pageSvc.FindByID(pageID); err != nil {
|
||||
if p, err := svc.pageSvc.FindByID(namespaceID, pageID); err != nil {
|
||||
return nil, err
|
||||
} else if !svc.prmSvc.CanUpdatePage(p) {
|
||||
return nil, errors.New("not allowed to add attachments to this page")
|
||||
|
||||
@@ -24,18 +24,17 @@ type (
|
||||
PageService interface {
|
||||
With(ctx context.Context) PageService
|
||||
|
||||
FindByID(pageID uint64) (*types.Page, error)
|
||||
FindByModuleID(moduleID uint64) (*types.Page, error)
|
||||
FindBySelfID(selfID uint64) (pages types.PageSet, err error)
|
||||
Find() (pages types.PageSet, err error)
|
||||
Tree() (pages types.PageSet, err error)
|
||||
FindRecordPages() (pages types.PageSet, err error)
|
||||
FindByID(namespaceID, pageID uint64) (*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)
|
||||
Tree(namespaceID uint64) (pages types.PageSet, err error)
|
||||
|
||||
Create(page *types.Page) (*types.Page, error)
|
||||
Update(page *types.Page) (*types.Page, error)
|
||||
DeleteByID(pageID uint64) error
|
||||
DeleteByID(namespaceID, pageID uint64) error
|
||||
|
||||
Reorder(selfID uint64, pageIDs []uint64) error
|
||||
Reorder(namespaceID, selfID uint64, pageIDs []uint64) error
|
||||
}
|
||||
)
|
||||
|
||||
@@ -58,12 +57,12 @@ func (svc *page) With(ctx context.Context) PageService {
|
||||
}
|
||||
}
|
||||
|
||||
func (svc *page) FindByID(id uint64) (p *types.Page, err error) {
|
||||
return svc.checkPermissions(svc.pageRepo.FindByID(id))
|
||||
func (svc *page) FindByID(namespaceID, pageID uint64) (p *types.Page, err error) {
|
||||
return svc.checkPermissions(svc.pageRepo.FindByID(namespaceID, pageID))
|
||||
}
|
||||
|
||||
func (svc *page) FindByModuleID(moduleID uint64) (p *types.Page, err error) {
|
||||
return svc.checkPermissions(svc.pageRepo.FindByModuleID(moduleID))
|
||||
func (svc *page) FindByModuleID(namespaceID, moduleID uint64) (p *types.Page, err error) {
|
||||
return svc.checkPermissions(svc.pageRepo.FindByModuleID(namespaceID, moduleID))
|
||||
}
|
||||
|
||||
func (svc *page) checkPermissions(p *types.Page, err error) (*types.Page, error) {
|
||||
@@ -76,19 +75,27 @@ func (svc *page) checkPermissions(p *types.Page, err error) (*types.Page, error)
|
||||
return p, err
|
||||
}
|
||||
|
||||
func (svc *page) FindBySelfID(selfID uint64) (pp types.PageSet, err error) {
|
||||
return svc.filterPageSet(svc.pageRepo.FindBySelfID(selfID))
|
||||
func (svc *page) FindBySelfID(namespaceID, parentID uint64) (pp types.PageSet, f types.PageFilter, err error) {
|
||||
return svc.filterPageSetByPermission(svc.pageRepo.Find(types.PageFilter{
|
||||
NamespaceID: namespaceID,
|
||||
ParentID: parentID,
|
||||
}))
|
||||
}
|
||||
|
||||
func (svc *page) Find() (pages types.PageSet, err error) {
|
||||
return svc.filterPageSet(svc.pageRepo.Find())
|
||||
func (svc *page) Find(filter types.PageFilter) (set types.PageSet, f types.PageFilter, err error) {
|
||||
return svc.filterPageSetByPermission(svc.pageRepo.Find(filter))
|
||||
}
|
||||
|
||||
func (svc *page) Tree() (pages types.PageSet, err error) {
|
||||
var tree types.PageSet
|
||||
func (svc *page) Tree(namespaceID uint64) (pages types.PageSet, err error) {
|
||||
var (
|
||||
tree types.PageSet
|
||||
filter = types.PageFilter{
|
||||
NamespaceID: namespaceID,
|
||||
}
|
||||
)
|
||||
|
||||
return tree, svc.db.Transaction(func() (err error) {
|
||||
if pages, err = svc.filterPageSet(svc.pageRepo.Find()); err != nil {
|
||||
if pages, _, err = svc.filterPageSetByPermission(svc.pageRepo.Find(filter)); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
@@ -116,22 +123,21 @@ func (svc *page) Tree() (pages types.PageSet, err error) {
|
||||
})
|
||||
}
|
||||
|
||||
func (svc *page) FindRecordPages() (pages types.PageSet, err error) {
|
||||
return svc.pageRepo.FindRecordPages()
|
||||
}
|
||||
|
||||
func (svc *page) filterPageSet(pp types.PageSet, err error) (types.PageSet, error) {
|
||||
func (svc *page) filterPageSetByPermission(pp types.PageSet, f types.PageFilter, err error) (types.PageSet, types.PageFilter, error) {
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return nil, f, err
|
||||
}
|
||||
|
||||
return pp.Filter(func(m *types.Page) (bool, error) {
|
||||
// @todo Filter-by-permission can/will mess up filter's count & paging...
|
||||
pp, err = pp.Filter(func(m *types.Page) (bool, error) {
|
||||
return svc.prmSvc.CanReadPage(m), nil
|
||||
})
|
||||
|
||||
return pp, f, err
|
||||
}
|
||||
|
||||
func (svc *page) Reorder(selfID uint64, pageIDs []uint64) error {
|
||||
return svc.pageRepo.Reorder(selfID, pageIDs)
|
||||
func (svc *page) Reorder(namespaceID, selfID uint64, pageIDs []uint64) error {
|
||||
return svc.pageRepo.Reorder(namespaceID, selfID, pageIDs)
|
||||
}
|
||||
|
||||
func (svc *page) Create(page *types.Page) (p *types.Page, err error) {
|
||||
@@ -141,7 +147,7 @@ func (svc *page) Create(page *types.Page) (p *types.Page, err error) {
|
||||
}
|
||||
|
||||
if page.ModuleID > 0 {
|
||||
if p, err = svc.pageRepo.FindByModuleID(page.ModuleID); err != nil {
|
||||
if p, err = svc.pageRepo.FindByModuleID(page.NamespaceID, page.ModuleID); err != nil {
|
||||
return err
|
||||
} else if p.ID > 0 {
|
||||
return errors.New("Page for module already exists")
|
||||
@@ -162,7 +168,7 @@ func (svc *page) Update(page *types.Page) (p *types.Page, err error) {
|
||||
validate := func() error {
|
||||
if page.ID == 0 {
|
||||
return errors.New("Error when saving page, invalid ID")
|
||||
} else if p, err = svc.pageRepo.FindByID(page.ID); err != nil {
|
||||
} else if p, err = svc.pageRepo.FindByID(page.NamespaceID, page.ID); err != nil {
|
||||
return errors.Wrap(err, "Error while loading page for update")
|
||||
} else {
|
||||
if !svc.prmSvc.CanUpdatePage(p) {
|
||||
@@ -171,7 +177,7 @@ func (svc *page) Update(page *types.Page) (p *types.Page, err error) {
|
||||
}
|
||||
|
||||
if page.ModuleID > 0 {
|
||||
if p, err = svc.pageRepo.FindByModuleID(page.ModuleID); err != nil {
|
||||
if p, err = svc.pageRepo.FindByModuleID(page.NamespaceID, page.ModuleID); err != nil {
|
||||
return err
|
||||
} else if p.ID > 0 && page.ID != p.ID {
|
||||
return errors.New("Page for module already exists")
|
||||
@@ -188,12 +194,12 @@ func (svc *page) Update(page *types.Page) (p *types.Page, err error) {
|
||||
})
|
||||
}
|
||||
|
||||
func (svc *page) DeleteByID(ID uint64) error {
|
||||
if p, err := svc.pageRepo.FindByID(ID); err != nil {
|
||||
func (svc *page) DeleteByID(namespaceID, pageID uint64) error {
|
||||
if p, err := svc.pageRepo.FindByID(namespaceID, pageID); err != nil {
|
||||
return errors.Wrap(err, "could not delete page")
|
||||
} else if !svc.prmSvc.CanDeletePage(p) {
|
||||
return errors.New("not allowed to delete this page")
|
||||
}
|
||||
|
||||
return svc.pageRepo.DeleteByID(ID)
|
||||
return svc.pageRepo.DeleteByID(namespaceID, pageID)
|
||||
}
|
||||
|
||||
@@ -106,14 +106,6 @@ func TestPage(t *testing.T) {
|
||||
prevPageCount = len(ms)
|
||||
}
|
||||
|
||||
// fetch all record pages
|
||||
{
|
||||
ms, err := repository.FindRecordPages()
|
||||
test.Assert(t, err == nil, "Error when retrieving pages: %+v", err)
|
||||
test.Assert(t, len(ms) >= 1, "Expected at least one page, got %d", len(ms))
|
||||
prevPageCount = len(ms)
|
||||
}
|
||||
|
||||
// fetch all pages
|
||||
{
|
||||
ms, err := repository.FindBySelfID(m.ID)
|
||||
|
||||
@@ -53,14 +53,14 @@ func (ctrl Chart) List(ctx context.Context, r *request.ChartList) (interface{},
|
||||
|
||||
func (ctrl Chart) Create(ctx context.Context, r *request.ChartCreate) (interface{}, error) {
|
||||
var err error
|
||||
ns := &types.Chart{
|
||||
mod := &types.Chart{
|
||||
NamespaceID: r.NamespaceID,
|
||||
Name: r.Name,
|
||||
Config: r.Config,
|
||||
}
|
||||
|
||||
ns, err = ctrl.chart.With(ctx).Create(ns)
|
||||
return ctrl.makePayload(ctx, ns, err)
|
||||
mod, err = ctrl.chart.With(ctx).Create(mod)
|
||||
return ctrl.makePayload(ctx, mod, err)
|
||||
}
|
||||
|
||||
func (ctrl Chart) Read(ctx context.Context, r *request.ChartRead) (interface{}, error) {
|
||||
@@ -69,18 +69,18 @@ func (ctrl Chart) Read(ctx context.Context, r *request.ChartRead) (interface{},
|
||||
|
||||
func (ctrl Chart) Update(ctx context.Context, r *request.ChartUpdate) (interface{}, error) {
|
||||
var (
|
||||
ns = &types.Chart{}
|
||||
mod = &types.Chart{}
|
||||
err error
|
||||
)
|
||||
|
||||
ns.ID = r.ChartID
|
||||
ns.Name = r.Name
|
||||
ns.Config = r.Config
|
||||
ns.NamespaceID = r.NamespaceID
|
||||
ns.UpdatedAt = r.UpdatedAt
|
||||
mod.ID = r.ChartID
|
||||
mod.Name = r.Name
|
||||
mod.Config = r.Config
|
||||
mod.NamespaceID = r.NamespaceID
|
||||
mod.UpdatedAt = r.UpdatedAt
|
||||
|
||||
ns, err = ctrl.chart.With(ctx).Update(ns)
|
||||
return ctrl.makePayload(ctx, ns, err)
|
||||
mod, err = ctrl.chart.With(ctx).Update(mod)
|
||||
return ctrl.makePayload(ctx, mod, err)
|
||||
}
|
||||
|
||||
func (ctrl Chart) Delete(ctx context.Context, r *request.ChartDelete) (interface{}, error) {
|
||||
@@ -92,18 +92,18 @@ func (ctrl Chart) Delete(ctx context.Context, r *request.ChartDelete) (interface
|
||||
return resputil.OK(), ctrl.chart.With(ctx).DeleteByID(r.NamespaceID, r.ChartID)
|
||||
}
|
||||
|
||||
func (ctrl Chart) makePayload(ctx context.Context, t *types.Chart, err error) (*chartPayload, error) {
|
||||
if err != nil || t == nil {
|
||||
func (ctrl Chart) makePayload(ctx context.Context, c *types.Chart, err error) (*chartPayload, error) {
|
||||
if err != nil || c == nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
perm := ctrl.permissions.With(ctx)
|
||||
|
||||
return &chartPayload{
|
||||
Chart: t,
|
||||
Chart: c,
|
||||
|
||||
CanUpdateChart: perm.CanUpdateChart(t),
|
||||
CanDeleteChart: perm.CanDeleteChart(t),
|
||||
CanUpdateChart: perm.CanUpdateChart(c),
|
||||
CanDeleteChart: perm.CanDeleteChart(c),
|
||||
}, nil
|
||||
}
|
||||
|
||||
@@ -112,11 +112,11 @@ func (ctrl Chart) makeFilterPayload(ctx context.Context, nn types.ChartSet, f ty
|
||||
return nil, err
|
||||
}
|
||||
|
||||
nsp := &chartSetPayload{Filter: f, Set: make([]*chartPayload, len(nn))}
|
||||
modp := &chartSetPayload{Filter: f, Set: make([]*chartPayload, len(nn))}
|
||||
|
||||
for i := range nn {
|
||||
nsp.Set[i], _ = ctrl.makePayload(ctx, nn[i], nil)
|
||||
modp.Set[i], _ = ctrl.makePayload(ctx, nn[i], nil)
|
||||
}
|
||||
|
||||
return nsp, nil
|
||||
return modp, nil
|
||||
}
|
||||
|
||||
@@ -12,70 +12,100 @@ import (
|
||||
)
|
||||
|
||||
type (
|
||||
pagePayload struct {
|
||||
*types.Page
|
||||
|
||||
CanUpdatePage bool `json:"canUpdatePage"`
|
||||
CanDeletePage bool `json:"canDeletePage"`
|
||||
}
|
||||
|
||||
pageSetPayload struct {
|
||||
Filter types.PageFilter `json:"filter"`
|
||||
Set []*pagePayload `json:"set"`
|
||||
}
|
||||
|
||||
Page struct {
|
||||
page service.PageService
|
||||
attachment service.AttachmentService
|
||||
page service.PageService
|
||||
attachment service.AttachmentService
|
||||
permissions service.PermissionsService
|
||||
}
|
||||
)
|
||||
|
||||
func (Page) New() *Page {
|
||||
return &Page{
|
||||
page: service.DefaultPage,
|
||||
attachment: service.DefaultAttachment,
|
||||
page: service.DefaultPage,
|
||||
attachment: service.DefaultAttachment,
|
||||
permissions: service.DefaultPermissions,
|
||||
}
|
||||
}
|
||||
|
||||
func (ctrl *Page) List(ctx context.Context, r *request.PageList) (interface{}, error) {
|
||||
if r.SelfID > 0 {
|
||||
return ctrl.page.With(ctx).FindBySelfID(r.SelfID)
|
||||
} else {
|
||||
return ctrl.page.With(ctx).Find()
|
||||
f := types.PageFilter{
|
||||
NamespaceID: r.NamespaceID,
|
||||
ParentID: r.SelfID,
|
||||
|
||||
Query: r.Query,
|
||||
PerPage: r.PerPage,
|
||||
Page: r.Page,
|
||||
}
|
||||
|
||||
set, filter, err := ctrl.page.With(ctx).Find(f)
|
||||
return ctrl.makeFilterPayload(ctx, set, filter, err)
|
||||
}
|
||||
|
||||
func (ctrl *Page) Tree(ctx context.Context, r *request.PageTree) (interface{}, error) {
|
||||
return ctrl.page.With(ctx).Tree()
|
||||
return ctrl.page.With(ctx).Tree(r.NamespaceID)
|
||||
}
|
||||
|
||||
func (ctrl *Page) Create(ctx context.Context, r *request.PageCreate) (interface{}, error) {
|
||||
p := &types.Page{
|
||||
SelfID: r.SelfID,
|
||||
ModuleID: r.ModuleID,
|
||||
Title: r.Title,
|
||||
Description: r.Description,
|
||||
Blocks: r.Blocks,
|
||||
Visible: r.Visible,
|
||||
}
|
||||
return ctrl.page.With(ctx).Create(p)
|
||||
var (
|
||||
err error
|
||||
mod = &types.Page{
|
||||
NamespaceID: r.NamespaceID,
|
||||
SelfID: r.SelfID,
|
||||
ModuleID: r.ModuleID,
|
||||
Title: r.Title,
|
||||
Description: r.Description,
|
||||
Blocks: r.Blocks,
|
||||
Visible: r.Visible,
|
||||
}
|
||||
)
|
||||
|
||||
mod, err = ctrl.page.With(ctx).Create(mod)
|
||||
return ctrl.makePayload(ctx, mod, err)
|
||||
}
|
||||
|
||||
func (ctrl *Page) Read(ctx context.Context, r *request.PageRead) (interface{}, error) {
|
||||
return ctrl.page.With(ctx).FindByID(r.PageID)
|
||||
return ctrl.page.With(ctx).FindByID(r.NamespaceID, r.PageID)
|
||||
}
|
||||
|
||||
func (ctrl *Page) Reorder(ctx context.Context, r *request.PageReorder) (interface{}, error) {
|
||||
return resputil.OK(), ctrl.page.With(ctx).Reorder(r.SelfID, payload.ParseUInt64s(r.PageIDs))
|
||||
return resputil.OK(), ctrl.page.With(ctx).Reorder(r.NamespaceID, r.SelfID, payload.ParseUInt64s(r.PageIDs))
|
||||
}
|
||||
|
||||
func (ctrl *Page) Update(ctx context.Context, r *request.PageUpdate) (interface{}, error) {
|
||||
p := &types.Page{
|
||||
ID: r.PageID,
|
||||
SelfID: r.SelfID,
|
||||
ModuleID: r.ModuleID,
|
||||
Title: r.Title,
|
||||
Description: r.Description,
|
||||
Blocks: r.Blocks,
|
||||
Visible: r.Visible,
|
||||
}
|
||||
return ctrl.page.With(ctx).Update(p)
|
||||
var (
|
||||
err error
|
||||
mod = &types.Page{
|
||||
ID: r.PageID,
|
||||
SelfID: r.SelfID,
|
||||
ModuleID: r.ModuleID,
|
||||
Title: r.Title,
|
||||
Description: r.Description,
|
||||
Blocks: r.Blocks,
|
||||
Visible: r.Visible,
|
||||
}
|
||||
)
|
||||
|
||||
mod, err = ctrl.page.With(ctx).Update(mod)
|
||||
return ctrl.makePayload(ctx, mod, err)
|
||||
}
|
||||
|
||||
func (ctrl *Page) Delete(ctx context.Context, r *request.PageDelete) (interface{}, error) {
|
||||
return resputil.OK(), ctrl.page.With(ctx).DeleteByID(r.PageID)
|
||||
return resputil.OK(), ctrl.page.With(ctx).DeleteByID(r.NamespaceID, r.PageID)
|
||||
}
|
||||
|
||||
func (ctrl *Page) Upload(ctx context.Context, r *request.PageUpload) (interface{}, error) {
|
||||
// @todo [SECURITY] check if attachments can be added to this page
|
||||
file, err := r.Upload.Open()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -93,3 +123,32 @@ func (ctrl *Page) Upload(ctx context.Context, r *request.PageUpload) (interface{
|
||||
|
||||
return makeAttachmentPayload(ctx, a, err)
|
||||
}
|
||||
|
||||
func (ctrl Page) makePayload(ctx context.Context, c *types.Page, err error) (*pagePayload, error) {
|
||||
if err != nil || c == nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
perm := ctrl.permissions.With(ctx)
|
||||
|
||||
return &pagePayload{
|
||||
Page: c,
|
||||
|
||||
CanUpdatePage: perm.CanUpdatePage(c),
|
||||
CanDeletePage: perm.CanDeletePage(c),
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (ctrl Page) makeFilterPayload(ctx context.Context, nn types.PageSet, f types.PageFilter, err error) (*pageSetPayload, error) {
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
modp := &pageSetPayload{Filter: f, Set: make([]*pagePayload, len(nn))}
|
||||
|
||||
for i := range nn {
|
||||
modp.Set[i], _ = ctrl.makePayload(ctx, nn[i], nil)
|
||||
}
|
||||
|
||||
return modp, nil
|
||||
}
|
||||
|
||||
@@ -54,7 +54,6 @@ func (ctrl *Record) Delete(ctx context.Context, r *request.RecordDelete) (interf
|
||||
}
|
||||
|
||||
func (ctrl *Record) Upload(ctx context.Context, r *request.RecordUpload) (interface{}, error) {
|
||||
// @todo [SECURITY] check if attachments can be added to this page
|
||||
file, err := r.Upload.Open()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
||||
@@ -35,6 +35,9 @@ var _ = multipart.FileHeader{}
|
||||
// Page list request parameters
|
||||
type PageList struct {
|
||||
SelfID uint64 `json:",string"`
|
||||
Query string
|
||||
Page uint
|
||||
PerPage uint
|
||||
NamespaceID uint64 `json:",string"`
|
||||
}
|
||||
|
||||
@@ -73,6 +76,18 @@ func (pReq *PageList) Fill(r *http.Request) (err error) {
|
||||
|
||||
pReq.SelfID = parseUInt64(val)
|
||||
}
|
||||
if val, ok := get["query"]; ok {
|
||||
|
||||
pReq.Query = val
|
||||
}
|
||||
if val, ok := get["page"]; ok {
|
||||
|
||||
pReq.Page = parseUint(val)
|
||||
}
|
||||
if val, ok := get["perPage"]; ok {
|
||||
|
||||
pReq.PerPage = parseUint(val)
|
||||
}
|
||||
pReq.NamespaceID = parseUInt64(chi.URLParam(r, "namespaceID"))
|
||||
|
||||
return err
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
package types
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"github.com/jmoiron/sqlx/types"
|
||||
|
||||
"github.com/crusttech/crust/internal/rules"
|
||||
@@ -14,8 +16,7 @@ type (
|
||||
|
||||
NamespaceID uint64 `json:"namespaceID,string" db:"rel_namespace"`
|
||||
|
||||
ModuleID uint64 `json:"moduleID,string" db:"module_id"`
|
||||
Module *Module `json:"module,omitempty" db:"-"`
|
||||
ModuleID uint64 `json:"moduleID,string" db:"rel_module"`
|
||||
|
||||
Title string `json:"title" db:"title"`
|
||||
Description string `json:"description" db:"description"`
|
||||
@@ -26,6 +27,10 @@ type (
|
||||
|
||||
Visible bool `json:"visible" db:"visible"`
|
||||
Weight int `json:"-" db:"weight"`
|
||||
|
||||
CreatedAt time.Time `db:"created_at" json:"createdAt,omitempty"`
|
||||
UpdatedAt *time.Time `db:"updated_at" json:"updatedAt,omitempty"`
|
||||
DeletedAt *time.Time `db:"deleted_at" json:"deletedAt,omitempty"`
|
||||
}
|
||||
|
||||
// Block - value of Page.Blocks ([]Block)
|
||||
@@ -39,6 +44,15 @@ type (
|
||||
Width int `json:"width"`
|
||||
Height int `json:"height"`
|
||||
}
|
||||
|
||||
PageFilter struct {
|
||||
NamespaceID uint64 `json:"namespaceID,string"`
|
||||
ParentID uint64 `json:"paentID,string"`
|
||||
Query string `json:"query"`
|
||||
Page uint `json:"page"`
|
||||
PerPage uint `json:"perPage"`
|
||||
Count uint `json:"count"`
|
||||
}
|
||||
)
|
||||
|
||||
// Resource returns a system resource ID for this type
|
||||
|
||||
@@ -461,6 +461,9 @@ Compose pages
|
||||
| Parameter | Type | Method | Description | Default | Required? |
|
||||
| --------- | ---- | ------ | ----------- | ------- | --------- |
|
||||
| selfID | uint64 | GET | Parent page ID | N/A | NO |
|
||||
| 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 page
|
||||
|
||||
Reference in New Issue
Block a user