Add /page/tree, generated set types
This commit is contained in:
@@ -265,6 +265,19 @@ CRM module pages
|
||||
| --------- | ---- | ------ | ----------- | ------- | --------- |
|
||||
| pageID | uint64 | PATH | Page ID | N/A | YES |
|
||||
|
||||
## Get page all pages, hierarchically
|
||||
|
||||
#### Method
|
||||
|
||||
| URI | Protocol | Method | Authentication |
|
||||
| --- | -------- | ------ | -------------- |
|
||||
| `/page/tree` | HTTP/S | GET | |
|
||||
|
||||
#### Request parameters
|
||||
|
||||
| Parameter | Type | Method | Description | Default | Required? |
|
||||
| --------- | ---- | ------ | ----------- | ------- | --------- |
|
||||
|
||||
## Edit page
|
||||
|
||||
#### Method
|
||||
|
||||
@@ -141,6 +141,13 @@
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "tree",
|
||||
"path": "/tree",
|
||||
"method": "GET",
|
||||
"title": "Get page all pages, hierarchically",
|
||||
"parameters": {}
|
||||
},
|
||||
{
|
||||
"name": "edit",
|
||||
"method": "POST",
|
||||
|
||||
@@ -87,6 +87,13 @@
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"Name": "tree",
|
||||
"Method": "GET",
|
||||
"Title": "Get page all pages, hierarchically",
|
||||
"Path": "/tree",
|
||||
"Parameters": {}
|
||||
},
|
||||
{
|
||||
"Name": "edit",
|
||||
"Method": "POST",
|
||||
|
||||
@@ -19,7 +19,7 @@ type (
|
||||
Chart(r *request.ModuleChart) (interface{}, error)
|
||||
|
||||
FindByID(id uint64) (*types.Module, error)
|
||||
Find() ([]*types.Module, error)
|
||||
Find() (types.ModuleSet, error)
|
||||
Create(mod *types.Module) (*types.Module, error)
|
||||
Update(mod *types.Module) (*types.Module, error)
|
||||
DeleteByID(id uint64) error
|
||||
@@ -56,8 +56,8 @@ func (r *module) FindByID(id uint64) (*types.Module, error) {
|
||||
return mod, nil
|
||||
}
|
||||
|
||||
func (r *module) Find() ([]*types.Module, error) {
|
||||
mod := make([]*types.Module, 0)
|
||||
func (r *module) Find() (types.ModuleSet, error) {
|
||||
mod := types.ModuleSet{}
|
||||
return mod, r.db().Select(&mod, "SELECT * FROM crm_module ORDER BY id ASC")
|
||||
}
|
||||
|
||||
|
||||
+11
-5
@@ -13,9 +13,10 @@ type (
|
||||
PageRepository interface {
|
||||
With(ctx context.Context, db *factory.DB) PageRepository
|
||||
|
||||
Find(selfID uint64) ([]*types.Page, error)
|
||||
FindByID(id uint64) (*types.Page, error)
|
||||
FindByModuleID(id uint64) (*types.Page, error)
|
||||
FindBySelfID(selfID uint64) (types.PageSet, error)
|
||||
FindAll() (types.PageSet, error)
|
||||
|
||||
Create(mod *types.Page) (*types.Page, error)
|
||||
Update(mod *types.Page) (*types.Page, error)
|
||||
@@ -58,9 +59,9 @@ func (r *page) FindByModuleID(id uint64) (*types.Page, error) {
|
||||
return page, nil
|
||||
}
|
||||
|
||||
func (r *page) Find(selfID uint64) ([]*types.Page, error) {
|
||||
pages := make([]*types.Page, 0)
|
||||
if err := r.db().Select(&pages, "SELECT * FROM crm_page where self_id=? ORDER BY weight ASC", selfID); err != nil {
|
||||
func (r *page) FindBySelfID(selfID uint64) (types.PageSet, error) {
|
||||
pages := types.PageSet{}
|
||||
if err := r.db().Select(&pages, "SELECT * FROM crm_page WHERE self_id = ? ORDER BY weight ASC", selfID); err != nil {
|
||||
return pages, err
|
||||
}
|
||||
for _, page := range pages {
|
||||
@@ -71,9 +72,14 @@ func (r *page) Find(selfID uint64) ([]*types.Page, error) {
|
||||
return pages, nil
|
||||
}
|
||||
|
||||
func (r *page) FindAll() (types.PageSet, error) {
|
||||
pages := types.PageSet{}
|
||||
return pages, r.db().Select(&pages, "SELECT * FROM crm_page ORDER BY self_id, weight ASC")
|
||||
}
|
||||
|
||||
func (r *page) Reorder(selfID uint64, pageIDs []uint64) error {
|
||||
pageMap := map[uint64]bool{}
|
||||
if pages, err := r.Find(selfID); err != nil {
|
||||
if pages, err := r.FindBySelfID(selfID); err != nil {
|
||||
return nil
|
||||
} else {
|
||||
for _, page := range pages {
|
||||
|
||||
@@ -30,6 +30,7 @@ type PageAPI interface {
|
||||
List(context.Context, *request.PageList) (interface{}, error)
|
||||
Create(context.Context, *request.PageCreate) (interface{}, error)
|
||||
Read(context.Context, *request.PageRead) (interface{}, error)
|
||||
Tree(context.Context, *request.PageTree) (interface{}, error)
|
||||
Edit(context.Context, *request.PageEdit) (interface{}, error)
|
||||
Reorder(context.Context, *request.PageReorder) (interface{}, error)
|
||||
Delete(context.Context, *request.PageDelete) (interface{}, error)
|
||||
@@ -40,6 +41,7 @@ type Page struct {
|
||||
List func(http.ResponseWriter, *http.Request)
|
||||
Create func(http.ResponseWriter, *http.Request)
|
||||
Read func(http.ResponseWriter, *http.Request)
|
||||
Tree func(http.ResponseWriter, *http.Request)
|
||||
Edit func(http.ResponseWriter, *http.Request)
|
||||
Reorder func(http.ResponseWriter, *http.Request)
|
||||
Delete func(http.ResponseWriter, *http.Request)
|
||||
@@ -68,6 +70,13 @@ func NewPage(ph PageAPI) *Page {
|
||||
return ph.Read(r.Context(), params)
|
||||
})
|
||||
},
|
||||
Tree: func(w http.ResponseWriter, r *http.Request) {
|
||||
defer r.Body.Close()
|
||||
params := request.NewPageTree()
|
||||
resputil.JSON(w, params.Fill(r), func() (interface{}, error) {
|
||||
return ph.Tree(r.Context(), params)
|
||||
})
|
||||
},
|
||||
Edit: func(w http.ResponseWriter, r *http.Request) {
|
||||
defer r.Body.Close()
|
||||
params := request.NewPageEdit()
|
||||
@@ -99,6 +108,7 @@ func (ph *Page) MountRoutes(r chi.Router, middlewares ...func(http.Handler) http
|
||||
r.Get("/", ph.List)
|
||||
r.Post("/", ph.Create)
|
||||
r.Get("/{pageID}", ph.Read)
|
||||
r.Get("/tree", ph.Tree)
|
||||
r.Post("/{pageID}", ph.Edit)
|
||||
r.Post("/{selfID}/reorder", ph.Reorder)
|
||||
r.Delete("/{pageID}", ph.Delete)
|
||||
|
||||
@@ -25,6 +25,10 @@ func (ctrl *Page) List(ctx context.Context, r *request.PageList) (interface{}, e
|
||||
return ctrl.page.With(ctx).Find(r.SelfID)
|
||||
}
|
||||
|
||||
func (ctrl *Page) Tree(ctx context.Context, r *request.PageTree) (interface{}, error) {
|
||||
return ctrl.page.With(ctx).Tree()
|
||||
}
|
||||
|
||||
func (ctrl *Page) Create(ctx context.Context, r *request.PageCreate) (interface{}, error) {
|
||||
p := &types.Page{
|
||||
SelfID: r.SelfID,
|
||||
|
||||
@@ -192,6 +192,46 @@ func (p *PageRead) Fill(r *http.Request) (err error) {
|
||||
|
||||
var _ RequestFiller = NewPageRead()
|
||||
|
||||
// Page tree request parameters
|
||||
type PageTree struct {
|
||||
}
|
||||
|
||||
func NewPageTree() *PageTree {
|
||||
return &PageTree{}
|
||||
}
|
||||
|
||||
func (p *PageTree) Fill(r *http.Request) (err error) {
|
||||
if strings.ToLower(r.Header.Get("content-type")) == "application/json" {
|
||||
err = json.NewDecoder(r.Body).Decode(p)
|
||||
|
||||
switch {
|
||||
case err == io.EOF:
|
||||
err = nil
|
||||
case err != nil:
|
||||
return errors.Wrap(err, "error parsing http request body")
|
||||
}
|
||||
}
|
||||
|
||||
if err = r.ParseForm(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
get := map[string]string{}
|
||||
post := map[string]string{}
|
||||
urlQuery := r.URL.Query()
|
||||
for name, param := range urlQuery {
|
||||
get[name] = string(param[0])
|
||||
}
|
||||
postVars := r.Form
|
||||
for name, param := range postVars {
|
||||
post[name] = string(param[0])
|
||||
}
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
var _ RequestFiller = NewPageTree()
|
||||
|
||||
// Page edit request parameters
|
||||
type PageEdit struct {
|
||||
PageID uint64 `json:",string"`
|
||||
|
||||
+62
-3
@@ -14,13 +14,15 @@ type (
|
||||
db *factory.DB
|
||||
ctx context.Context
|
||||
repository repository.PageRepository
|
||||
moduleRepo repository.ModuleRepository
|
||||
}
|
||||
|
||||
PageService interface {
|
||||
With(ctx context.Context) PageService
|
||||
|
||||
FindByID(pageID uint64) (*types.Page, error)
|
||||
Find(selfID uint64) ([]*types.Page, error)
|
||||
Find(selfID uint64) (pages types.PageSet, err error)
|
||||
Tree() (pages types.PageSet, err error)
|
||||
|
||||
Create(page *types.Page) (*types.Page, error)
|
||||
Update(page *types.Page) (*types.Page, error)
|
||||
@@ -40,6 +42,7 @@ func (s *page) With(ctx context.Context) PageService {
|
||||
db: db,
|
||||
ctx: ctx,
|
||||
repository: repository.Page(ctx, db),
|
||||
moduleRepo: repository.Module(ctx, db),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -47,8 +50,50 @@ func (s *page) FindByID(id uint64) (*types.Page, error) {
|
||||
return s.repository.FindByID(id)
|
||||
}
|
||||
|
||||
func (s *page) Find(selfID uint64) ([]*types.Page, error) {
|
||||
return s.repository.Find(selfID)
|
||||
func (s *page) Find(selfID uint64) (pages types.PageSet, err error) {
|
||||
return pages, s.db.Transaction(func() (err error) {
|
||||
if pages, err = s.repository.FindBySelfID(selfID); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
if err = s.preload(pages); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
return nil
|
||||
})
|
||||
}
|
||||
|
||||
func (s *page) Tree() (pages types.PageSet, err error) {
|
||||
var tree types.PageSet
|
||||
|
||||
return tree, s.db.Transaction(func() (err error) {
|
||||
if pages, err = s.repository.FindAll(); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
if err = s.preload(pages); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
_ = pages.Walk(func(p *types.Page) error {
|
||||
if p.SelfID == 0 {
|
||||
tree = append(tree, p)
|
||||
} else if c := pages.FindByID(p.SelfID); c != nil {
|
||||
if c.Children == nil {
|
||||
c.Children = types.PageSet{}
|
||||
}
|
||||
|
||||
c.Children = append(c.Children, p)
|
||||
} else {
|
||||
// Ignore orphans :(
|
||||
}
|
||||
|
||||
return nil
|
||||
})
|
||||
|
||||
return nil
|
||||
})
|
||||
}
|
||||
|
||||
func (s *page) Reorder(selfID uint64, pageIDs []uint64) error {
|
||||
@@ -66,3 +111,17 @@ func (s *page) Update(mod *types.Page) (*types.Page, error) {
|
||||
func (s *page) DeleteByID(id uint64) error {
|
||||
return s.repository.DeleteByID(id)
|
||||
}
|
||||
|
||||
// Preloads modules for all pages
|
||||
func (s *page) preload(pages types.PageSet) error {
|
||||
if modules, err := s.moduleRepo.Find(); err != nil {
|
||||
return err
|
||||
} else {
|
||||
_ = pages.Walk(func(page *types.Page) error {
|
||||
page.Module = modules.FindByID(page.ModuleID)
|
||||
return nil
|
||||
})
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -0,0 +1,105 @@
|
||||
package types
|
||||
|
||||
type (
|
||||
|
||||
// ModuleSet slice of Module
|
||||
ModuleSet []*Module
|
||||
// PageSet slice of Page
|
||||
PageSet []*Page
|
||||
)
|
||||
|
||||
// Walk iterates through every slice item and calls w(Module) err
|
||||
func (set ModuleSet) Walk(w func(*Module) error) (err error) {
|
||||
for i := range set {
|
||||
if err = w(set[i]); err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// Filter iterates through every slice item, calls f(Module) (bool, err) and return filtered slice
|
||||
func (set ModuleSet) Filter(f func(*Module) (bool, error)) (out ModuleSet, err error) {
|
||||
var ok bool
|
||||
out = ModuleSet{}
|
||||
for i := range set {
|
||||
if ok, err = f(set[i]); err != nil {
|
||||
return
|
||||
} else if ok {
|
||||
out = append(out, set[i])
|
||||
}
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// Finds slice item by its ID property
|
||||
func (set ModuleSet) FindByID(ID uint64) *Module {
|
||||
for i := range set {
|
||||
if set[i].ID == ID {
|
||||
return set[i]
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Returns a slice of uint64s from all items in the set
|
||||
func (set ModuleSet) IDs() (IDs []uint64) {
|
||||
IDs = make([]uint64, len(set))
|
||||
|
||||
for i := range set {
|
||||
IDs[i] = set[i].ID
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// Walk iterates through every slice item and calls w(Page) err
|
||||
func (set PageSet) Walk(w func(*Page) error) (err error) {
|
||||
for i := range set {
|
||||
if err = w(set[i]); err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// Filter iterates through every slice item, calls f(Page) (bool, err) and return filtered slice
|
||||
func (set PageSet) Filter(f func(*Page) (bool, error)) (out PageSet, err error) {
|
||||
var ok bool
|
||||
out = PageSet{}
|
||||
for i := range set {
|
||||
if ok, err = f(set[i]); err != nil {
|
||||
return
|
||||
} else if ok {
|
||||
out = append(out, set[i])
|
||||
}
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// Finds slice item by its ID property
|
||||
func (set PageSet) FindByID(ID uint64) *Page {
|
||||
for i := range set {
|
||||
if set[i].ID == ID {
|
||||
return set[i]
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Returns a slice of uint64s from all items in the set
|
||||
func (set PageSet) IDs() (IDs []uint64) {
|
||||
IDs = make([]uint64, len(set))
|
||||
|
||||
for i := range set {
|
||||
IDs[i] = set[i].ID
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
@@ -1,5 +1,7 @@
|
||||
package types
|
||||
|
||||
//go:generate go run ../../codegen/v2/type-set.go Module Page type-sets.gen.go
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
@@ -80,6 +82,8 @@ type (
|
||||
|
||||
Blocks types.JSONText `json:"blocks" db:"blocks"`
|
||||
|
||||
Children PageSet `json:"children,omitempty" db:"-"`
|
||||
|
||||
Visible bool `json:"visible" db:"visible"`
|
||||
Weight int `json:"-" db:"weight"`
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user