3
0

add(crm): import implementation for pages

This commit is contained in:
Tit Petric 2018-10-15 14:46:35 +00:00
parent 909bd6d82e
commit ad6cf16e4b
15 changed files with 1035 additions and 43 deletions

View File

@ -32,6 +32,93 @@ CRM input field definitions
# Pages
CRM module pages
## List available pages
#### Method
| URI | Protocol | Method | Authentication |
| --- | -------- | ------ | -------------- |
| `/page/` | HTTP/S | GET | |
#### Request parameters
| Parameter | Type | Method | Description | Default | Required? |
| --------- | ---- | ------ | ----------- | ------- | --------- |
## Create page
#### Method
| URI | Protocol | Method | Authentication |
| --- | -------- | ------ | -------------- |
| `/page/` | HTTP/S | POST | |
#### Request parameters
| Parameter | Type | Method | Description | Default | Required? |
| --------- | ---- | ------ | ----------- | ------- | --------- |
| selfID | uint64 | POST | Parent Page ID | N/A | NO |
| moduleID | uint64 | POST | Module ID (optional) | N/A | NO |
| title | string | POST | Title | N/A | YES |
| description | string | POST | Description | N/A | NO |
| visible | bool | POST | Visible in navigation | N/A | NO |
| blocks | types.JSONText | POST | Blocks JSON | N/A | YES |
## Get page details
#### Method
| URI | Protocol | Method | Authentication |
| --- | -------- | ------ | -------------- |
| `/page/{id}` | HTTP/S | GET | |
#### Request parameters
| Parameter | Type | Method | Description | Default | Required? |
| --------- | ---- | ------ | ----------- | ------- | --------- |
| id | uint64 | PATH | Page ID | N/A | YES |
## Create page
#### Method
| URI | Protocol | Method | Authentication |
| --- | -------- | ------ | -------------- |
| `/page/{id}` | HTTP/S | POST | |
#### Request parameters
| Parameter | Type | Method | Description | Default | Required? |
| --------- | ---- | ------ | ----------- | ------- | --------- |
| id | uint64 | PATH | Page ID | N/A | YES |
| selfID | uint64 | POST | Parent Page ID | N/A | NO |
| moduleID | uint64 | POST | Module ID (optional) | N/A | NO |
| title | string | POST | Title | N/A | YES |
| description | string | POST | Description | N/A | NO |
| visible | bool | POST | Visible in navigation | N/A | NO |
| blocks | types.JSONText | POST | Blocks JSON | N/A | YES |
## Delete page
#### Method
| URI | Protocol | Method | Authentication |
| --- | -------- | ------ | -------------- |
| `/page/{id}` | HTTP/S | Delete | |
#### Request parameters
| Parameter | Type | Method | Description | Default | Required? |
| --------- | ---- | ------ | ----------- | ------- | --------- |
| id | uint64 | PATH | Page ID | N/A | YES |
# Modules
CRM module definitions
@ -121,7 +208,7 @@ CRM module definitions
| Parameter | Type | Method | Description | Default | Required? |
| --------- | ---- | ------ | ----------- | ------- | --------- |
| module | uint64 | PATH | Module ID | N/A | YES |
| moduleID | uint64 | PATH | Module ID | N/A | YES |
## List/read contents from module section
@ -135,7 +222,7 @@ CRM module definitions
| Parameter | Type | Method | Description | Default | Required? |
| --------- | ---- | ------ | ----------- | ------- | --------- |
| module | uint64 | PATH | Module ID | N/A | YES |
| moduleID | uint64 | PATH | Module ID | N/A | YES |
| fields | types.JSONText | POST | Content JSON | N/A | YES |
## Read contents by ID from module section
@ -150,7 +237,7 @@ CRM module definitions
| Parameter | Type | Method | Description | Default | Required? |
| --------- | ---- | ------ | ----------- | ------- | --------- |
| module | uint64 | PATH | Module ID | N/A | YES |
| moduleID | uint64 | PATH | Module ID | N/A | YES |
| id | uint64 | PATH | Content ID | N/A | YES |
## Add/update contents in module section
@ -165,7 +252,7 @@ CRM module definitions
| Parameter | Type | Method | Description | Default | Required? |
| --------- | ---- | ------ | ----------- | ------- | --------- |
| module | uint64 | PATH | Module ID | N/A | YES |
| moduleID | uint64 | PATH | Module ID | N/A | YES |
| id | uint64 | PATH | Content ID | N/A | YES |
| fields | types.JSONText | POST | Content JSON | N/A | YES |
@ -181,5 +268,5 @@ CRM module definitions
| Parameter | Type | Method | Description | Default | Required? |
| --------- | ---- | ------ | ----------- | ------- | --------- |
| module | uint64 | PATH | Module ID | N/A | YES |
| moduleID | uint64 | PATH | Module ID | N/A | YES |
| id | uint64 | PATH | Content ID | N/A | YES |

View File

@ -36,6 +36,80 @@
}
]
},
{
"title": "Pages",
"description": "CRM module pages",
"package": "crm",
"entrypoint": "page",
"path": "/page",
"authentication": [],
"struct": [],
"apis": [
{
"name": "list",
"method": "GET",
"path": "/",
"title": "List available pages"
},
{
"name": "create",
"method": "POST",
"title": "Create page",
"path": "/",
"parameters": {
"post": [
{ "type": "uint64", "name": "selfID", "required": false, "title": "Parent Page ID" },
{ "type": "uint64", "name": "moduleID", "required": false, "title": "Module ID (optional)" },
{ "type": "string", "name": "title", "required": true, "title": "Title" },
{ "type": "string", "name": "description", "required": false, "title": "Description" },
{ "type": "bool", "name": "visible", "required": false, "title": "Visible in navigation" },
{ "type": "types.JSONText", "name": "blocks", "required": true, "title": "Blocks JSON" }
]
}
},
{
"name": "read",
"path": "/{id}",
"method": "GET",
"title": "Get page details",
"parameters": {
"path": [
{ "type": "uint64", "name": "id", "required": true, "title": "Page ID" }
]
}
},
{
"name": "edit",
"method": "POST",
"title": "Create page",
"path": "/{id}",
"parameters": {
"path": [
{ "type": "uint64", "name": "id", "required": true, "title": "Page ID" }
],
"post": [
{ "type": "uint64", "name": "selfID", "required": false, "title": "Parent Page ID" },
{ "type": "uint64", "name": "moduleID", "required": false, "title": "Module ID (optional)" },
{ "type": "string", "name": "title", "required": true, "title": "Title" },
{ "type": "string", "name": "description", "required": false, "title": "Description" },
{ "type": "bool", "name": "visible", "required": false, "title": "Visible in navigation" },
{ "type": "types.JSONText", "name": "blocks", "required": true, "title": "Blocks JSON" }
]
}
},
{
"name": "delete",
"path": "/{id}",
"method": "Delete",
"title": "Delete page",
"parameters": {
"path": [
{ "type": "uint64", "name": "id", "required": true, "title": "Page ID" }
]
}
}
]
},
{
"title": "Modules",
"description": "CRM module definitions",
@ -72,7 +146,7 @@
],
"fields": [
{ "name": "ID", "type": "uint64" },
{ "name": "ModuleID", "type": "uint64" },
{ "name": "moduleID", "type": "uint64" },
{ "name": "Fields", "type": "types.JSONText", "db": "json" }
]
}
@ -145,7 +219,7 @@
"path": "/{module}/content",
"parameters": {
"path": [
{ "type": "uint64", "name": "module", "required": true, "title": "Module ID" }
{ "type": "uint64", "name": "moduleID", "required": true, "title": "Module ID" }
]
}
},
@ -156,7 +230,7 @@
"path": "/{module}/content",
"parameters": {
"path": [
{ "type": "uint64", "name": "module", "required": true, "title": "Module ID" }
{ "type": "uint64", "name": "moduleID", "required": true, "title": "Module ID" }
],
"post": [
{ "type": "types.JSONText", "name": "fields", "required": true, "title": "Content JSON" }
@ -170,7 +244,7 @@
"path": "/{module}/content/{id}",
"parameters": {
"path": [
{ "type": "uint64", "name": "module", "required": true, "title": "Module ID" },
{ "type": "uint64", "name": "moduleID", "required": true, "title": "Module ID" },
{ "type": "uint64", "name": "id", "required": true, "title": "Content ID" }
]
}
@ -182,7 +256,7 @@
"path": "/{module}/content/{id}",
"parameters": {
"path": [
{ "type": "uint64", "name": "module", "required": true, "title": "Module ID" },
{ "type": "uint64", "name": "moduleID", "required": true, "title": "Module ID" },
{ "type": "uint64", "name": "id", "required": true, "title": "Content ID" }
],
"post": [
@ -197,7 +271,7 @@
"path": "/{module}/content/{id}",
"parameters": {
"path": [
{ "type": "uint64", "name": "module", "required": true, "title": "Module ID" },
{ "type": "uint64", "name": "moduleID", "required": true, "title": "Module ID" },
{ "type": "uint64", "name": "id", "required": true, "title": "Content ID" }
]
}

View File

@ -58,7 +58,7 @@
"type": "uint64"
},
{
"name": "ModuleID",
"name": "moduleID",
"type": "uint64"
},
{
@ -186,7 +186,7 @@
"Parameters": {
"path": [
{
"name": "module",
"name": "moduleID",
"required": true,
"title": "Module ID",
"type": "uint64"
@ -202,7 +202,7 @@
"Parameters": {
"path": [
{
"name": "module",
"name": "moduleID",
"required": true,
"title": "Module ID",
"type": "uint64"
@ -226,7 +226,7 @@
"Parameters": {
"path": [
{
"name": "module",
"name": "moduleID",
"required": true,
"title": "Module ID",
"type": "uint64"
@ -248,7 +248,7 @@
"Parameters": {
"path": [
{
"name": "module",
"name": "moduleID",
"required": true,
"title": "Module ID",
"type": "uint64"
@ -278,7 +278,7 @@
"Parameters": {
"path": [
{
"name": "module",
"name": "moduleID",
"required": true,
"title": "Module ID",
"type": "uint64"

152
crm/docs/src/spec/page.json Normal file
View File

@ -0,0 +1,152 @@
{
"Title": "Pages",
"Description": "CRM module pages",
"Package": "crm",
"Interface": "Page",
"Struct": [],
"Parameters": null,
"Protocol": "",
"Authentication": [],
"Path": "/page",
"APIs": [
{
"Name": "list",
"Method": "GET",
"Title": "List available pages",
"Path": "/",
"Parameters": null
},
{
"Name": "create",
"Method": "POST",
"Title": "Create page",
"Path": "/",
"Parameters": {
"post": [
{
"name": "selfID",
"required": false,
"title": "Parent Page ID",
"type": "uint64"
},
{
"name": "moduleID",
"required": false,
"title": "Module ID (optional)",
"type": "uint64"
},
{
"name": "title",
"required": true,
"title": "Title",
"type": "string"
},
{
"name": "description",
"required": false,
"title": "Description",
"type": "string"
},
{
"name": "visible",
"required": false,
"title": "Visible in navigation",
"type": "bool"
},
{
"name": "blocks",
"required": true,
"title": "Blocks JSON",
"type": "types.JSONText"
}
]
}
},
{
"Name": "read",
"Method": "GET",
"Title": "Get page details",
"Path": "/{id}",
"Parameters": {
"path": [
{
"name": "id",
"required": true,
"title": "Page ID",
"type": "uint64"
}
]
}
},
{
"Name": "edit",
"Method": "POST",
"Title": "Create page",
"Path": "/{id}",
"Parameters": {
"path": [
{
"name": "id",
"required": true,
"title": "Page ID",
"type": "uint64"
}
],
"post": [
{
"name": "selfID",
"required": false,
"title": "Parent Page ID",
"type": "uint64"
},
{
"name": "moduleID",
"required": false,
"title": "Module ID (optional)",
"type": "uint64"
},
{
"name": "title",
"required": true,
"title": "Title",
"type": "string"
},
{
"name": "description",
"required": false,
"title": "Description",
"type": "string"
},
{
"name": "visible",
"required": false,
"title": "Visible in navigation",
"type": "bool"
},
{
"name": "blocks",
"required": true,
"title": "Blocks JSON",
"type": "types.JSONText"
}
]
}
},
{
"Name": "delete",
"Method": "Delete",
"Title": "Delete page",
"Path": "/{id}",
"Parameters": {
"path": [
{
"name": "id",
"required": true,
"title": "Page ID",
"type": "uint64"
}
]
}
}
]
}

66
crm/repository/page.go Normal file
View File

@ -0,0 +1,66 @@
package repository
import (
"context"
"github.com/titpetric/factory"
"github.com/crusttech/crust/crm/types"
)
type (
PageRepository interface {
With(ctx context.Context, db *factory.DB) PageRepository
Find() ([]*types.Page, error)
FindByID(id uint64) (*types.Page, error)
FindByModuleID(id uint64) (*types.Page, error)
Create(mod *types.Page) (*types.Page, error)
Update(mod *types.Page) (*types.Page, error)
DeleteByID(id uint64) error
}
page struct {
*repository
}
)
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 {
return &page{
repository: r.repository.With(ctx, db),
}
}
func (r *page) FindByID(id uint64) (*types.Page, error) {
mod := &types.Page{}
return mod, r.db().Get(mod, "SELECT * FROM crm_page WHERE id=?", id)
}
func (r *page) FindByModuleID(id uint64) (*types.Page, error) {
mod := &types.Page{}
return mod, r.db().Get(mod, "SELECT * FROM crm_page WHERE module_id=?", id)
}
func (r *page) Find() ([]*types.Page, error) {
mod := make([]*types.Page, 0)
return mod, r.db().Select(&mod, "SELECT * FROM crm_page ORDER BY id ASC")
}
func (r *page) Create(mod *types.Page) (*types.Page, error) {
mod.ID = factory.Sonyflake.NextID()
return mod, r.db().Insert("crm_page", mod)
}
func (r *page) Update(mod *types.Page) (*types.Page, error) {
return mod, r.db().Replace("crm_page", mod)
}
func (r *page) DeleteByID(id uint64) error {
_, err := r.db().Exec("DELETE FROM crm_page WHERE id=?", id)
return err
}

View File

@ -0,0 +1,71 @@
package repository
import (
"context"
"github.com/crusttech/crust/crm/types"
"testing"
)
func TestPage(t *testing.T) {
repository := Page(context.TODO(), nil).With(context.Background(), nil)
// the page object we're working with
page := &types.Page{
Name: "Test",
}
(&page.Blocks).Scan([]byte("[]"))
prevPageCount := 0
{
// create page
m, err := repository.Create(page)
assert(t, err == nil, "Error when creating page: %+v", err)
assert(t, m.ID > 0, "Expected auto generated ID")
// fetch created page
{
ms, err := repository.FindByID(m.ID)
assert(t, err == nil, "Error when retrieving page by id: %+v", err)
assert(t, ms.ID == m.ID, "Expected ID from database to match, %d != %d", m.ID, ms.ID)
assert(t, ms.Name == m.Name, "Expected Name from database to match, %s != %s", m.Name, ms.Name)
}
// update created page
{
m.Name = "Updated test"
_, err := repository.Update(m)
assert(t, err == nil, "Error when updating page, %+v", err)
}
// re-fetch page
{
ms, err := repository.FindByID(m.ID)
assert(t, err == nil, "Error when retrieving page by id: %+v", err)
assert(t, ms.ID == m.ID, "Expected ID from database to match, %d != %d", m.ID, ms.ID)
assert(t, ms.Name == m.Name, "Expected Name from database to match, %s != %s", m.Name, ms.Name)
}
// fetch all pages
{
ms, err := repository.Find()
assert(t, err == nil, "Error when retrieving pages: %+v", err)
assert(t, len(ms) >= 1, "Expected at least one page, got %d", len(ms))
prevPageCount = len(ms)
}
// re-fetch page
{
err := repository.DeleteByID(m.ID)
assert(t, err == nil, "Error when deleting page by id: %+v", err)
}
// fetch all pages
{
ms, err := repository.Find()
assert(t, err == nil, "Error when retrieving pages: %+v", err)
assert(t, len(ms) < prevPageCount, "Expected pages count to decrease after deletion, %d < %d", len(ms), prevPageCount)
}
}
}

View File

@ -1,16 +1,13 @@
package rest
import (
"github.com/pkg/errors"
"context"
"github.com/crusttech/crust/crm/rest/request"
"github.com/crusttech/crust/crm/service"
"github.com/crusttech/crust/crm/types"
)
var _ = errors.Wrap
type (
Field struct {
field service.FieldService

97
crm/rest/handlers/page.go Normal file
View File

@ -0,0 +1,97 @@
package handlers
/*
Hello! This file is auto-generated from `docs/src/spec.json`.
For development:
In order to update the generated files, edit this file under the location,
add your struct fields, imports, API definitions and whatever you want, and:
1. run [spec](https://github.com/titpetric/spec) in the same folder,
2. run `./_gen.php` in this folder.
You may edit `page.go`, `page.util.go` or `page_test.go` to
implement your API calls, helper functions and tests. The file `page.go`
is only generated the first time, and will not be overwritten if it exists.
*/
import (
"context"
"github.com/go-chi/chi"
"net/http"
"github.com/titpetric/factory/resputil"
"github.com/crusttech/crust/crm/rest/request"
)
// Internal API interface
type PageAPI interface {
List(context.Context, *request.PageList) (interface{}, error)
Create(context.Context, *request.PageCreate) (interface{}, error)
Read(context.Context, *request.PageRead) (interface{}, error)
Edit(context.Context, *request.PageEdit) (interface{}, error)
Delete(context.Context, *request.PageDelete) (interface{}, error)
}
// HTTP API interface
type Page struct {
List func(http.ResponseWriter, *http.Request)
Create func(http.ResponseWriter, *http.Request)
Read func(http.ResponseWriter, *http.Request)
Edit func(http.ResponseWriter, *http.Request)
Delete func(http.ResponseWriter, *http.Request)
}
func NewPage(ph PageAPI) *Page {
return &Page{
List: func(w http.ResponseWriter, r *http.Request) {
defer r.Body.Close()
params := request.NewPageList()
resputil.JSON(w, params.Fill(r), func() (interface{}, error) {
return ph.List(r.Context(), params)
})
},
Create: func(w http.ResponseWriter, r *http.Request) {
defer r.Body.Close()
params := request.NewPageCreate()
resputil.JSON(w, params.Fill(r), func() (interface{}, error) {
return ph.Create(r.Context(), params)
})
},
Read: func(w http.ResponseWriter, r *http.Request) {
defer r.Body.Close()
params := request.NewPageRead()
resputil.JSON(w, params.Fill(r), func() (interface{}, error) {
return ph.Read(r.Context(), params)
})
},
Edit: func(w http.ResponseWriter, r *http.Request) {
defer r.Body.Close()
params := request.NewPageEdit()
resputil.JSON(w, params.Fill(r), func() (interface{}, error) {
return ph.Edit(r.Context(), params)
})
},
Delete: func(w http.ResponseWriter, r *http.Request) {
defer r.Body.Close()
params := request.NewPageDelete()
resputil.JSON(w, params.Fill(r), func() (interface{}, error) {
return ph.Delete(r.Context(), params)
})
},
}
}
func (ph *Page) MountRoutes(r chi.Router, middlewares ...func(http.Handler) http.Handler) {
r.Group(func(r chi.Router) {
r.Use(middlewares...)
r.Route("/page", func(r chi.Router) {
r.Get("/", ph.List)
r.Post("/", ph.Create)
r.Get("/{id}", ph.Read)
r.Post("/{id}", ph.Edit)
r.Delete("/{id}", ph.Delete)
})
})
}

View File

@ -1,18 +1,15 @@
package rest
import (
"github.com/pkg/errors"
"context"
"github.com/titpetric/factory/resputil"
"context"
"github.com/crusttech/crust/crm/rest/request"
"github.com/crusttech/crust/crm/service"
"github.com/crusttech/crust/crm/types"
)
var _ = errors.Wrap
type (
Module struct {
module service.ModuleService
@ -63,7 +60,7 @@ func (s *Module) ContentRead(ctx context.Context, r *request.ModuleContentRead)
func (s *Module) ContentCreate(ctx context.Context, r *request.ModuleContentCreate) (interface{}, error) {
item := &types.Content{
ModuleID: r.Module,
ModuleID: r.ModuleID,
Fields: r.Fields,
}
return s.content.With(ctx).Create(item)
@ -72,7 +69,7 @@ func (s *Module) ContentCreate(ctx context.Context, r *request.ModuleContentCrea
func (s *Module) ContentEdit(ctx context.Context, r *request.ModuleContentEdit) (interface{}, error) {
item := &types.Content{
ID: r.ID,
ModuleID: r.Module,
ModuleID: r.ModuleID,
Fields: r.Fields,
}
return s.content.With(ctx).Update(item)

58
crm/rest/page.go Normal file
View File

@ -0,0 +1,58 @@
package rest
import (
"context"
"github.com/titpetric/factory/resputil"
"github.com/crusttech/crust/crm/rest/request"
"github.com/crusttech/crust/crm/service"
"github.com/crusttech/crust/crm/types"
)
type (
Page struct {
page service.PageService
}
)
func (Page) New(pageSvc service.PageService) *Page {
return &Page{pageSvc}
}
func (ctrl *Page) List(ctx context.Context, r *request.PageList) (interface{}, error) {
return ctrl.page.With(ctx).Find()
}
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)
}
func (ctrl *Page) Read(ctx context.Context, r *request.PageRead) (interface{}, error) {
return ctrl.page.With(ctx).FindByID(r.ID)
}
func (ctrl *Page) Edit(ctx context.Context, r *request.PageEdit) (interface{}, error) {
p := &types.Page{
ID: r.ID,
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)
}
func (ctrl *Page) Delete(ctx context.Context, r *request.PageDelete) (interface{}, error) {
return resputil.OK(), ctrl.page.With(ctx).DeleteByID(r.ID)
}

View File

@ -267,7 +267,7 @@ var _ RequestFiller = NewModuleDelete()
// Module content/list request parameters
type ModuleContentList struct {
Module uint64
ModuleID uint64
}
func NewModuleContentList() *ModuleContentList {
@ -300,7 +300,7 @@ func (m *ModuleContentList) Fill(r *http.Request) error {
post[name] = string(param[0])
}
m.Module = parseUInt64(chi.URLParam(r, "module"))
m.ModuleID = parseUInt64(chi.URLParam(r, "moduleID"))
return err
}
@ -309,8 +309,8 @@ var _ RequestFiller = NewModuleContentList()
// Module content/create request parameters
type ModuleContentCreate struct {
Module uint64
Fields types.JSONText
ModuleID uint64
Fields types.JSONText
}
func NewModuleContentCreate() *ModuleContentCreate {
@ -343,7 +343,7 @@ func (m *ModuleContentCreate) Fill(r *http.Request) error {
post[name] = string(param[0])
}
m.Module = parseUInt64(chi.URLParam(r, "module"))
m.ModuleID = parseUInt64(chi.URLParam(r, "moduleID"))
if val, ok := post["fields"]; ok {
if m.Fields, err = parseJSONText(val); err != nil {
@ -358,8 +358,8 @@ var _ RequestFiller = NewModuleContentCreate()
// Module content/read request parameters
type ModuleContentRead struct {
Module uint64
ID uint64
ModuleID uint64
ID uint64
}
func NewModuleContentRead() *ModuleContentRead {
@ -392,7 +392,7 @@ func (m *ModuleContentRead) Fill(r *http.Request) error {
post[name] = string(param[0])
}
m.Module = parseUInt64(chi.URLParam(r, "module"))
m.ModuleID = parseUInt64(chi.URLParam(r, "moduleID"))
m.ID = parseUInt64(chi.URLParam(r, "id"))
return err
@ -402,9 +402,9 @@ var _ RequestFiller = NewModuleContentRead()
// Module content/edit request parameters
type ModuleContentEdit struct {
Module uint64
ID uint64
Fields types.JSONText
ModuleID uint64
ID uint64
Fields types.JSONText
}
func NewModuleContentEdit() *ModuleContentEdit {
@ -437,7 +437,7 @@ func (m *ModuleContentEdit) Fill(r *http.Request) error {
post[name] = string(param[0])
}
m.Module = parseUInt64(chi.URLParam(r, "module"))
m.ModuleID = parseUInt64(chi.URLParam(r, "moduleID"))
m.ID = parseUInt64(chi.URLParam(r, "id"))
if val, ok := post["fields"]; ok {
@ -453,8 +453,8 @@ var _ RequestFiller = NewModuleContentEdit()
// Module content/delete request parameters
type ModuleContentDelete struct {
Module uint64
ID uint64
ModuleID uint64
ID uint64
}
func NewModuleContentDelete() *ModuleContentDelete {
@ -487,7 +487,7 @@ func (m *ModuleContentDelete) Fill(r *http.Request) error {
post[name] = string(param[0])
}
m.Module = parseUInt64(chi.URLParam(r, "module"))
m.ModuleID = parseUInt64(chi.URLParam(r, "moduleID"))
m.ID = parseUInt64(chi.URLParam(r, "id"))
return err

300
crm/rest/request/page.go Normal file
View File

@ -0,0 +1,300 @@
package request
/*
Hello! This file is auto-generated from `docs/src/spec.json`.
For development:
In order to update the generated files, edit this file under the location,
add your struct fields, imports, API definitions and whatever you want, and:
1. run [spec](https://github.com/titpetric/spec) in the same folder,
2. run `./_gen.php` in this folder.
You may edit `page.go`, `page.util.go` or `page_test.go` to
implement your API calls, helper functions and tests. The file `page.go`
is only generated the first time, and will not be overwritten if it exists.
*/
import (
"encoding/json"
"github.com/go-chi/chi"
"github.com/jmoiron/sqlx/types"
"github.com/pkg/errors"
"io"
"mime/multipart"
"net/http"
"strings"
)
var _ = chi.URLParam
var _ = types.JSONText{}
var _ = multipart.FileHeader{}
// Page list request parameters
type PageList struct {
}
func NewPageList() *PageList {
return &PageList{}
}
func (p *PageList) Fill(r *http.Request) error {
var 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")
}
}
r.ParseForm()
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 = NewPageList()
// Page create request parameters
type PageCreate struct {
SelfID uint64
ModuleID uint64
Title string
Description string
Visible bool
Blocks types.JSONText
}
func NewPageCreate() *PageCreate {
return &PageCreate{}
}
func (p *PageCreate) Fill(r *http.Request) error {
var 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")
}
}
r.ParseForm()
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])
}
if val, ok := post["selfID"]; ok {
p.SelfID = parseUInt64(val)
}
if val, ok := post["moduleID"]; ok {
p.ModuleID = parseUInt64(val)
}
if val, ok := post["title"]; ok {
p.Title = val
}
if val, ok := post["description"]; ok {
p.Description = val
}
if val, ok := post["visible"]; ok {
p.Visible = parseBool(val)
}
if val, ok := post["blocks"]; ok {
if p.Blocks, err = parseJSONText(val); err != nil {
return err
}
}
return err
}
var _ RequestFiller = NewPageCreate()
// Page read request parameters
type PageRead struct {
ID uint64
}
func NewPageRead() *PageRead {
return &PageRead{}
}
func (p *PageRead) Fill(r *http.Request) error {
var 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")
}
}
r.ParseForm()
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])
}
p.ID = parseUInt64(chi.URLParam(r, "id"))
return err
}
var _ RequestFiller = NewPageRead()
// Page edit request parameters
type PageEdit struct {
ID uint64
SelfID uint64
ModuleID uint64
Title string
Description string
Visible bool
Blocks types.JSONText
}
func NewPageEdit() *PageEdit {
return &PageEdit{}
}
func (p *PageEdit) Fill(r *http.Request) error {
var 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")
}
}
r.ParseForm()
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])
}
p.ID = parseUInt64(chi.URLParam(r, "id"))
if val, ok := post["selfID"]; ok {
p.SelfID = parseUInt64(val)
}
if val, ok := post["moduleID"]; ok {
p.ModuleID = parseUInt64(val)
}
if val, ok := post["title"]; ok {
p.Title = val
}
if val, ok := post["description"]; ok {
p.Description = val
}
if val, ok := post["visible"]; ok {
p.Visible = parseBool(val)
}
if val, ok := post["blocks"]; ok {
if p.Blocks, err = parseJSONText(val); err != nil {
return err
}
}
return err
}
var _ RequestFiller = NewPageEdit()
// Page delete request parameters
type PageDelete struct {
ID uint64
}
func NewPageDelete() *PageDelete {
return &PageDelete{}
}
func (p *PageDelete) Fill(r *http.Request) error {
var 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")
}
}
r.ParseForm()
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])
}
p.ID = parseUInt64(chi.URLParam(r, "id"))
return err
}
var _ RequestFiller = NewPageDelete()

View File

@ -1,10 +1,11 @@
package rest
import (
"github.com/go-chi/chi"
"github.com/crusttech/crust/crm/rest/handlers"
"github.com/crusttech/crust/crm/service"
"github.com/crusttech/crust/internal/auth"
"github.com/go-chi/chi"
)
func MountRoutes(jwtAuth auth.TokenEncoder) func(chi.Router) {
@ -12,11 +13,13 @@ func MountRoutes(jwtAuth auth.TokenEncoder) func(chi.Router) {
fieldSvc = service.Field()
moduleSvc = service.Module()
contentSvc = service.Content()
pageSvc = service.Page()
)
var (
field = Field{}.New(fieldSvc)
module = Module{}.New(moduleSvc, contentSvc)
page = Page{}.New(pageSvc)
)
// Initialize handers & controllers.
@ -26,6 +29,7 @@ func MountRoutes(jwtAuth auth.TokenEncoder) func(chi.Router) {
r.Use(auth.MiddlewareValidOnly)
handlers.NewField(field).MountRoutes(r)
handlers.NewPage(page).MountRoutes(r)
handlers.NewModule(module).MountRoutes(r)
})
}

62
crm/service/page.go Normal file
View File

@ -0,0 +1,62 @@
package service
import (
"context"
"github.com/titpetric/factory"
"github.com/crusttech/crust/crm/repository"
"github.com/crusttech/crust/crm/types"
)
type (
page struct {
db *factory.DB
ctx context.Context
repository repository.PageRepository
}
PageService interface {
With(ctx context.Context) PageService
FindByID(pageID uint64) (*types.Page, error)
Find() ([]*types.Page, error)
Create(page *types.Page) (*types.Page, error)
Update(page *types.Page) (*types.Page, error)
DeleteByID(pageID uint64) error
}
)
func Page() PageService {
return (&page{}).With(context.Background())
}
func (s *page) With(ctx context.Context) PageService {
db := repository.DB(ctx)
return &page{
db: db,
ctx: ctx,
repository: repository.Page(ctx, db),
}
}
func (s *page) FindByID(id uint64) (*types.Page, error) {
return s.repository.FindByID(id)
}
func (s *page) Find() ([]*types.Page, error) {
return s.repository.Find()
}
func (s *page) Create(mod *types.Page) (*types.Page, error) {
return s.repository.Create(mod)
}
func (s *page) Update(mod *types.Page) (*types.Page, error) {
return s.repository.Update(mod)
}
func (s *page) DeleteByID(id uint64) error {
return s.repository.DeleteByID(id)
}

View File

@ -57,4 +57,31 @@ type (
MaxLength int `json:"maxLength" db:"max_length"`
Private bool `json:"isPrivate" db:"is_private"`
}
// Page - page structure
Page struct {
ID uint64 `json:"id" db:"id"`
SelfID uint64 `json:"selfID" db:"self_id"`
ModuleID uint64 `json:"moduleID" db:"module_id"`
Title string `json:"title" db:"title"`
Description string `json:"description" db:"description"`
Blocks types.JSONText `json:"blocks" db:"blocks"`
Visible bool `json:"visible" db:"visible"`
Weight int `json:"-" db:"weight"`
}
// Block - value of Page.Blocks ([]Block)
Block struct {
Title string `json:"title"`
Description string `json:"description"`
Options types.JSONText `json:"options"`
Kind string `json:"kind"`
X int `json:"x"`
Y int `json:"y"`
Width int `json:"width"`
Height int `json:"height"`
}
)