3
0

Merge branch 'feature/module-field-options'

This commit is contained in:
Denis Arh
2018-12-05 11:17:11 +01:00
48 changed files with 243 additions and 469 deletions
+16 -94
View File
@@ -6,29 +6,7 @@
"entrypoint": "field",
"path": "/field",
"authentication": [],
"struct": [
{
"name": "Field",
"fields": [
{
"name": "Name",
"type": "string",
"db": "field_name"
},
{
"name": "Type",
"type": "string",
"db": "field_type"
},
{
"name": "Template",
"type": "string",
"db": "field_template",
"omitempty": true
}
]
}
],
"struct": [],
"apis": [
{
"name": "list",
@@ -61,7 +39,13 @@
"entrypoint": "page",
"path": "/page",
"authentication": [],
"struct": [],
"struct": [
{
"imports": [
"sqlxTypes github.com/jmoiron/sqlx/types"
]
}
],
"apis": [
{
"name": "list",
@@ -117,7 +101,7 @@
"title": "Visible in navigation"
},
{
"type": "types.JSONText",
"type": "sqlxTypes.JSONText",
"name": "blocks",
"required": true,
"title": "Blocks JSON"
@@ -194,7 +178,7 @@
"title": "Visible in navigation"
},
{
"type": "types.JSONText",
"type": "sqlxTypes.JSONText",
"name": "blocks",
"required": true,
"title": "Blocks JSON"
@@ -253,71 +237,9 @@
"authentication": [],
"struct": [
{
"name": "Module",
"imports": [
"github.com/jmoiron/sqlx/types"
],
"fields": [
{
"name": "ID",
"type": "uint64"
},
{
"name": "Name",
"type": "string"
},
{
"name": "Fields",
"type": "types.JSONText",
"json": "fields",
"db": "json"
}
]
},
{
"name": "ModuleField",
"fields": [
{
"name": "Name",
"type": "string"
},
{
"name": "Title",
"type": "string"
},
{
"name": "Kind",
"type": "string"
},
{
"name": "GDPR",
"type": "bool"
},
{
"name": "Show",
"type": "bool"
}
]
},
{
"name": "Content",
"imports": [
"github.com/jmoiron/sqlx/types"
],
"fields": [
{
"name": "ID",
"type": "uint64"
},
{
"name": "moduleID",
"type": "uint64"
},
{
"name": "Fields",
"type": "types.JSONText",
"db": "json"
}
"sqlxTypes github.com/jmoiron/sqlx/types",
"github.com/crusttech/crust/crm/types"
]
}
],
@@ -352,7 +274,7 @@
"title": "Module Name"
},
{
"type": "types.JSONText",
"type": "types.ModuleFieldSet",
"name": "fields",
"required": true,
"title": "Fields JSON"
@@ -476,7 +398,7 @@
"title": "Module Name"
},
{
"type": "types.JSONText",
"type": "types.ModuleFieldSet",
"name": "fields",
"required": true,
"title": "Fields JSON"
@@ -552,7 +474,7 @@
],
"post": [
{
"type": "types.JSONText",
"type": "sqlxTypes.JSONText",
"name": "fields",
"required": true,
"title": "Content JSON"
@@ -604,7 +526,7 @@
],
"post": [
{
"type": "types.JSONText",
"type": "sqlxTypes.JSONText",
"name": "fields",
"required": true,
"title": "Content JSON"
+1 -23
View File
@@ -3,29 +3,7 @@
"Description": "CRM input field definitions",
"Package": "crm",
"Interface": "Field",
"Struct": [
{
"fields": [
{
"db": "field_name",
"name": "Name",
"type": "string"
},
{
"db": "field_type",
"name": "Type",
"type": "string"
},
{
"db": "field_template",
"name": "Template",
"omitempty": true,
"type": "string"
}
],
"name": "Field"
}
],
"Struct": [],
"Parameters": null,
"Protocol": "",
"Authentication": [],
+7 -69
View File
@@ -5,72 +5,10 @@
"Interface": "Module",
"Struct": [
{
"fields": [
{
"name": "ID",
"type": "uint64"
},
{
"name": "Name",
"type": "string"
},
{
"db": "json",
"json": "fields",
"name": "Fields",
"type": "types.JSONText"
}
],
"imports": [
"github.com/jmoiron/sqlx/types"
],
"name": "Module"
},
{
"fields": [
{
"name": "Name",
"type": "string"
},
{
"name": "Title",
"type": "string"
},
{
"name": "Kind",
"type": "string"
},
{
"name": "GDPR",
"type": "bool"
},
{
"name": "Show",
"type": "bool"
}
],
"name": "ModuleField"
},
{
"fields": [
{
"name": "ID",
"type": "uint64"
},
{
"name": "moduleID",
"type": "uint64"
},
{
"db": "json",
"name": "Fields",
"type": "types.JSONText"
}
],
"imports": [
"github.com/jmoiron/sqlx/types"
],
"name": "Content"
"sqlxTypes github.com/jmoiron/sqlx/types",
"github.com/crusttech/crust/crm/types"
]
}
],
"Parameters": null,
@@ -111,7 +49,7 @@
"name": "fields",
"required": true,
"title": "Fields JSON",
"type": "types.JSONText"
"type": "types.ModuleFieldSet"
}
]
}
@@ -235,7 +173,7 @@
"name": "fields",
"required": true,
"title": "Fields JSON",
"type": "types.JSONText"
"type": "types.ModuleFieldSet"
}
]
}
@@ -311,7 +249,7 @@
"name": "fields",
"required": true,
"title": "Content JSON",
"type": "types.JSONText"
"type": "sqlxTypes.JSONText"
}
]
}
@@ -363,7 +301,7 @@
"name": "fields",
"required": true,
"title": "Content JSON",
"type": "types.JSONText"
"type": "sqlxTypes.JSONText"
}
]
}
+9 -3
View File
@@ -3,7 +3,13 @@
"Description": "CRM module pages",
"Package": "crm",
"Interface": "Page",
"Struct": [],
"Struct": [
{
"imports": [
"sqlxTypes github.com/jmoiron/sqlx/types"
]
}
],
"Parameters": null,
"Protocol": "",
"Authentication": [],
@@ -66,7 +72,7 @@
"name": "blocks",
"required": true,
"title": "Blocks JSON",
"type": "types.JSONText"
"type": "sqlxTypes.JSONText"
}
]
}
@@ -143,7 +149,7 @@
"name": "blocks",
"required": true,
"title": "Blocks JSON",
"type": "types.JSONText"
"type": "sqlxTypes.JSONText"
}
]
}
+7
View File
@@ -644,6 +644,13 @@
"Client ID",
"Session ID"
],
"struct": [
{
"imports": [
"github.com/crusttech/crust/internal/rbac"
]
}
],
"apis": [
{
"name": "list",
+7 -1
View File
@@ -2,7 +2,13 @@
"Title": "Permissions",
"Package": "sam",
"Interface": "Permissions",
"Struct": null,
"Struct": [
{
"imports": [
"github.com/crusttech/crust/internal/rbac"
]
}
],
"Parameters": {},
"Protocol": "",
"Authentication": [
+3 -3
View File
@@ -398,7 +398,7 @@
"struct": [
{
"imports": [
"github.com/jmoiron/sqlx/types"
"sqlxTypes github.com/jmoiron/sqlx/types"
]
}
],
@@ -464,7 +464,7 @@
},
{
"name": "meta",
"type": "types.JSONText",
"type": "sqlxTypes.JSONText",
"required": false,
"title": "Meta data"
},
@@ -536,7 +536,7 @@
},
{
"name": "meta",
"type": "types.JSONText",
"type": "sqlxTypes.JSONText",
"required": false,
"title": "Meta data"
},
+3 -3
View File
@@ -5,7 +5,7 @@
"Struct": [
{
"imports": [
"github.com/jmoiron/sqlx/types"
"sqlxTypes github.com/jmoiron/sqlx/types"
]
}
],
@@ -80,7 +80,7 @@
"name": "meta",
"required": false,
"title": "Meta data",
"type": "types.JSONText"
"type": "sqlxTypes.JSONText"
},
{
"name": "satosaID",
@@ -152,7 +152,7 @@
"name": "meta",
"required": false,
"title": "Meta data",
"type": "types.JSONText"
"type": "sqlxTypes.JSONText"
},
{
"name": "satosaID",
+19 -1
View File
@@ -38,9 +38,27 @@ function array_change_key_case_recursive($arr) {
}, array_change_key_case($arr));
}
function imports($api) {
$imports = array();
if (is_array($api['struct']))
foreach ($api['struct'] as $struct) {
if (isset($struct['imports']))
foreach ($struct['imports'] as $import) {
$import = explode(" ", $import);
if (count($import) == 1) {
$imports[] = '"' . $import[0] . '"';
} else {
$imports[] = $import[0] . ' "' . $import[1] . '"';
}
}
}
return array_unique($imports);
}
$tpl = new Monotek\MiniTPL\Template;
$tpl->set_compile_location("/tmp", true);
$tpl->add_default("newline", "\n");
$tpl->add_default("EOL", "\n");
$generators = array();
exec("find -L " . __DIR__ . "/" . $project . " -name index.php", $generators);
@@ -81,7 +99,7 @@ $parsers = array(
"[]uint64" => "parseUInt64A",
"int" => "parseInt",
"bool" => "parseBool",
"types.JSONText" => "parseJSONText",
"sqlxTypes.JSONText" => "parseJSONTextWithErr",
);
foreach ($generators as $generator) {
+1 -8
View File
@@ -19,14 +19,7 @@ foreach ($apis as $api) {
$tpl->assign("apis", $apis);
$tpl->assign("self", strtolower(substr($name, 0, 1)));
$tpl->assign("structs", $api['struct']);
$imports = array();
if (is_array($api['struct']))
foreach ($api['struct'] as $struct) {
if (isset($struct['imports']))
foreach ($struct['imports'] as $import) {
$imports[] = $import;
}
}
$imports = imports($api);
$tpl->assign("imports", $imports);
$tpl->assign("calls", $api['apis']);
$contents = str_replace("\n\n}", "\n}", $tpl->get());
+1 -8
View File
@@ -11,14 +11,7 @@ foreach ($apis as $api) {
$tpl->assign("api", $api);
$tpl->assign("self", strtolower(substr($name, 0, 1)));
$tpl->assign("structs", $api['struct']);
$imports = array();
if (is_array($api['struct']))
foreach ($api['struct'] as $struct) {
if (isset($struct['imports']))
foreach ($struct['imports'] as $import) {
$imports[] = $import;
}
}
$imports = imports($api);
$tpl->assign("imports", $imports);
$tpl->assign("calls", $api['apis']);
$contents = str_replace("\n\n}", "\n}", $tpl->get());
+1 -8
View File
@@ -19,14 +19,7 @@ foreach ($apis as $api) {
$tpl->assign("apis", $apis);
$tpl->assign("self", strtolower(substr($name, 0, 1)));
$tpl->assign("structs", $api['struct']);
$imports = array();
if (is_array($api['struct']))
foreach ($api['struct'] as $struct) {
if (isset($struct['imports']))
foreach ($struct['imports'] as $import) {
$imports[] = $import;
}
}
$imports = imports($api);
$tpl->assign("imports", $imports);
$tpl->assign("calls", $api['apis']);
$contents = str_replace("\n\n}", "\n}", $tpl->get());
+1 -7
View File
@@ -22,13 +22,7 @@ foreach ($apis as $api) {
$tpl->assign("apis", $apis);
$tpl->assign("self", strtolower(substr($name, 0, 1)));
$tpl->assign("structs", $api['struct']);
$imports = array();
foreach ($api['struct'] as $struct) {
if (isset($struct['imports']))
foreach ($struct['imports'] as $import) {
$imports[] = $import;
}
}
$imports = imports($api);
$tpl->assign("imports", $imports);
$tpl->assign("calls", $api['apis']);
$contents = str_replace("\n\n}", "\n}", $tpl->get());
+1 -8
View File
@@ -19,14 +19,7 @@ foreach ($apis as $api) {
$tpl->assign("apis", $apis);
$tpl->assign("self", strtolower(substr($name, 0, 1)));
$tpl->assign("structs", $api['struct']);
$imports = array();
if (is_array($api['struct']))
foreach ($api['struct'] as $struct) {
if (isset($struct['imports']))
foreach ($struct['imports'] as $import) {
$imports[] = $import;
}
}
$imports = imports($api);
$tpl->assign("imports", $imports);
$tpl->assign("calls", $api['apis']);
$contents = str_replace("\n\n}", "\n}", $tpl->get());
+1 -8
View File
@@ -11,14 +11,7 @@ foreach ($apis as $api) {
$tpl->assign("api", $api);
$tpl->assign("self", strtolower(substr($name, 0, 1)));
$tpl->assign("structs", $api['struct']);
$imports = array();
if (is_array($api['struct']))
foreach ($api['struct'] as $struct) {
if (isset($struct['imports']))
foreach ($struct['imports'] as $import) {
$imports[] = $import;
}
}
$imports = imports($api);
$tpl->assign("imports", $imports);
$tpl->assign("calls", $api['apis']);
$contents = str_replace("\n\n}", "\n}", $tpl->get());
+1 -8
View File
@@ -19,14 +19,7 @@ foreach ($apis as $api) {
$tpl->assign("apis", $apis);
$tpl->assign("self", strtolower(substr($name, 0, 1)));
$tpl->assign("structs", $api['struct']);
$imports = array();
if (is_array($api['struct']))
foreach ($api['struct'] as $struct) {
if (isset($struct['imports']))
foreach ($struct['imports'] as $import) {
$imports[] = $import;
}
}
$imports = imports($api);
$tpl->assign("imports", $imports);
$tpl->assign("calls", $api['apis']);
$contents = str_replace("\n\n}", "\n}", $tpl->get());
+1 -8
View File
@@ -19,14 +19,7 @@ foreach ($apis as $api) {
$tpl->assign("apis", $apis);
$tpl->assign("self", strtolower(substr($name, 0, 1)));
$tpl->assign("structs", $api['struct']);
$imports = array();
if (is_array($api['struct']))
foreach ($api['struct'] as $struct) {
if (isset($struct['imports']))
foreach ($struct['imports'] as $import) {
$imports[] = $import;
}
}
$imports = imports($api);
$tpl->assign("imports", $imports);
$tpl->assign("calls", $api['apis']);
$contents = str_replace("\n\n}", "\n}", $tpl->get());
+1 -8
View File
@@ -11,14 +11,7 @@ foreach ($apis as $api) {
$tpl->assign("api", $api);
$tpl->assign("self", strtolower(substr($name, 0, 1)));
$tpl->assign("structs", $api['struct']);
$imports = array();
if (is_array($api['struct']))
foreach ($api['struct'] as $struct) {
if (isset($struct['imports']))
foreach ($struct['imports'] as $import) {
$imports[] = $import;
}
}
$imports = imports($api);
$tpl->assign("imports", $imports);
$tpl->assign("calls", $api['apis']);
$contents = str_replace("\n\n}", "\n}", $tpl->get());
+1 -8
View File
@@ -19,14 +19,7 @@ foreach ($apis as $api) {
$tpl->assign("apis", $apis);
$tpl->assign("self", strtolower(substr($name, 0, 1)));
$tpl->assign("structs", $api['struct']);
$imports = array();
if (is_array($api['struct']))
foreach ($api['struct'] as $struct) {
if (isset($struct['imports']))
foreach ($struct['imports'] as $import) {
$imports[] = $import;
}
}
$imports = imports($api);
$tpl->assign("imports", $imports);
$tpl->assign("calls", $api['apis']);
$contents = str_replace("\n\n}", "\n}", $tpl->get());
+17 -17
View File
@@ -6,18 +6,18 @@ import (
"io"
"net/http"
"encoding/json"
"github.com/go-chi/chi"
"github.com/pkg/errors"
"github.com/jmoiron/sqlx/types"
"github.com/crusttech/crust/internal/rbac"
"mime/multipart"
"strings"
"github.com/go-chi/chi"
"github.com/pkg/errors"
{if !empty($imports)}{foreach ($imports as $import)}
{import}{EOL}{/foreach}{/if}
)
var _ = chi.URLParam
var _ = types.JSONText{}
var _ = multipart.FileHeader{}
var _ = rbac.Operation{}
{foreach $calls as $call}
// {name} {call.name} request parameters
@@ -65,20 +65,20 @@ func ({self} *{name|expose}{call.name|capitalize}) Fill(r *http.Request) (err er
{foreach $params as $param}
{if strtolower($method) === "path"}
{self}.{param.name|expose} = {if ($param.type !== "string")}{$parsers[$param.type]}({/if}chi.URLParam(r, "{param.name}"){if ($param.type !== "string")}){/if}
{elseif substr($param.type, 0, 2) === '[]' && isset($parsers[$param.type])}
{elseif (substr($param.type, 0, 2) === '[]' || substr($param.type, -3) === "Set") && isset($parsers[$param.type])}
{self}.{param.name|expose} = {$parsers[$param.type]}({if $method === "post"}r.Form["{param.name}"]{else}urlQuery["{param.name}"]{/if})
{elseif $param.type === "*multipart.FileHeader"}
if _, {self}.{param.name|expose}, err = r.FormFile("{$param.name}"); err != nil {
return errors.Wrap(err, "error procesing uploaded file")
}
{elseif substr($param.type, 0, 2) !== '[]'}
if val, ok := {method|strtolower}["{param.name}"]; ok {
{if $param.type === "types.JSONText"}
if {self}.{param.name|expose}, err = {$parsers[$param.type]}(val); err != nil {
return err
}
if _, {self}.{param.name|expose}, err = r.FormFile("{$param.name}"); err != nil {
return errors.Wrap(err, "error procesing uploaded file")
}
{elseif substr($param.type, 0, 2) !== '[]' && substr($param.type, -3) !== 'Set'}
if val, ok := {method|strtolower}["{param.name}"]; ok {
{if substr($parsers[$param.type], -7) === 'WithErr'}
if {self}.{param.name|expose}, err = {$parsers[$param.type]}(val); err != nil {
return err
}
{else}
{self}.{param.name|expose} = {if ($param.type !== "string")}{$parsers[$param.type]}(val){else}val{/if}
{self}.{param.name|expose} = {if ($param.type !== "string")}{$parsers[$param.type]}(val){else}val{/if}{EOL}
{/if}
}{/if}
{/foreach}
+1 -2
View File
@@ -5,8 +5,7 @@ package {package}
{if !empty($imports)}
import (
{foreach ($imports as $import)}
"{import}"
{/foreach}
{import}{EOL}{/foreach}
)
{/if}
File diff suppressed because one or more lines are too long
@@ -0,0 +1 @@
ALTER TABLE `crm_module_form` ADD `json` JSON NOT NULL COMMENT 'Options in JSON format.' AFTER `kind`;
+3 -3
View File
@@ -67,8 +67,8 @@ func (r *content) FindByID(id uint64) (*types.Content, error) {
}
func (r *content) Find(moduleID uint64, query string, page int, perPage int) (*FindResponse, error) {
if page < 1 {
page = 1
if page < 0 {
page = 0
}
if perPage <= 0 {
perPage = 50
@@ -95,7 +95,7 @@ func (r *content) Find(moduleID uint64, query string, page int, perPage int) (*F
sqlWhere := "WHERE module_id=? and deleted_at IS NULL"
sqlOrder := "ORDER BY id DESC"
sqlLimit := fmt.Sprintf("LIMIT %d, %d", (page-1)*perPage, perPage)
sqlLimit := fmt.Sprintf("LIMIT %d, %d", page*perPage, perPage)
switch true {
case query != "":
+2 -18
View File
@@ -2,7 +2,6 @@ package repository
import (
"context"
"encoding/json"
"time"
"github.com/pkg/errors"
@@ -61,13 +60,7 @@ func (r *module) Find() (types.ModuleSet, error) {
func (r *module) Create(mod *types.Module) (*types.Module, error) {
mod.ID = factory.Sonyflake.NextID()
mod.CreatedAt = time.Now()
fields := make([]types.ModuleField, 0)
if err := json.Unmarshal(mod.Fields, &fields); err != nil {
return nil, errors.Wrap(err, "No fields")
}
for idx, v := range fields {
for idx, v := range mod.Fields {
v.ModuleID = mod.ID
v.Place = idx
if err := r.db().Replace("crm_module_form", v); err != nil {
@@ -78,18 +71,9 @@ func (r *module) Create(mod *types.Module) (*types.Module, error) {
}
func (r *module) Update(mod *types.Module) (*types.Module, error) {
if mod.ID == 0 {
return nil, errors.New("Error when saving module, invalid ID")
}
now := time.Now()
mod.UpdatedAt = &now
fields := make([]types.ModuleField, 0)
if err := json.Unmarshal(mod.Fields, &fields); err != nil {
return nil, errors.Wrap(err, "No fields")
}
for idx, v := range fields {
for idx, v := range mod.Fields {
v.ModuleID = mod.ID
v.Place = idx
if err := r.db().Replace("crm_module_form", v); err != nil {
+3 -6
View File
@@ -17,20 +17,17 @@ package request
import (
"encoding/json"
"github.com/crusttech/crust/internal/rbac"
"github.com/go-chi/chi"
"github.com/jmoiron/sqlx/types"
"github.com/pkg/errors"
"io"
"mime/multipart"
"net/http"
"strings"
"github.com/go-chi/chi"
"github.com/pkg/errors"
)
var _ = chi.URLParam
var _ = types.JSONText{}
var _ = multipart.FileHeader{}
var _ = rbac.Operation{}
// Field list request parameters
type FieldList struct {
+12 -24
View File
@@ -17,20 +17,20 @@ package request
import (
"encoding/json"
"github.com/crusttech/crust/internal/rbac"
"github.com/go-chi/chi"
"github.com/jmoiron/sqlx/types"
"github.com/pkg/errors"
"io"
"mime/multipart"
"net/http"
"strings"
"github.com/go-chi/chi"
"github.com/pkg/errors"
"github.com/crusttech/crust/crm/types"
sqlxTypes "github.com/jmoiron/sqlx/types"
)
var _ = chi.URLParam
var _ = types.JSONText{}
var _ = multipart.FileHeader{}
var _ = rbac.Operation{}
// Module list request parameters
type ModuleList struct {
@@ -81,7 +81,7 @@ var _ RequestFiller = NewModuleList()
// Module create request parameters
type ModuleCreate struct {
Name string
Fields types.JSONText
Fields types.ModuleFieldSet
}
func NewModuleCreate() *ModuleCreate {
@@ -119,12 +119,6 @@ func (m *ModuleCreate) Fill(r *http.Request) (err error) {
m.Name = val
}
if val, ok := post["fields"]; ok {
if m.Fields, err = parseJSONText(val); err != nil {
return err
}
}
return err
}
@@ -271,7 +265,7 @@ var _ RequestFiller = NewModuleChart()
type ModuleEdit struct {
ModuleID uint64 `json:",string"`
Name string
Fields types.JSONText
Fields types.ModuleFieldSet
}
func NewModuleEdit() *ModuleEdit {
@@ -310,12 +304,6 @@ func (m *ModuleEdit) Fill(r *http.Request) (err error) {
m.Name = val
}
if val, ok := post["fields"]; ok {
if m.Fields, err = parseJSONText(val); err != nil {
return err
}
}
return err
}
@@ -426,7 +414,7 @@ var _ RequestFiller = NewModuleContentList()
// Module content/create request parameters
type ModuleContentCreate struct {
ModuleID uint64 `json:",string"`
Fields types.JSONText
Fields sqlxTypes.JSONText
}
func NewModuleContentCreate() *ModuleContentCreate {
@@ -463,7 +451,7 @@ func (m *ModuleContentCreate) Fill(r *http.Request) (err error) {
m.ModuleID = parseUInt64(chi.URLParam(r, "moduleID"))
if val, ok := post["fields"]; ok {
if m.Fields, err = parseJSONText(val); err != nil {
if m.Fields, err = parseJSONTextWithErr(val); err != nil {
return err
}
}
@@ -522,7 +510,7 @@ var _ RequestFiller = NewModuleContentRead()
type ModuleContentEdit struct {
ModuleID uint64 `json:",string"`
ContentID uint64 `json:",string"`
Fields types.JSONText
Fields sqlxTypes.JSONText
}
func NewModuleContentEdit() *ModuleContentEdit {
@@ -560,7 +548,7 @@ func (m *ModuleContentEdit) Fill(r *http.Request) (err error) {
m.ContentID = parseUInt64(chi.URLParam(r, "contentID"))
if val, ok := post["fields"]; ok {
if m.Fields, err = parseJSONText(val); err != nil {
if m.Fields, err = parseJSONTextWithErr(val); err != nil {
return err
}
}
+9 -10
View File
@@ -17,20 +17,19 @@ package request
import (
"encoding/json"
"github.com/crusttech/crust/internal/rbac"
"github.com/go-chi/chi"
"github.com/jmoiron/sqlx/types"
"github.com/pkg/errors"
"io"
"mime/multipart"
"net/http"
"strings"
"github.com/go-chi/chi"
"github.com/pkg/errors"
sqlxTypes "github.com/jmoiron/sqlx/types"
)
var _ = chi.URLParam
var _ = types.JSONText{}
var _ = multipart.FileHeader{}
var _ = rbac.Operation{}
// Page list request parameters
type PageList struct {
@@ -85,7 +84,7 @@ type PageCreate struct {
Title string
Description string
Visible bool
Blocks types.JSONText
Blocks sqlxTypes.JSONText
}
func NewPageCreate() *PageCreate {
@@ -141,7 +140,7 @@ func (p *PageCreate) Fill(r *http.Request) (err error) {
}
if val, ok := post["blocks"]; ok {
if p.Blocks, err = parseJSONText(val); err != nil {
if p.Blocks, err = parseJSONTextWithErr(val); err != nil {
return err
}
}
@@ -242,7 +241,7 @@ type PageEdit struct {
Title string
Description string
Visible bool
Blocks types.JSONText
Blocks sqlxTypes.JSONText
}
func NewPageEdit() *PageEdit {
@@ -299,7 +298,7 @@ func (p *PageEdit) Fill(r *http.Request) (err error) {
}
if val, ok := post["blocks"]; ok {
if p.Blocks, err = parseJSONText(val); err != nil {
if p.Blocks, err = parseJSONTextWithErr(val); err != nil {
return err
}
}
+1 -1
View File
@@ -11,7 +11,7 @@ import (
var truthy = regexp.MustCompile("^\\s*(t(rue)?|y(es)?|1)\\s*$")
func parseJSONText(s string) (types.JSONText, error) {
func parseJSONTextWithErr(s string) (types.JSONText, error) {
result := &types.JSONText{}
err := errors.Wrap(result.Scan(s), "error when parsing JSONText")
return *result, err
+16 -18
View File
@@ -2,9 +2,10 @@ package service
import (
"context"
"encoding/json"
"testing"
"encoding/json"
"github.com/pkg/errors"
"github.com/crusttech/crust/crm/types"
@@ -32,26 +33,23 @@ func TestContent(t *testing.T) {
ctx := auth.SetIdentityToContext(context.Background(), auth.NewIdentity(user.Identity()))
repository := Content().With(ctx)
fields, err := json.Marshal([]types.Field{
types.Field{
Name: "name",
Type: "input",
},
types.Field{
Name: "email",
Type: "email",
},
types.Field{
Name: "options",
Type: "select_multi",
},
})
assert(t, err == nil, "Error when encoding JSON fields: %+v", err)
module := &types.Module{
Name: "Test",
Fields: []types.ModuleField{
types.ModuleField{
Name: "name",
Kind: "input",
},
types.ModuleField{
Name: "email",
Kind: "email",
},
types.ModuleField{
Name: "options",
Kind: "select_multi",
},
},
}
(&module.Fields).Scan(fields)
// set up a module
{
+10
View File
@@ -3,6 +3,7 @@ package service
import (
"context"
"github.com/pkg/errors"
"github.com/titpetric/factory"
"github.com/crusttech/crust/crm/repository"
@@ -69,10 +70,19 @@ func (s *module) Chart(r *request.ModuleChart) (interface{}, error) {
}
func (s *module) Create(mod *types.Module) (*types.Module, error) {
if len(mod.Fields) == 0 {
return nil, errors.New("Error creating module: no fields")
}
return s.moduleRepo.Create(mod)
}
func (s *module) Update(mod *types.Module) (*types.Module, error) {
if mod.ID == 0 {
return nil, errors.New("Error updating module: invalid ID")
}
if len(mod.Fields) == 0 {
return nil, errors.New("Error updating module: no fields")
}
return s.moduleRepo.Update(mod)
}
+19 -22
View File
@@ -2,7 +2,6 @@ package service
import (
"context"
"encoding/json"
"testing"
"github.com/crusttech/crust/crm/types"
@@ -11,31 +10,28 @@ import (
func TestModule(t *testing.T) {
repository := Module().With(context.Background())
fields, err := json.Marshal([]types.Field{
types.Field{
Name: "name",
Type: "input",
},
types.Field{
Name: "email",
Type: "email",
},
types.Field{
Name: "options",
Type: "select_multi",
},
types.Field{
Name: "description",
Type: "text",
},
})
assert(t, err == nil, "Error when encoding JSON fields: %+v", err)
// the module object we're working with
module := &types.Module{
Name: "Test",
Fields: []types.ModuleField{
types.ModuleField{
Name: "name",
Kind: "input",
},
types.ModuleField{
Name: "email",
Kind: "email",
},
types.ModuleField{
Name: "options",
Kind: "select_multi",
},
types.ModuleField{
Name: "description",
Kind: "text",
},
},
}
(&module.Fields).Scan(fields)
prevModuleCount := 0
@@ -57,6 +53,7 @@ func TestModule(t *testing.T) {
assert(t, err == nil, "Error when retrieving module 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)
assert(t, len(ms.Fields) == 4, "Expected Fields count from database to match, 4 != %d", len(ms.Fields))
}
// update created module
+19 -1
View File
@@ -3,6 +3,9 @@ package types
import (
"time"
"database/sql/driver"
"encoding/json"
"github.com/jmoiron/sqlx/types"
systemTypes "github.com/crusttech/crust/system/types"
@@ -53,7 +56,7 @@ type (
Module struct {
ID uint64 `json:"moduleID,string" db:"id"`
Name string `json:"name" db:"name"`
Fields types.JSONText `json:"fields" db:"json"`
Fields ModuleFieldSet `json:"fields" db:"json"`
Page *Page `json:"page,omitempty"`
@@ -74,11 +77,15 @@ type (
Default string `json:"defaultValue,omitempty" db:"default_value"`
MaxLength int `json:"maxLength" db:"max_length"`
Options types.JSONText `json:"options" db:"json"`
Private bool `json:"isPrivate" db:"is_private"`
Required bool `json:"isRequired" db:"is_required"`
Visible bool `json:"isVisible" db:"is_visible"`
}
ModuleFieldSet []ModuleField
// Page - page structure
Page struct {
ID uint64 `json:"pageID,string" db:"id"`
@@ -110,3 +117,14 @@ type (
Height int `json:"height"`
}
)
func (f *ModuleFieldSet) Scan(src interface{}) error {
if data, ok := src.([]byte); ok {
return json.Unmarshal(data, f)
}
return nil
}
func (f ModuleFieldSet) Value() (driver.Value, error) {
return json.Marshal(f)
}
+6 -6
View File
@@ -63,7 +63,7 @@ CRM module definitions
| Parameter | Type | Method | Description | Default | Required? |
| --------- | ---- | ------ | ----------- | ------- | --------- |
| name | string | POST | Module Name | N/A | YES |
| fields | types.JSONText | POST | Fields JSON | N/A | YES |
| fields | types.ModuleFieldSet | POST | Fields JSON | N/A | YES |
## Read module
@@ -302,7 +302,7 @@ Example bar chart with number of leads per country: select lead.country from lea
| --------- | ---- | ------ | ----------- | ------- | --------- |
| moduleID | uint64 | PATH | Module ID | N/A | YES |
| name | string | POST | Module Name | N/A | YES |
| fields | types.JSONText | POST | Fields JSON | N/A | YES |
| fields | types.ModuleFieldSet | POST | Fields JSON | N/A | YES |
## Delete module
@@ -348,7 +348,7 @@ Example bar chart with number of leads per country: select lead.country from lea
| Parameter | Type | Method | Description | Default | Required? |
| --------- | ---- | ------ | ----------- | ------- | --------- |
| moduleID | uint64 | PATH | Module ID | N/A | YES |
| fields | types.JSONText | POST | Content JSON | N/A | YES |
| fields | sqlxTypes.JSONText | POST | Content JSON | N/A | YES |
## Read contents by ID from module section
@@ -379,7 +379,7 @@ Example bar chart with number of leads per country: select lead.country from lea
| --------- | ---- | ------ | ----------- | ------- | --------- |
| moduleID | uint64 | PATH | Module ID | N/A | YES |
| contentID | uint64 | PATH | Content ID | N/A | YES |
| fields | types.JSONText | POST | Content JSON | N/A | YES |
| fields | sqlxTypes.JSONText | POST | Content JSON | N/A | YES |
## Delete content row from module section
@@ -434,7 +434,7 @@ CRM module pages
| 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 |
| blocks | sqlxTypes.JSONText | POST | Blocks JSON | N/A | YES |
## Get page details
@@ -481,7 +481,7 @@ CRM module pages
| 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 |
| blocks | sqlxTypes.JSONText | POST | Blocks JSON | N/A | YES |
## Reorder pages
+2 -2
View File
@@ -324,7 +324,7 @@ An organisation may have many teams. Teams may have many channels available. Acc
| name | string | POST | Name | N/A | YES |
| handle | string | POST | Handle | N/A | YES |
| kind | string | POST | Kind (normal, bot) | N/A | NO |
| meta | types.JSONText | POST | Meta data | N/A | NO |
| meta | sqlxTypes.JSONText | POST | Meta data | N/A | NO |
| satosaID | string | POST | Satosa ID | N/A | NO |
| organisationID | uint64 | POST | Organisation ID | N/A | NO |
@@ -347,7 +347,7 @@ An organisation may have many teams. Teams may have many channels available. Acc
| name | string | POST | Name | N/A | YES |
| handle | string | POST | Handle | N/A | YES |
| kind | string | POST | Kind (normal, bot) | N/A | NO |
| meta | types.JSONText | POST | Meta data | N/A | NO |
| meta | sqlxTypes.JSONText | POST | Meta data | N/A | NO |
| satosaID | string | POST | Satosa ID | N/A | NO |
| organisationID | uint64 | POST | Organisation ID | N/A | NO |
+3 -6
View File
@@ -17,20 +17,17 @@ package request
import (
"encoding/json"
"github.com/crusttech/crust/internal/rbac"
"github.com/go-chi/chi"
"github.com/jmoiron/sqlx/types"
"github.com/pkg/errors"
"io"
"mime/multipart"
"net/http"
"strings"
"github.com/go-chi/chi"
"github.com/pkg/errors"
)
var _ = chi.URLParam
var _ = types.JSONText{}
var _ = multipart.FileHeader{}
var _ = rbac.Operation{}
// Attachment original request parameters
type AttachmentOriginal struct {
+3 -6
View File
@@ -17,20 +17,17 @@ package request
import (
"encoding/json"
"github.com/crusttech/crust/internal/rbac"
"github.com/go-chi/chi"
"github.com/jmoiron/sqlx/types"
"github.com/pkg/errors"
"io"
"mime/multipart"
"net/http"
"strings"
"github.com/go-chi/chi"
"github.com/pkg/errors"
)
var _ = chi.URLParam
var _ = types.JSONText{}
var _ = multipart.FileHeader{}
var _ = rbac.Operation{}
// Channel list request parameters
type ChannelList struct {
+3 -6
View File
@@ -17,20 +17,17 @@ package request
import (
"encoding/json"
"github.com/crusttech/crust/internal/rbac"
"github.com/go-chi/chi"
"github.com/jmoiron/sqlx/types"
"github.com/pkg/errors"
"io"
"mime/multipart"
"net/http"
"strings"
"github.com/go-chi/chi"
"github.com/pkg/errors"
)
var _ = chi.URLParam
var _ = types.JSONText{}
var _ = multipart.FileHeader{}
var _ = rbac.Operation{}
// Message create request parameters
type MessageCreate struct {
+5 -6
View File
@@ -17,20 +17,19 @@ package request
import (
"encoding/json"
"github.com/crusttech/crust/internal/rbac"
"github.com/go-chi/chi"
"github.com/jmoiron/sqlx/types"
"github.com/pkg/errors"
"io"
"mime/multipart"
"net/http"
"strings"
"github.com/go-chi/chi"
"github.com/pkg/errors"
"github.com/crusttech/crust/internal/rbac"
)
var _ = chi.URLParam
var _ = types.JSONText{}
var _ = multipart.FileHeader{}
var _ = rbac.Operation{}
// Permissions list request parameters
type PermissionsList struct {
+3 -6
View File
@@ -17,20 +17,17 @@ package request
import (
"encoding/json"
"github.com/crusttech/crust/internal/rbac"
"github.com/go-chi/chi"
"github.com/jmoiron/sqlx/types"
"github.com/pkg/errors"
"io"
"mime/multipart"
"net/http"
"strings"
"github.com/go-chi/chi"
"github.com/pkg/errors"
)
var _ = chi.URLParam
var _ = types.JSONText{}
var _ = multipart.FileHeader{}
var _ = rbac.Operation{}
// Search messages request parameters
type SearchMessages struct {
+1 -1
View File
@@ -2,7 +2,7 @@ package types
import "github.com/crusttech/crust/internal/rbac"
/* File is generated from sam/types/permissions/3-channel.json with permissions.go */
/* File is generated from sam/types/permissions/3-channel.json with permissions.go */
func (c *Channel) Permissions() []rbac.OperationGroup {
return []rbac.OperationGroup{
+1 -1
View File
@@ -2,7 +2,7 @@ package types
import "github.com/crusttech/crust/internal/rbac"
/* File is generated from sam/types/permissions/1-organisation.json with permissions.go */
/* File is generated from sam/types/permissions/1-organisation.json with permissions.go */
func (c *Organisation) Permissions() []rbac.OperationGroup {
return []rbac.OperationGroup{
+1 -1
View File
@@ -2,7 +2,7 @@ package types
import "github.com/crusttech/crust/internal/rbac"
/* File is generated from sam/types/permissions/2-team.json with permissions.go */
/* File is generated from sam/types/permissions/2-team.json with permissions.go */
func (c *Team) Permissions() []rbac.OperationGroup {
return []rbac.OperationGroup{
+3 -6
View File
@@ -17,20 +17,17 @@ package request
import (
"encoding/json"
"github.com/crusttech/crust/internal/rbac"
"github.com/go-chi/chi"
"github.com/jmoiron/sqlx/types"
"github.com/pkg/errors"
"io"
"mime/multipart"
"net/http"
"strings"
"github.com/go-chi/chi"
"github.com/pkg/errors"
)
var _ = chi.URLParam
var _ = types.JSONText{}
var _ = multipart.FileHeader{}
var _ = rbac.Operation{}
// Auth check request parameters
type AuthCheck struct {
+3 -6
View File
@@ -17,20 +17,17 @@ package request
import (
"encoding/json"
"github.com/crusttech/crust/internal/rbac"
"github.com/go-chi/chi"
"github.com/jmoiron/sqlx/types"
"github.com/pkg/errors"
"io"
"mime/multipart"
"net/http"
"strings"
"github.com/go-chi/chi"
"github.com/pkg/errors"
)
var _ = chi.URLParam
var _ = types.JSONText{}
var _ = multipart.FileHeader{}
var _ = rbac.Operation{}
// Organisation list request parameters
type OrganisationList struct {
+3 -6
View File
@@ -17,20 +17,17 @@ package request
import (
"encoding/json"
"github.com/crusttech/crust/internal/rbac"
"github.com/go-chi/chi"
"github.com/jmoiron/sqlx/types"
"github.com/pkg/errors"
"io"
"mime/multipart"
"net/http"
"strings"
"github.com/go-chi/chi"
"github.com/pkg/errors"
)
var _ = chi.URLParam
var _ = types.JSONText{}
var _ = multipart.FileHeader{}
var _ = rbac.Operation{}
// Team list request parameters
type TeamList struct {
+9 -10
View File
@@ -17,20 +17,19 @@ package request
import (
"encoding/json"
"github.com/crusttech/crust/internal/rbac"
"github.com/go-chi/chi"
"github.com/jmoiron/sqlx/types"
"github.com/pkg/errors"
"io"
"mime/multipart"
"net/http"
"strings"
"github.com/go-chi/chi"
"github.com/pkg/errors"
sqlxTypes "github.com/jmoiron/sqlx/types"
)
var _ = chi.URLParam
var _ = types.JSONText{}
var _ = multipart.FileHeader{}
var _ = rbac.Operation{}
// User list request parameters
type UserList struct {
@@ -86,7 +85,7 @@ type UserCreate struct {
Name string
Handle string
Kind string
Meta types.JSONText
Meta sqlxTypes.JSONText
SatosaID string
OrganisationID uint64 `json:",string"`
}
@@ -148,7 +147,7 @@ func (u *UserCreate) Fill(r *http.Request) (err error) {
}
if val, ok := post["meta"]; ok {
if u.Meta, err = parseJSONText(val); err != nil {
if u.Meta, err = parseJSONTextWithErr(val); err != nil {
return err
}
}
@@ -175,7 +174,7 @@ type UserEdit struct {
Name string
Handle string
Kind string
Meta types.JSONText
Meta sqlxTypes.JSONText
SatosaID string
OrganisationID uint64 `json:",string"`
}
@@ -238,7 +237,7 @@ func (u *UserEdit) Fill(r *http.Request) (err error) {
}
if val, ok := post["meta"]; ok {
if u.Meta, err = parseJSONText(val); err != nil {
if u.Meta, err = parseJSONTextWithErr(val); err != nil {
return err
}
}
+1 -1
View File
@@ -11,7 +11,7 @@ import (
var truthy = regexp.MustCompile("^\\s*(t(rue)?|y(es)?|1)\\s*$")
func parseJSONText(s string) (types.JSONText, error) {
func parseJSONTextWithErr(s string) (types.JSONText, error) {
result := &types.JSONText{}
err := errors.Wrap(result.Scan(s), "error when parsing JSONText")
return *result, err