Refactor for new system service
- upd(all): indent spec.json files on all apps - upd(auth): rename auth app to cmd - upd(sam): move orgs, teams to system - upd(system): extend spec.json for check - upd(codegen): include system/ - upd(codegen): always generate spec files - upd(sam): references from auth to system
This commit is contained in:
@@ -1,10 +0,0 @@
|
||||
[
|
||||
{
|
||||
"title": "Authentication",
|
||||
"package": "auth",
|
||||
"path": "/auth",
|
||||
"entrypoint": "auth",
|
||||
"authentication": [],
|
||||
"apis": []
|
||||
}
|
||||
]
|
||||
@@ -1,68 +0,0 @@
|
||||
{
|
||||
"Title": "Authentication",
|
||||
"Package": "auth",
|
||||
"Interface": "Auth",
|
||||
"Struct": null,
|
||||
"Parameters": null,
|
||||
"Protocol": "",
|
||||
"Authentication": [],
|
||||
"Path": "/auth",
|
||||
"APIs": [
|
||||
{
|
||||
"Name": "login",
|
||||
"Method": "POST",
|
||||
"Title": "User login",
|
||||
"Path": "/login",
|
||||
"Parameters": {
|
||||
"post": [
|
||||
{
|
||||
"name": "username",
|
||||
"required": true,
|
||||
"title": "Username or email",
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"name": "password",
|
||||
"required": true,
|
||||
"title": "Password for user",
|
||||
"type": "string"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"Name": "create",
|
||||
"Method": "POST",
|
||||
"Title": "Create new user",
|
||||
"Path": "/create",
|
||||
"Parameters": {
|
||||
"post": [
|
||||
{
|
||||
"name": "name",
|
||||
"required": true,
|
||||
"title": "Display name",
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"name": "email",
|
||||
"required": true,
|
||||
"title": "Email",
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"name": "username",
|
||||
"required": true,
|
||||
"title": "Username",
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"name": "password",
|
||||
"required": true,
|
||||
"title": "Password",
|
||||
"type": "string"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -1,16 +0,0 @@
|
||||
package service
|
||||
|
||||
import (
|
||||
"sync"
|
||||
)
|
||||
|
||||
var (
|
||||
o sync.Once
|
||||
DefaultUser UserService
|
||||
)
|
||||
|
||||
func Init() {
|
||||
o.Do(func() {
|
||||
DefaultUser = User()
|
||||
})
|
||||
}
|
||||
@@ -4,23 +4,23 @@ import (
|
||||
"log"
|
||||
"os"
|
||||
|
||||
service "github.com/crusttech/crust/auth"
|
||||
service "github.com/crusttech/crust/system"
|
||||
|
||||
"github.com/crusttech/crust/internal/auth"
|
||||
"github.com/crusttech/crust/internal/rbac"
|
||||
)
|
||||
|
||||
func main() {
|
||||
flags("auth", service.Flags, auth.Flags, rbac.Flags)
|
||||
flags("system", service.Flags, auth.Flags, rbac.Flags)
|
||||
|
||||
// log to stdout not stderr
|
||||
log.SetOutput(os.Stdout)
|
||||
log.SetFlags(log.LstdFlags | log.Lshortfile)
|
||||
|
||||
if err := service.Init(); err != nil {
|
||||
log.Fatalf("Error initializing auth: %+v", err)
|
||||
log.Fatalf("Error initializing system: %+v", err)
|
||||
}
|
||||
if err := service.Start(); err != nil {
|
||||
log.Fatalf("Error starting/running auth: %+v", err)
|
||||
log.Fatalf("Error starting/running system: %+v", err)
|
||||
}
|
||||
}
|
||||
+3
-2
@@ -13,7 +13,7 @@ function gofmt {
|
||||
}
|
||||
|
||||
echo "=== go generate ==="
|
||||
cd auth/db && go generate && cd ../..
|
||||
cd system/db && go generate && cd ../..
|
||||
cd crm/db && go generate && cd ../..
|
||||
cd sam/db && go generate && cd ../..
|
||||
|
||||
@@ -21,8 +21,9 @@ _PWD=$PWD
|
||||
SPECS=$(find $PWD -name 'spec.json' | xargs -n1 dirname)
|
||||
for SPEC in $SPECS; do
|
||||
echo "=== spec $SPEC ==="
|
||||
cd $SPEC && rm -rf spec && /usr/bin/env spec && cd $_PWD
|
||||
if [ -x "$(dirname $SPEC)/README.php" ]; then
|
||||
cd $SPEC && rm -rf spec && /usr/bin/env spec && cd .. && ./README.php && cd $_PWD
|
||||
cd $SPEC && cd .. && ./README.php && cd $_PWD
|
||||
fi
|
||||
|
||||
SRC=$(dirname $(dirname $SPEC))
|
||||
|
||||
@@ -0,0 +1,36 @@
|
||||
<?php
|
||||
|
||||
$templates = array(
|
||||
"http_handlers_inline.tpl" => function($name, $api) {
|
||||
return strtolower($name) . ".go";
|
||||
},
|
||||
);
|
||||
|
||||
foreach ($templates as $template => $fn)
|
||||
foreach ($apis as $api) {
|
||||
$name = ucfirst($api['interface']);
|
||||
$filename = $dirname . "/" . $fn($name, $api);
|
||||
|
||||
$tpl->load($template);
|
||||
$tpl->assign($common);
|
||||
$tpl->assign("package", basename(__DIR__));
|
||||
$tpl->assign("name", $name);
|
||||
$tpl->assign("api", $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;
|
||||
}
|
||||
}
|
||||
$tpl->assign("imports", $imports);
|
||||
$tpl->assign("calls", $api['apis']);
|
||||
$contents = str_replace("\n\n}", "\n}", $tpl->get());
|
||||
|
||||
file_put_contents($filename, $contents);
|
||||
echo $filename . "\n";
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
<?php
|
||||
|
||||
foreach ($apis as $api) {
|
||||
$name = ucfirst($api['interface']);
|
||||
$filename = $dirname . "/" . str_replace("..", ".", strtolower($name) . ".go");
|
||||
|
||||
$tpl->load("http_.tpl");
|
||||
$tpl->assign($common);
|
||||
$tpl->assign("package", basename(__DIR__));
|
||||
$tpl->assign("name", $name);
|
||||
$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;
|
||||
}
|
||||
}
|
||||
$tpl->assign("imports", $imports);
|
||||
$tpl->assign("calls", $api['apis']);
|
||||
$contents = str_replace("\n\n}", "\n}", $tpl->get());
|
||||
|
||||
if (!file_exists($filename)) {
|
||||
file_put_contents($filename, $contents);
|
||||
echo $filename . "\n";
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
<?php
|
||||
|
||||
$templates = array(
|
||||
"http_request_inline.tpl" => function($name, $api) {
|
||||
return strtolower($name) . ".go";
|
||||
},
|
||||
);
|
||||
|
||||
foreach ($templates as $template => $fn)
|
||||
foreach ($apis as $api) {
|
||||
$name = ucfirst($api['interface']);
|
||||
$filename = $dirname . "/" . $fn($name, $api);
|
||||
|
||||
$tpl->load($template);
|
||||
$tpl->assign($common);
|
||||
$tpl->assign("package", basename(__DIR__));
|
||||
$tpl->assign("name", $name);
|
||||
$tpl->assign("api", $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;
|
||||
}
|
||||
}
|
||||
$tpl->assign("imports", $imports);
|
||||
$tpl->assign("calls", $api['apis']);
|
||||
$contents = str_replace("\n\n}", "\n}", $tpl->get());
|
||||
|
||||
file_put_contents($filename, $contents);
|
||||
echo $filename . "\n";
|
||||
}
|
||||
+547
-303
@@ -1,304 +1,548 @@
|
||||
[
|
||||
{
|
||||
"title": "Fields",
|
||||
"description": "CRM input field definitions",
|
||||
"package": "crm",
|
||||
"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 }
|
||||
]
|
||||
}
|
||||
],
|
||||
"apis": [
|
||||
{
|
||||
"name": "list",
|
||||
"method": "GET",
|
||||
"path": "/",
|
||||
"title": "List available fields"
|
||||
},
|
||||
{
|
||||
"name": "type",
|
||||
"path": "/{id}",
|
||||
"method": "GET",
|
||||
"title": "Get field details",
|
||||
"parameters": {
|
||||
"path": [
|
||||
{ "type": "string", "name": "id", "required": true, "title": "Type ID" }
|
||||
]
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"title": "Pages",
|
||||
"description": "CRM module pages",
|
||||
"package": "crm",
|
||||
"entrypoint": "page",
|
||||
"path": "/page",
|
||||
"authentication": [],
|
||||
"struct": [],
|
||||
"apis": [
|
||||
{
|
||||
"name": "list",
|
||||
"method": "GET",
|
||||
"path": "/",
|
||||
"title": "List available pages",
|
||||
"parameters": {
|
||||
"get": [
|
||||
{ "type": "uint64", "name": "selfID", "required": false, "title": "Parent page ID" }
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"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": "reorder",
|
||||
"method": "POST",
|
||||
"title": "Reorder pages",
|
||||
"path": "/{selfID}/reorder",
|
||||
"parameters": {
|
||||
"path": [
|
||||
{ "type": "uint64", "name": "selfID", "required": true, "title": "Parent page ID" }
|
||||
],
|
||||
"post": [
|
||||
{ "type": "[]uint64", "name": "pageIDs", "required": true, "title": "Page ID order" }
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"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",
|
||||
"package": "crm",
|
||||
"entrypoint": "module",
|
||||
"path": "/module",
|
||||
"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" }
|
||||
]
|
||||
}
|
||||
],
|
||||
"apis": [
|
||||
{
|
||||
"name": "list",
|
||||
"method": "GET",
|
||||
"title": "List modules",
|
||||
"path": "/",
|
||||
"parameters": {
|
||||
"get": [
|
||||
{ "type": "string", "name": "query", "required": false, "title": "Search query" }
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "create",
|
||||
"method": "POST",
|
||||
"title": "Create module",
|
||||
"path": "/",
|
||||
"parameters": {
|
||||
"post": [
|
||||
{ "type": "string", "name": "name", "required": true, "title": "Module Name" },
|
||||
{ "type": "types.JSONText", "name": "fields", "required": true, "title": "Fields JSON" }
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "read",
|
||||
"method": "GET",
|
||||
"title": "Read module",
|
||||
"path": "/{id}",
|
||||
"parameters": {
|
||||
"path": [
|
||||
{ "type": "uint64", "name": "id", "required": true, "title": "Module ID" }
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "edit",
|
||||
"method": "POST",
|
||||
"title": "Edit module",
|
||||
"path": "/{id}",
|
||||
"parameters": {
|
||||
"path": [
|
||||
{ "type": "uint64", "name": "id", "required": true, "title": "Module ID" }
|
||||
],
|
||||
"post": [
|
||||
{ "type": "string", "name": "name", "required": true, "title": "Module Name" },
|
||||
{ "type": "types.JSONText", "name": "fields", "required": true, "title": "Fields JSON" }
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "delete",
|
||||
"method": "DELETE",
|
||||
"title": "Delete module",
|
||||
"path": "/{id}",
|
||||
"parameters": {
|
||||
"path": [
|
||||
{ "type": "uint64", "name": "id", "required": true, "title": "Module ID" }
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "content/list",
|
||||
"method": "GET",
|
||||
"title": "List/read contents from module section",
|
||||
"path": "/{moduleID}/content",
|
||||
"parameters": {
|
||||
"path": [
|
||||
{ "type": "uint64", "name": "moduleID", "required": true, "title": "Module ID" }
|
||||
],
|
||||
"get": [
|
||||
{ "name": "page", "type": "int", "required": false, "title": "Page number (0 based)" },
|
||||
{ "name": "perPage", "type": "int", "required": false, "title": "Returned items per page (default 50)" }
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "content/create",
|
||||
"method": "POST",
|
||||
"title": "List/read contents from module section",
|
||||
"path": "/{moduleID}/content",
|
||||
"parameters": {
|
||||
"path": [
|
||||
{ "type": "uint64", "name": "moduleID", "required": true, "title": "Module ID" }
|
||||
],
|
||||
"post": [
|
||||
{ "type": "types.JSONText", "name": "fields", "required": true, "title": "Content JSON" }
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "content/read",
|
||||
"method": "GET",
|
||||
"title": "Read contents by ID from module section",
|
||||
"path": "/{moduleID}/content/{id}",
|
||||
"parameters": {
|
||||
"path": [
|
||||
{ "type": "uint64", "name": "moduleID", "required": true, "title": "Module ID" },
|
||||
{ "type": "uint64", "name": "id", "required": true, "title": "Content ID" }
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "content/edit",
|
||||
"method": "POST",
|
||||
"title": "Add/update contents in module section",
|
||||
"path": "/{moduleID}/content/{id}",
|
||||
"parameters": {
|
||||
"path": [
|
||||
{ "type": "uint64", "name": "moduleID", "required": true, "title": "Module ID" },
|
||||
{ "type": "uint64", "name": "id", "required": true, "title": "Content ID" }
|
||||
],
|
||||
"post": [
|
||||
{ "type": "types.JSONText", "name": "fields", "required": true, "title": "Content JSON" }
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "content/delete",
|
||||
"method": "DELETE",
|
||||
"title": "Delete content row from module section",
|
||||
"path": "/{moduleID}/content/{id}",
|
||||
"parameters": {
|
||||
"path": [
|
||||
{ "type": "uint64", "name": "moduleID", "required": true, "title": "Module ID" },
|
||||
{ "type": "uint64", "name": "id", "required": true, "title": "Content ID" }
|
||||
]
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
{
|
||||
"title": "Fields",
|
||||
"description": "CRM input field definitions",
|
||||
"package": "crm",
|
||||
"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
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"apis": [
|
||||
{
|
||||
"name": "list",
|
||||
"method": "GET",
|
||||
"path": "/",
|
||||
"title": "List available fields"
|
||||
},
|
||||
{
|
||||
"name": "type",
|
||||
"path": "/{id}",
|
||||
"method": "GET",
|
||||
"title": "Get field details",
|
||||
"parameters": {
|
||||
"path": [
|
||||
{
|
||||
"type": "string",
|
||||
"name": "id",
|
||||
"required": true,
|
||||
"title": "Type ID"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"title": "Pages",
|
||||
"description": "CRM module pages",
|
||||
"package": "crm",
|
||||
"entrypoint": "page",
|
||||
"path": "/page",
|
||||
"authentication": [],
|
||||
"struct": [],
|
||||
"apis": [
|
||||
{
|
||||
"name": "list",
|
||||
"method": "GET",
|
||||
"path": "/",
|
||||
"title": "List available pages",
|
||||
"parameters": {
|
||||
"get": [
|
||||
{
|
||||
"type": "uint64",
|
||||
"name": "selfID",
|
||||
"required": false,
|
||||
"title": "Parent page ID"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"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": "reorder",
|
||||
"method": "POST",
|
||||
"title": "Reorder pages",
|
||||
"path": "/{selfID}/reorder",
|
||||
"parameters": {
|
||||
"path": [
|
||||
{
|
||||
"type": "uint64",
|
||||
"name": "selfID",
|
||||
"required": true,
|
||||
"title": "Parent page ID"
|
||||
}
|
||||
],
|
||||
"post": [
|
||||
{
|
||||
"type": "[]uint64",
|
||||
"name": "pageIDs",
|
||||
"required": true,
|
||||
"title": "Page ID order"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"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",
|
||||
"package": "crm",
|
||||
"entrypoint": "module",
|
||||
"path": "/module",
|
||||
"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"
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"apis": [
|
||||
{
|
||||
"name": "list",
|
||||
"method": "GET",
|
||||
"title": "List modules",
|
||||
"path": "/",
|
||||
"parameters": {
|
||||
"get": [
|
||||
{
|
||||
"type": "string",
|
||||
"name": "query",
|
||||
"required": false,
|
||||
"title": "Search query"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "create",
|
||||
"method": "POST",
|
||||
"title": "Create module",
|
||||
"path": "/",
|
||||
"parameters": {
|
||||
"post": [
|
||||
{
|
||||
"type": "string",
|
||||
"name": "name",
|
||||
"required": true,
|
||||
"title": "Module Name"
|
||||
},
|
||||
{
|
||||
"type": "types.JSONText",
|
||||
"name": "fields",
|
||||
"required": true,
|
||||
"title": "Fields JSON"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "read",
|
||||
"method": "GET",
|
||||
"title": "Read module",
|
||||
"path": "/{id}",
|
||||
"parameters": {
|
||||
"path": [
|
||||
{
|
||||
"type": "uint64",
|
||||
"name": "id",
|
||||
"required": true,
|
||||
"title": "Module ID"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "edit",
|
||||
"method": "POST",
|
||||
"title": "Edit module",
|
||||
"path": "/{id}",
|
||||
"parameters": {
|
||||
"path": [
|
||||
{
|
||||
"type": "uint64",
|
||||
"name": "id",
|
||||
"required": true,
|
||||
"title": "Module ID"
|
||||
}
|
||||
],
|
||||
"post": [
|
||||
{
|
||||
"type": "string",
|
||||
"name": "name",
|
||||
"required": true,
|
||||
"title": "Module Name"
|
||||
},
|
||||
{
|
||||
"type": "types.JSONText",
|
||||
"name": "fields",
|
||||
"required": true,
|
||||
"title": "Fields JSON"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "delete",
|
||||
"method": "DELETE",
|
||||
"title": "Delete module",
|
||||
"path": "/{id}",
|
||||
"parameters": {
|
||||
"path": [
|
||||
{
|
||||
"type": "uint64",
|
||||
"name": "id",
|
||||
"required": true,
|
||||
"title": "Module ID"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "content/list",
|
||||
"method": "GET",
|
||||
"title": "List/read contents from module section",
|
||||
"path": "/{moduleID}/content",
|
||||
"parameters": {
|
||||
"path": [
|
||||
{
|
||||
"type": "uint64",
|
||||
"name": "moduleID",
|
||||
"required": true,
|
||||
"title": "Module ID"
|
||||
}
|
||||
],
|
||||
"get": [
|
||||
{
|
||||
"name": "page",
|
||||
"type": "int",
|
||||
"required": false,
|
||||
"title": "Page number (0 based)"
|
||||
},
|
||||
{
|
||||
"name": "perPage",
|
||||
"type": "int",
|
||||
"required": false,
|
||||
"title": "Returned items per page (default 50)"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "content/create",
|
||||
"method": "POST",
|
||||
"title": "List/read contents from module section",
|
||||
"path": "/{moduleID}/content",
|
||||
"parameters": {
|
||||
"path": [
|
||||
{
|
||||
"type": "uint64",
|
||||
"name": "moduleID",
|
||||
"required": true,
|
||||
"title": "Module ID"
|
||||
}
|
||||
],
|
||||
"post": [
|
||||
{
|
||||
"type": "types.JSONText",
|
||||
"name": "fields",
|
||||
"required": true,
|
||||
"title": "Content JSON"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "content/read",
|
||||
"method": "GET",
|
||||
"title": "Read contents by ID from module section",
|
||||
"path": "/{moduleID}/content/{id}",
|
||||
"parameters": {
|
||||
"path": [
|
||||
{
|
||||
"type": "uint64",
|
||||
"name": "moduleID",
|
||||
"required": true,
|
||||
"title": "Module ID"
|
||||
},
|
||||
{
|
||||
"type": "uint64",
|
||||
"name": "id",
|
||||
"required": true,
|
||||
"title": "Content ID"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "content/edit",
|
||||
"method": "POST",
|
||||
"title": "Add/update contents in module section",
|
||||
"path": "/{moduleID}/content/{id}",
|
||||
"parameters": {
|
||||
"path": [
|
||||
{
|
||||
"type": "uint64",
|
||||
"name": "moduleID",
|
||||
"required": true,
|
||||
"title": "Module ID"
|
||||
},
|
||||
{
|
||||
"type": "uint64",
|
||||
"name": "id",
|
||||
"required": true,
|
||||
"title": "Content ID"
|
||||
}
|
||||
],
|
||||
"post": [
|
||||
{
|
||||
"type": "types.JSONText",
|
||||
"name": "fields",
|
||||
"required": true,
|
||||
"title": "Content JSON"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "content/delete",
|
||||
"method": "DELETE",
|
||||
"title": "Delete content row from module section",
|
||||
"path": "/{moduleID}/content/{id}",
|
||||
"parameters": {
|
||||
"path": [
|
||||
{
|
||||
"type": "uint64",
|
||||
"name": "moduleID",
|
||||
"required": true,
|
||||
"title": "Module ID"
|
||||
},
|
||||
{
|
||||
"type": "uint64",
|
||||
"name": "id",
|
||||
"required": true,
|
||||
"title": "Content ID"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
package crm
|
||||
package service
|
||||
|
||||
import (
|
||||
"github.com/pkg/errors"
|
||||
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
package crm
|
||||
package service
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
package crm
|
||||
package service
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
@@ -5,10 +5,10 @@ import (
|
||||
"fmt"
|
||||
"net/url"
|
||||
|
||||
authTypes "github.com/crusttech/crust/auth/types"
|
||||
"github.com/crusttech/crust/internal/auth"
|
||||
"github.com/crusttech/crust/internal/payload/outgoing"
|
||||
samTypes "github.com/crusttech/crust/sam/types"
|
||||
systemTypes "github.com/crusttech/crust/system/types"
|
||||
)
|
||||
|
||||
const (
|
||||
@@ -180,7 +180,7 @@ func ChannelPart(channelID, userID uint64) *outgoing.ChannelPart {
|
||||
}
|
||||
}
|
||||
|
||||
func User(user *authTypes.User) *outgoing.User {
|
||||
func User(user *systemTypes.User) *outgoing.User {
|
||||
if user == nil {
|
||||
return nil
|
||||
}
|
||||
@@ -194,7 +194,7 @@ func User(user *authTypes.User) *outgoing.User {
|
||||
}
|
||||
}
|
||||
|
||||
func Users(users []*authTypes.User) *outgoing.UserSet {
|
||||
func Users(users []*systemTypes.User) *outgoing.UserSet {
|
||||
uu := make([]*outgoing.User, len(users))
|
||||
for k, u := range users {
|
||||
uu[k] = User(u)
|
||||
|
||||
+1
-236
@@ -1,219 +1,3 @@
|
||||
# Organisations
|
||||
|
||||
Organisations represent a top-level grouping entity. There may be many organisations defined in a single deployment.
|
||||
|
||||
## List organisations
|
||||
|
||||
#### Method
|
||||
|
||||
| URI | Protocol | Method | Authentication |
|
||||
| --- | -------- | ------ | -------------- |
|
||||
| `/organisations/` | HTTP/S | GET | Client ID, Session ID |
|
||||
|
||||
#### Request parameters
|
||||
|
||||
| Parameter | Type | Method | Description | Default | Required? |
|
||||
| --------- | ---- | ------ | ----------- | ------- | --------- |
|
||||
| query | string | GET | Search query | N/A | NO |
|
||||
|
||||
## Create organisation
|
||||
|
||||
#### Method
|
||||
|
||||
| URI | Protocol | Method | Authentication |
|
||||
| --- | -------- | ------ | -------------- |
|
||||
| `/organisations/` | HTTP/S | POST | Client ID, Session ID |
|
||||
|
||||
#### Request parameters
|
||||
|
||||
| Parameter | Type | Method | Description | Default | Required? |
|
||||
| --------- | ---- | ------ | ----------- | ------- | --------- |
|
||||
| name | string | POST | Organisation Name | N/A | YES |
|
||||
|
||||
## Update organisation details
|
||||
|
||||
#### Method
|
||||
|
||||
| URI | Protocol | Method | Authentication |
|
||||
| --- | -------- | ------ | -------------- |
|
||||
| `/organisations/{id}` | HTTP/S | PUT | Client ID, Session ID |
|
||||
|
||||
#### Request parameters
|
||||
|
||||
| Parameter | Type | Method | Description | Default | Required? |
|
||||
| --------- | ---- | ------ | ----------- | ------- | --------- |
|
||||
| id | uint64 | PATH | Organisation ID | N/A | NO |
|
||||
| name | string | POST | Organisation Name | N/A | YES |
|
||||
|
||||
## Remove organisation
|
||||
|
||||
#### Method
|
||||
|
||||
| URI | Protocol | Method | Authentication |
|
||||
| --- | -------- | ------ | -------------- |
|
||||
| `/organisations/{id}` | HTTP/S | DELETE | Client ID, Session ID |
|
||||
|
||||
#### Request parameters
|
||||
|
||||
| Parameter | Type | Method | Description | Default | Required? |
|
||||
| --------- | ---- | ------ | ----------- | ------- | --------- |
|
||||
| id | uint64 | PATH | Organisation ID | N/A | YES |
|
||||
|
||||
## Read organisation details
|
||||
|
||||
#### Method
|
||||
|
||||
| URI | Protocol | Method | Authentication |
|
||||
| --- | -------- | ------ | -------------- |
|
||||
| `/organisations/{id}` | HTTP/S | GET | Client ID, Session ID |
|
||||
|
||||
#### Request parameters
|
||||
|
||||
| Parameter | Type | Method | Description | Default | Required? |
|
||||
| --------- | ---- | ------ | ----------- | ------- | --------- |
|
||||
| id | uint64 | GET | Organisation ID | N/A | YES |
|
||||
|
||||
## Archive organisation
|
||||
|
||||
#### Method
|
||||
|
||||
| URI | Protocol | Method | Authentication |
|
||||
| --- | -------- | ------ | -------------- |
|
||||
| `/organisations/{id}/archive` | HTTP/S | POST | Client ID, Session ID |
|
||||
|
||||
#### Request parameters
|
||||
|
||||
| Parameter | Type | Method | Description | Default | Required? |
|
||||
| --------- | ---- | ------ | ----------- | ------- | --------- |
|
||||
| id | uint64 | PATH | Organisation ID | N/A | YES |
|
||||
|
||||
|
||||
|
||||
|
||||
# Teams
|
||||
|
||||
An organisation may have many teams. Teams may have many channels available. Access to channels may be shared between teams.
|
||||
|
||||
## List teams
|
||||
|
||||
#### Method
|
||||
|
||||
| URI | Protocol | Method | Authentication |
|
||||
| --- | -------- | ------ | -------------- |
|
||||
| `/teams/` | HTTP/S | GET | Client ID, Session ID |
|
||||
|
||||
#### Request parameters
|
||||
|
||||
| Parameter | Type | Method | Description | Default | Required? |
|
||||
| --------- | ---- | ------ | ----------- | ------- | --------- |
|
||||
| query | string | GET | Search query | N/A | NO |
|
||||
|
||||
## Update team details
|
||||
|
||||
#### Method
|
||||
|
||||
| URI | Protocol | Method | Authentication |
|
||||
| --- | -------- | ------ | -------------- |
|
||||
| `/teams/` | HTTP/S | POST | Client ID, Session ID |
|
||||
|
||||
#### Request parameters
|
||||
|
||||
| Parameter | Type | Method | Description | Default | Required? |
|
||||
| --------- | ---- | ------ | ----------- | ------- | --------- |
|
||||
| name | string | POST | Name of Team | N/A | YES |
|
||||
| members | []uint64 | POST | Team member IDs | N/A | NO |
|
||||
|
||||
## Update team details
|
||||
|
||||
#### Method
|
||||
|
||||
| URI | Protocol | Method | Authentication |
|
||||
| --- | -------- | ------ | -------------- |
|
||||
| `/teams/{teamID}` | HTTP/S | PUT | Client ID, Session ID |
|
||||
|
||||
#### Request parameters
|
||||
|
||||
| Parameter | Type | Method | Description | Default | Required? |
|
||||
| --------- | ---- | ------ | ----------- | ------- | --------- |
|
||||
| teamID | uint64 | PATH | Team ID | N/A | YES |
|
||||
| name | string | POST | Name of Team | N/A | NO |
|
||||
| members | []uint64 | POST | Team member IDs | N/A | NO |
|
||||
|
||||
## Read team details and memberships
|
||||
|
||||
#### Method
|
||||
|
||||
| URI | Protocol | Method | Authentication |
|
||||
| --- | -------- | ------ | -------------- |
|
||||
| `/teams/{teamID}` | HTTP/S | GET | Client ID, Session ID |
|
||||
|
||||
#### Request parameters
|
||||
|
||||
| Parameter | Type | Method | Description | Default | Required? |
|
||||
| --------- | ---- | ------ | ----------- | ------- | --------- |
|
||||
| teamID | uint64 | PATH | Team ID | N/A | YES |
|
||||
|
||||
## Remove team
|
||||
|
||||
#### Method
|
||||
|
||||
| URI | Protocol | Method | Authentication |
|
||||
| --- | -------- | ------ | -------------- |
|
||||
| `/teams/{teamID}` | HTTP/S | DELETE | Client ID, Session ID |
|
||||
|
||||
#### Request parameters
|
||||
|
||||
| Parameter | Type | Method | Description | Default | Required? |
|
||||
| --------- | ---- | ------ | ----------- | ------- | --------- |
|
||||
| teamID | uint64 | PATH | Team ID | N/A | YES |
|
||||
|
||||
## Archive team
|
||||
|
||||
#### Method
|
||||
|
||||
| URI | Protocol | Method | Authentication |
|
||||
| --- | -------- | ------ | -------------- |
|
||||
| `/teams/{teamID}/archive` | HTTP/S | POST | Client ID, Session ID |
|
||||
|
||||
#### Request parameters
|
||||
|
||||
| Parameter | Type | Method | Description | Default | Required? |
|
||||
| --------- | ---- | ------ | ----------- | ------- | --------- |
|
||||
| teamID | uint64 | PATH | Team ID | N/A | YES |
|
||||
|
||||
## Move team to different organisation
|
||||
|
||||
#### Method
|
||||
|
||||
| URI | Protocol | Method | Authentication |
|
||||
| --- | -------- | ------ | -------------- |
|
||||
| `/teams/{teamID}/move` | HTTP/S | POST | Client ID, Session ID |
|
||||
|
||||
#### Request parameters
|
||||
|
||||
| Parameter | Type | Method | Description | Default | Required? |
|
||||
| --------- | ---- | ------ | ----------- | ------- | --------- |
|
||||
| teamID | uint64 | PATH | Team ID | N/A | YES |
|
||||
| organisationID | uint64 | POST | Team ID | N/A | YES |
|
||||
|
||||
## Merge one team into another
|
||||
|
||||
#### Method
|
||||
|
||||
| URI | Protocol | Method | Authentication |
|
||||
| --- | -------- | ------ | -------------- |
|
||||
| `/teams/{teamID}/merge` | HTTP/S | POST | Client ID, Session ID |
|
||||
|
||||
#### Request parameters
|
||||
|
||||
| Parameter | Type | Method | Description | Default | Required? |
|
||||
| --------- | ---- | ------ | ----------- | ------- | --------- |
|
||||
| teamID | uint64 | PATH | Source Team ID | N/A | YES |
|
||||
| destination | uint64 | POST | Destination Team ID | N/A | YES |
|
||||
|
||||
|
||||
|
||||
|
||||
# Channels
|
||||
|
||||
A channel is a representation of a sequence of messages. It has meta data like channel subject. Channels may be public, private or group.
|
||||
@@ -620,23 +404,4 @@ The following event types may be sent with a message event:
|
||||
| inChannel | uint64 | GET | Search only in one channel | N/A | NO |
|
||||
| fromUser | uint64 | GET | Search only from one user | N/A | NO |
|
||||
| firstID | uint64 | GET | Paging; return newer messages only (higher id) | N/A | NO |
|
||||
| lastID | uint64 | GET | Paging; return older messages only (lower id) | N/A | NO |
|
||||
|
||||
|
||||
|
||||
|
||||
# Users
|
||||
|
||||
## Search users (Directory)
|
||||
|
||||
#### Method
|
||||
|
||||
| URI | Protocol | Method | Authentication |
|
||||
| --- | -------- | ------ | -------------- |
|
||||
| `/users/search` | HTTP/S | GET | Client ID, Session ID |
|
||||
|
||||
#### Request parameters
|
||||
|
||||
| Parameter | Type | Method | Description | Default | Required? |
|
||||
| --------- | ---- | ------ | ----------- | ------- | --------- |
|
||||
| query | string | GET | Search query to match against users | N/A | NO |
|
||||
| lastID | uint64 | GET | Paging; return older messages only (lower id) | N/A | NO |
|
||||
+593
-556
File diff suppressed because it is too large
Load Diff
+1
-1
@@ -1,4 +1,4 @@
|
||||
package sam
|
||||
package service
|
||||
|
||||
import (
|
||||
"github.com/pkg/errors"
|
||||
|
||||
@@ -20,9 +20,6 @@ func MountRoutes() func(chi.Router) {
|
||||
|
||||
handlers.NewChannel(Channel{}.New()).MountRoutes(r)
|
||||
handlers.NewMessage(Message{}.New()).MountRoutes(r)
|
||||
handlers.NewOrganisation(Organisation{}.New()).MountRoutes(r)
|
||||
handlers.NewTeam(Team{}.New()).MountRoutes(r)
|
||||
handlers.NewUser(User{}.New()).MountRoutes(r)
|
||||
handlers.NewSearch(Search{}.New()).MountRoutes(r)
|
||||
})
|
||||
}
|
||||
|
||||
@@ -1,35 +0,0 @@
|
||||
package rest
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
|
||||
authService "github.com/crusttech/crust/auth/service"
|
||||
authTypes "github.com/crusttech/crust/auth/types"
|
||||
"github.com/crusttech/crust/sam/rest/request"
|
||||
"github.com/crusttech/crust/sam/service"
|
||||
)
|
||||
|
||||
var _ = errors.Wrap
|
||||
|
||||
type (
|
||||
User struct {
|
||||
svc struct {
|
||||
user authService.UserService
|
||||
message service.MessageService
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
func (User) New() *User {
|
||||
ctrl := &User{}
|
||||
ctrl.svc.user = authService.DefaultUser
|
||||
ctrl.svc.message = service.DefaultMessage
|
||||
return ctrl
|
||||
}
|
||||
|
||||
// Searches the users table in the database to find users by matching (by-prefix) their.Username
|
||||
func (ctrl *User) Search(ctx context.Context, r *request.UserSearch) (interface{}, error) {
|
||||
return ctrl.svc.user.With(ctx).Find(&authTypes.UserFilter{Query: r.Query})
|
||||
}
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
package sam
|
||||
package service
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
@@ -16,10 +16,10 @@ import (
|
||||
"github.com/pkg/errors"
|
||||
"github.com/titpetric/factory"
|
||||
|
||||
authService "github.com/crusttech/crust/auth/service"
|
||||
"github.com/crusttech/crust/internal/store"
|
||||
"github.com/crusttech/crust/sam/repository"
|
||||
"github.com/crusttech/crust/sam/types"
|
||||
systemService "github.com/crusttech/crust/system/service"
|
||||
)
|
||||
|
||||
const (
|
||||
@@ -33,7 +33,7 @@ type (
|
||||
ctx context.Context
|
||||
|
||||
store store.Store
|
||||
usr authService.UserService
|
||||
usr systemService.UserService
|
||||
evl EventService
|
||||
|
||||
attachment repository.AttachmentRepository
|
||||
@@ -53,7 +53,7 @@ type (
|
||||
func Attachment(store store.Store) AttachmentService {
|
||||
return (&attachment{
|
||||
store: store,
|
||||
usr: authService.DefaultUser,
|
||||
usr: systemService.DefaultUser,
|
||||
evl: DefaultEvent,
|
||||
}).With(context.Background())
|
||||
}
|
||||
|
||||
@@ -8,10 +8,9 @@ import (
|
||||
"github.com/pkg/errors"
|
||||
|
||||
"github.com/crusttech/crust/internal/auth"
|
||||
|
||||
authService "github.com/crusttech/crust/auth/service"
|
||||
"github.com/crusttech/crust/sam/repository"
|
||||
"github.com/crusttech/crust/sam/types"
|
||||
systemService "github.com/crusttech/crust/system/service"
|
||||
)
|
||||
|
||||
type (
|
||||
@@ -19,7 +18,7 @@ type (
|
||||
db db
|
||||
ctx context.Context
|
||||
|
||||
usr authService.UserService
|
||||
usr systemService.UserService
|
||||
evl EventService
|
||||
|
||||
channel repository.ChannelRepository
|
||||
@@ -65,7 +64,7 @@ const (
|
||||
|
||||
func Channel() ChannelService {
|
||||
return (&channel{
|
||||
usr: authService.DefaultUser,
|
||||
usr: systemService.DefaultUser,
|
||||
evl: DefaultEvent,
|
||||
}).With(context.Background())
|
||||
}
|
||||
|
||||
@@ -5,9 +5,9 @@ import (
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
authTypes "github.com/crusttech/crust/auth/types"
|
||||
"github.com/crusttech/crust/internal/auth"
|
||||
"github.com/crusttech/crust/sam/types"
|
||||
systemTypes "github.com/crusttech/crust/system/types"
|
||||
)
|
||||
|
||||
// func TestChannelCreation(t *testing.T) {
|
||||
@@ -33,7 +33,7 @@ func TestChannelNameTooShort(t *testing.T) {
|
||||
// defer mockCtrl.Finish()
|
||||
|
||||
ctx := context.TODO()
|
||||
auth.SetIdentityToContext(ctx, &authTypes.User{})
|
||||
auth.SetIdentityToContext(ctx, &systemTypes.User{})
|
||||
|
||||
svc := channel{db: &mockDB{}, ctx: ctx}
|
||||
e := func(out *types.Channel, err error) error { return err }
|
||||
|
||||
@@ -6,10 +6,10 @@ import (
|
||||
|
||||
"github.com/pkg/errors"
|
||||
|
||||
authService "github.com/crusttech/crust/auth/service"
|
||||
authTypes "github.com/crusttech/crust/auth/types"
|
||||
"github.com/crusttech/crust/sam/repository"
|
||||
"github.com/crusttech/crust/sam/types"
|
||||
systemService "github.com/crusttech/crust/system/service"
|
||||
systemTypes "github.com/crusttech/crust/system/types"
|
||||
)
|
||||
|
||||
type (
|
||||
@@ -24,7 +24,7 @@ type (
|
||||
message repository.MessageRepository
|
||||
mflag repository.MessageFlagRepository
|
||||
|
||||
usr authService.UserService
|
||||
usr systemService.UserService
|
||||
evl EventService
|
||||
}
|
||||
|
||||
@@ -56,7 +56,7 @@ const (
|
||||
|
||||
func Message() MessageService {
|
||||
return &message{
|
||||
usr: authService.DefaultUser,
|
||||
usr: systemService.DefaultUser,
|
||||
evl: DefaultEvent,
|
||||
}
|
||||
}
|
||||
@@ -402,7 +402,7 @@ func (svc *message) preload(mm types.MessageSet) (err error) {
|
||||
|
||||
// Preload for all messages
|
||||
func (svc *message) preloadUsers(mm types.MessageSet) (err error) {
|
||||
var uu authTypes.UserSet
|
||||
var uu systemTypes.UserSet
|
||||
|
||||
for _, msg := range mm {
|
||||
if msg.User != nil || msg.UserID == 0 {
|
||||
|
||||
@@ -5,9 +5,9 @@ import (
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
authTypes "github.com/crusttech/crust/auth/types"
|
||||
"github.com/crusttech/crust/internal/auth"
|
||||
"github.com/crusttech/crust/sam/types"
|
||||
systemTypes "github.com/crusttech/crust/system/types"
|
||||
)
|
||||
|
||||
// func TestChannelCreation(t *testing.T) {
|
||||
@@ -33,7 +33,7 @@ func TesMessageLength(t *testing.T) {
|
||||
// defer mockCtrl.Finish()
|
||||
|
||||
ctx := context.TODO()
|
||||
auth.SetIdentityToContext(ctx, &authTypes.User{})
|
||||
auth.SetIdentityToContext(ctx, &systemTypes.User{})
|
||||
|
||||
svc := message{db: &mockDB{}, ctx: ctx}
|
||||
e := func(out *types.Message, err error) error { return err }
|
||||
|
||||
+6
-10
@@ -15,14 +15,12 @@ type (
|
||||
)
|
||||
|
||||
var (
|
||||
o sync.Once
|
||||
DefaultAttachment AttachmentService
|
||||
DefaultChannel ChannelService
|
||||
DefaultMessage MessageService
|
||||
DefaultOrganisation OrganisationService
|
||||
DefaultPubSub *pubSub
|
||||
DefaultTeam TeamService
|
||||
DefaultEvent EventService
|
||||
o sync.Once
|
||||
DefaultAttachment AttachmentService
|
||||
DefaultChannel ChannelService
|
||||
DefaultMessage MessageService
|
||||
DefaultPubSub *pubSub
|
||||
DefaultEvent EventService
|
||||
)
|
||||
|
||||
func Init() {
|
||||
@@ -36,9 +34,7 @@ func Init() {
|
||||
DefaultAttachment = Attachment(fs)
|
||||
DefaultMessage = Message()
|
||||
DefaultChannel = Channel()
|
||||
DefaultOrganisation = Organisation()
|
||||
DefaultPubSub = PubSub()
|
||||
DefaultTeam = Team()
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
+3
-3
@@ -1,4 +1,4 @@
|
||||
package sam
|
||||
package service
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
@@ -14,11 +14,11 @@ import (
|
||||
"github.com/titpetric/factory"
|
||||
"github.com/titpetric/factory/resputil"
|
||||
|
||||
authService "github.com/crusttech/crust/auth/service"
|
||||
migrate "github.com/crusttech/crust/sam/db"
|
||||
"github.com/crusttech/crust/sam/rest"
|
||||
samService "github.com/crusttech/crust/sam/service"
|
||||
"github.com/crusttech/crust/sam/websocket"
|
||||
systemService "github.com/crusttech/crust/system/service"
|
||||
|
||||
"github.com/crusttech/crust/internal/auth"
|
||||
"github.com/crusttech/crust/internal/metrics"
|
||||
@@ -60,7 +60,7 @@ func Init() error {
|
||||
},
|
||||
})
|
||||
|
||||
authService.Init()
|
||||
systemService.Init()
|
||||
samService.Init()
|
||||
|
||||
return nil
|
||||
|
||||
@@ -3,15 +3,15 @@ package types
|
||||
import (
|
||||
"time"
|
||||
|
||||
authTypes "github.com/crusttech/crust/auth/types"
|
||||
systemTypes "github.com/crusttech/crust/system/types"
|
||||
)
|
||||
|
||||
type (
|
||||
ChannelMember struct {
|
||||
ChannelID uint64 `db:"rel_channel"`
|
||||
|
||||
UserID uint64 `db:"rel_user"`
|
||||
User *authTypes.User `db:"-"`
|
||||
UserID uint64 `db:"rel_user"`
|
||||
User *systemTypes.User `db:"-"`
|
||||
|
||||
Type ChannelMembershipType `db:"type"`
|
||||
|
||||
|
||||
+14
-14
@@ -4,24 +4,24 @@ import (
|
||||
"database/sql/driver"
|
||||
"time"
|
||||
|
||||
authTypes "github.com/crusttech/crust/auth/types"
|
||||
systemTypes "github.com/crusttech/crust/system/types"
|
||||
)
|
||||
|
||||
type (
|
||||
Message struct {
|
||||
ID uint64 `json:"id" db:"id"`
|
||||
Type MessageType `json:"type" db:"type"`
|
||||
Message string `json:"message" db:"message"`
|
||||
UserID uint64 `json:"userId" db:"rel_user"`
|
||||
ChannelID uint64 `json:"channelId" db:"rel_channel"`
|
||||
ReplyTo uint64 `json:"replyTo" db:"reply_to"`
|
||||
Replies uint `json:"replies" db:"replies"`
|
||||
CreatedAt time.Time `json:"createdAt,omitempty" db:"created_at"`
|
||||
UpdatedAt *time.Time `json:"updatedAt,omitempty" db:"updated_at"`
|
||||
DeletedAt *time.Time `json:"deletedAt,omitempty" db:"deleted_at"`
|
||||
Attachment *Attachment `json:"attachment,omitempty"`
|
||||
User *authTypes.User `json:"user,omitempty"`
|
||||
Flags MessageFlagSet `json:"flags,omitempty"`
|
||||
ID uint64 `json:"id" db:"id"`
|
||||
Type MessageType `json:"type" db:"type"`
|
||||
Message string `json:"message" db:"message"`
|
||||
UserID uint64 `json:"userId" db:"rel_user"`
|
||||
ChannelID uint64 `json:"channelId" db:"rel_channel"`
|
||||
ReplyTo uint64 `json:"replyTo" db:"reply_to"`
|
||||
Replies uint `json:"replies" db:"replies"`
|
||||
CreatedAt time.Time `json:"createdAt,omitempty" db:"created_at"`
|
||||
UpdatedAt *time.Time `json:"updatedAt,omitempty" db:"updated_at"`
|
||||
DeletedAt *time.Time `json:"deletedAt,omitempty" db:"deleted_at"`
|
||||
Attachment *Attachment `json:"attachment,omitempty"`
|
||||
User *systemTypes.User `json:"user,omitempty"`
|
||||
Flags MessageFlagSet `json:"flags,omitempty"`
|
||||
}
|
||||
|
||||
MessageSet []*Message
|
||||
|
||||
@@ -2,24 +2,13 @@ package types
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/crusttech/crust/system/types"
|
||||
)
|
||||
|
||||
type (
|
||||
// Organisations - Organisations represent a top-level grouping entity. There may be many organisations defined in a single deployment.
|
||||
Organisation struct {
|
||||
ID uint64 `json:"id" db:"id"`
|
||||
FQN string `json:"fqn" db:"fqn"`
|
||||
Name string `json:"name" db:"name"`
|
||||
CreatedAt time.Time `json:"createdAt,omitempty" db:"created_at"`
|
||||
UpdatedAt *time.Time `json:"updatedAt,omitempty" db:"updated_at"`
|
||||
ArchivedAt *time.Time `json:"archivedAt,omitempty" db:"archived_at"`
|
||||
DeletedAt *time.Time `json:"deletedAt,omitempty" db:"deleted_at"`
|
||||
}
|
||||
|
||||
OrganisationFilter struct {
|
||||
Query string
|
||||
}
|
||||
Organisation types.Organisation
|
||||
)
|
||||
|
||||
// Scope returns permissions group that for this type
|
||||
|
||||
+3
-15
@@ -2,24 +2,12 @@ package types
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/crusttech/crust/system/types"
|
||||
)
|
||||
|
||||
type (
|
||||
// Teams - An organisation may have many teams. Teams may have many channels available. Access to channels may be shared between teams.
|
||||
Team struct {
|
||||
ID uint64 `json:"id" db:"id"`
|
||||
Name string `json:"name" db:"name"`
|
||||
Handle string `json:"handle" db:"handle"`
|
||||
CreatedAt time.Time `json:"createdAt,omitempty" db:"created_at"`
|
||||
UpdatedAt *time.Time `json:"updatedAt,omitempty" db:"updated_at"`
|
||||
ArchivedAt *time.Time `json:"archivedAt,omitempty" db:"archived_at"`
|
||||
DeletedAt *time.Time `json:"deletedAt,omitempty" db:"deleted_at"`
|
||||
}
|
||||
|
||||
TeamFilter struct {
|
||||
Query string
|
||||
}
|
||||
Team types.Team
|
||||
)
|
||||
|
||||
// Scope returns permissions group that for this type
|
||||
|
||||
@@ -6,17 +6,17 @@ import (
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
authTypes "github.com/crusttech/crust/auth/types"
|
||||
"github.com/crusttech/crust/internal/auth"
|
||||
"github.com/crusttech/crust/internal/payload"
|
||||
"github.com/crusttech/crust/internal/payload/outgoing"
|
||||
"github.com/crusttech/crust/sam/types"
|
||||
"github.com/gorilla/websocket"
|
||||
"github.com/pkg/errors"
|
||||
|
||||
authService "github.com/crusttech/crust/auth/service"
|
||||
"github.com/crusttech/crust/internal/auth"
|
||||
"github.com/crusttech/crust/internal/payload"
|
||||
"github.com/crusttech/crust/internal/payload/outgoing"
|
||||
"github.com/crusttech/crust/sam/repository"
|
||||
samService "github.com/crusttech/crust/sam/service"
|
||||
"github.com/crusttech/crust/sam/types"
|
||||
systemService "github.com/crusttech/crust/system/service"
|
||||
systemTypes "github.com/crusttech/crust/system/types"
|
||||
)
|
||||
|
||||
type (
|
||||
@@ -39,7 +39,7 @@ type (
|
||||
user auth.Identifiable
|
||||
|
||||
svc struct {
|
||||
user authService.UserService
|
||||
user systemService.UserService
|
||||
ch samService.ChannelService
|
||||
msg samService.MessageService
|
||||
}
|
||||
@@ -56,7 +56,7 @@ func (Session) New(ctx context.Context, config *repository.Flags, conn *websocke
|
||||
stop: make(chan []byte, 1),
|
||||
}
|
||||
|
||||
s.svc.user = authService.DefaultUser
|
||||
s.svc.user = systemService.DefaultUser
|
||||
s.svc.ch = samService.DefaultChannel
|
||||
s.svc.msg = samService.DefaultMessage
|
||||
|
||||
@@ -69,7 +69,7 @@ func (sess *Session) Context() context.Context {
|
||||
|
||||
func (sess *Session) connected() (err error) {
|
||||
var (
|
||||
uu authTypes.UserSet
|
||||
uu systemTypes.UserSet
|
||||
cc types.ChannelSet
|
||||
)
|
||||
|
||||
|
||||
@@ -8,15 +8,15 @@ import (
|
||||
"github.com/pkg/errors"
|
||||
"github.com/titpetric/factory/resputil"
|
||||
|
||||
authService "github.com/crusttech/crust/auth/service"
|
||||
"github.com/crusttech/crust/internal/auth"
|
||||
"github.com/crusttech/crust/sam/repository"
|
||||
systemService "github.com/crusttech/crust/system/service"
|
||||
)
|
||||
|
||||
type (
|
||||
Websocket struct {
|
||||
svc struct {
|
||||
user authService.UserService
|
||||
user systemService.UserService
|
||||
}
|
||||
config *repository.Flags
|
||||
}
|
||||
@@ -26,7 +26,7 @@ func (Websocket) New(config *repository.Flags) *Websocket {
|
||||
ws := &Websocket{
|
||||
config: config,
|
||||
}
|
||||
ws.svc.user = authService.DefaultUser
|
||||
ws.svc.user = systemService.DefaultUser
|
||||
return ws
|
||||
}
|
||||
|
||||
|
||||
@@ -9,7 +9,7 @@ import (
|
||||
"sort"
|
||||
"strings"
|
||||
|
||||
_ "github.com/crusttech/crust/auth/db/mysql"
|
||||
_ "github.com/crusttech/crust/system/db/mysql"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/rakyll/statik/fs"
|
||||
"github.com/titpetric/factory"
|
||||
@@ -50,7 +50,7 @@ func Migrate(db *factory.DB) error {
|
||||
|
||||
migrate := func(filename string, useLog bool) error {
|
||||
status := migration{
|
||||
Project: "auth",
|
||||
Project: "system",
|
||||
Filename: filename,
|
||||
}
|
||||
if useLog {
|
||||
@@ -0,0 +1,339 @@
|
||||
[
|
||||
{
|
||||
"title": "Authentication",
|
||||
"package": "auth",
|
||||
"path": "/auth",
|
||||
"entrypoint": "auth",
|
||||
"authentication": [],
|
||||
"apis": [
|
||||
{
|
||||
"name": "check",
|
||||
"method": "GET",
|
||||
"title": "Check JWT token",
|
||||
"path": "/check",
|
||||
"parameters": []
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"title": "Organisations",
|
||||
"description": "Organisations represent a top-level grouping entity. There may be many organisations defined in a single deployment.",
|
||||
"package": "sam",
|
||||
"path": "/organisations",
|
||||
"entrypoint": "organisation",
|
||||
"authentication": [
|
||||
"Client ID",
|
||||
"Session ID"
|
||||
],
|
||||
"apis": [
|
||||
{
|
||||
"name": "list",
|
||||
"method": "GET",
|
||||
"title": "List organisations",
|
||||
"path": "/",
|
||||
"parameters": {
|
||||
"get": [
|
||||
{
|
||||
"type": "string",
|
||||
"name": "query",
|
||||
"required": false,
|
||||
"title": "Search query"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "create",
|
||||
"method": "POST",
|
||||
"title": "Create organisation",
|
||||
"path": "/",
|
||||
"parameters": {
|
||||
"post": [
|
||||
{
|
||||
"type": "string",
|
||||
"name": "name",
|
||||
"required": true,
|
||||
"title": "Organisation Name"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "edit",
|
||||
"method": "PUT",
|
||||
"title": "Update organisation details",
|
||||
"path": "/{id}",
|
||||
"parameters": {
|
||||
"path": [
|
||||
{
|
||||
"type": "uint64",
|
||||
"name": "id",
|
||||
"required": false,
|
||||
"title": "Organisation ID"
|
||||
}
|
||||
],
|
||||
"post": [
|
||||
{
|
||||
"type": "string",
|
||||
"name": "name",
|
||||
"required": true,
|
||||
"title": "Organisation Name"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "remove",
|
||||
"method": "DELETE",
|
||||
"title": "Remove organisation",
|
||||
"path": "/{id}",
|
||||
"parameters": {
|
||||
"path": [
|
||||
{
|
||||
"type": "uint64",
|
||||
"name": "id",
|
||||
"required": true,
|
||||
"title": "Organisation ID"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "read",
|
||||
"method": "GET",
|
||||
"title": "Read organisation details",
|
||||
"path": "/{id}",
|
||||
"parameters": {
|
||||
"get": [
|
||||
{
|
||||
"type": "uint64",
|
||||
"name": "id",
|
||||
"required": true,
|
||||
"title": "Organisation ID"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "archive",
|
||||
"method": "POST",
|
||||
"title": "Archive organisation",
|
||||
"path": "/{id}/archive",
|
||||
"parameters": {
|
||||
"path": [
|
||||
{
|
||||
"type": "uint64",
|
||||
"name": "id",
|
||||
"required": true,
|
||||
"title": "Organisation ID"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"title": "Teams",
|
||||
"description": "An organisation may have many teams. Teams may have many channels available. Access to channels may be shared between teams.",
|
||||
"package": "sam",
|
||||
"path": "/teams",
|
||||
"entrypoint": "team",
|
||||
"authentication": [
|
||||
"Client ID",
|
||||
"Session ID"
|
||||
],
|
||||
"apis": [
|
||||
{
|
||||
"name": "list",
|
||||
"method": "GET",
|
||||
"title": "List teams",
|
||||
"path": "/",
|
||||
"parameters": {
|
||||
"get": [
|
||||
{
|
||||
"type": "string",
|
||||
"name": "query",
|
||||
"required": false,
|
||||
"title": "Search query"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "create",
|
||||
"method": "POST",
|
||||
"title": "Update team details",
|
||||
"path": "/",
|
||||
"parameters": {
|
||||
"post": [
|
||||
{
|
||||
"type": "string",
|
||||
"name": "name",
|
||||
"required": true,
|
||||
"title": "Name of Team"
|
||||
},
|
||||
{
|
||||
"type": "[]uint64",
|
||||
"name": "members",
|
||||
"required": false,
|
||||
"title": "Team member IDs"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "edit",
|
||||
"method": "PUT",
|
||||
"title": "Update team details",
|
||||
"path": "/{teamID}",
|
||||
"parameters": {
|
||||
"path": [
|
||||
{
|
||||
"type": "uint64",
|
||||
"name": "teamID",
|
||||
"required": true,
|
||||
"title": "Team ID"
|
||||
}
|
||||
],
|
||||
"post": [
|
||||
{
|
||||
"type": "string",
|
||||
"name": "name",
|
||||
"required": false,
|
||||
"title": "Name of Team"
|
||||
},
|
||||
{
|
||||
"type": "[]uint64",
|
||||
"name": "members",
|
||||
"required": false,
|
||||
"title": "Team member IDs"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "read",
|
||||
"method": "GET",
|
||||
"title": "Read team details and memberships",
|
||||
"path": "/{teamID}",
|
||||
"parameters": {
|
||||
"path": [
|
||||
{
|
||||
"type": "uint64",
|
||||
"name": "teamID",
|
||||
"required": true,
|
||||
"title": "Team ID"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "remove",
|
||||
"method": "DELETE",
|
||||
"title": "Remove team",
|
||||
"path": "/{teamID}",
|
||||
"parameters": {
|
||||
"path": [
|
||||
{
|
||||
"type": "uint64",
|
||||
"name": "teamID",
|
||||
"required": true,
|
||||
"title": "Team ID"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "archive",
|
||||
"method": "POST",
|
||||
"title": "Archive team",
|
||||
"path": "/{teamID}/archive",
|
||||
"parameters": {
|
||||
"path": [
|
||||
{
|
||||
"type": "uint64",
|
||||
"name": "teamID",
|
||||
"required": true,
|
||||
"title": "Team ID"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "move",
|
||||
"method": "POST",
|
||||
"title": "Move team to different organisation",
|
||||
"path": "/{teamID}/move",
|
||||
"parameters": {
|
||||
"path": [
|
||||
{
|
||||
"type": "uint64",
|
||||
"name": "teamID",
|
||||
"required": true,
|
||||
"title": "Team ID"
|
||||
}
|
||||
],
|
||||
"post": [
|
||||
{
|
||||
"type": "uint64",
|
||||
"name": "organisationID",
|
||||
"required": true,
|
||||
"title": "Team ID"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "merge",
|
||||
"method": "POST",
|
||||
"title": "Merge one team into another",
|
||||
"path": "/{teamID}/merge",
|
||||
"parameters": {
|
||||
"path": [
|
||||
{
|
||||
"type": "uint64",
|
||||
"name": "teamID",
|
||||
"required": true,
|
||||
"title": "Source Team ID"
|
||||
}
|
||||
],
|
||||
"post": [
|
||||
{
|
||||
"type": "uint64",
|
||||
"name": "destination",
|
||||
"required": true,
|
||||
"title": "Destination Team ID"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"title": "Users",
|
||||
"package": "sam",
|
||||
"path": "/users",
|
||||
"entrypoint": "user",
|
||||
"authentication": [
|
||||
"Client ID",
|
||||
"Session ID"
|
||||
],
|
||||
"apis": [
|
||||
{
|
||||
"name": "search",
|
||||
"method": "GET",
|
||||
"title": "Search users (Directory)",
|
||||
"parameters": {
|
||||
"get": [
|
||||
{
|
||||
"type": "string",
|
||||
"name": "query",
|
||||
"required": false,
|
||||
"title": "Search query to match against users"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
@@ -0,0 +1,19 @@
|
||||
{
|
||||
"Title": "Authentication",
|
||||
"Package": "auth",
|
||||
"Interface": "Auth",
|
||||
"Struct": null,
|
||||
"Parameters": null,
|
||||
"Protocol": "",
|
||||
"Authentication": [],
|
||||
"Path": "/auth",
|
||||
"APIs": [
|
||||
{
|
||||
"Name": "check",
|
||||
"Method": "GET",
|
||||
"Title": "Check JWT token",
|
||||
"Path": "/check",
|
||||
"Parameters": null
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
package auth
|
||||
package service
|
||||
|
||||
import (
|
||||
"github.com/pkg/errors"
|
||||
@@ -6,7 +6,7 @@ import (
|
||||
|
||||
"github.com/titpetric/factory"
|
||||
|
||||
"github.com/crusttech/crust/sam/types"
|
||||
"github.com/crusttech/crust/system/types"
|
||||
)
|
||||
|
||||
type (
|
||||
@@ -6,7 +6,7 @@ import (
|
||||
|
||||
"github.com/titpetric/factory"
|
||||
|
||||
"github.com/crusttech/crust/sam/types"
|
||||
"github.com/crusttech/crust/system/types"
|
||||
)
|
||||
|
||||
type (
|
||||
@@ -4,7 +4,7 @@ import (
|
||||
"context"
|
||||
"time"
|
||||
|
||||
"github.com/crusttech/crust/auth/types"
|
||||
"github.com/crusttech/crust/system/types"
|
||||
"github.com/titpetric/factory"
|
||||
)
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
package rest
|
||||
|
||||
import (
|
||||
"context"
|
||||
"github.com/crusttech/crust/system/rest/request"
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
var _ = errors.Wrap
|
||||
|
||||
type Auth struct{}
|
||||
|
||||
func (Auth) New() *Auth {
|
||||
return &Auth{}
|
||||
}
|
||||
|
||||
func (ctrl *Auth) Check(ctx context.Context, r *request.AuthCheck) (interface{}, error) {
|
||||
return nil, errors.New("Not implemented: Auth.check")
|
||||
}
|
||||
@@ -0,0 +1,57 @@
|
||||
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 `auth.go`, `auth.util.go` or `auth_test.go` to
|
||||
implement your API calls, helper functions and tests. The file `auth.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/system/rest/request"
|
||||
)
|
||||
|
||||
// Internal API interface
|
||||
type AuthAPI interface {
|
||||
Check(context.Context, *request.AuthCheck) (interface{}, error)
|
||||
}
|
||||
|
||||
// HTTP API interface
|
||||
type Auth struct {
|
||||
Check func(http.ResponseWriter, *http.Request)
|
||||
}
|
||||
|
||||
func NewAuth(ah AuthAPI) *Auth {
|
||||
return &Auth{
|
||||
Check: func(w http.ResponseWriter, r *http.Request) {
|
||||
defer r.Body.Close()
|
||||
params := request.NewAuthCheck()
|
||||
resputil.JSON(w, params.Fill(r), func() (interface{}, error) {
|
||||
return ah.Check(r.Context(), params)
|
||||
})
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func (ah *Auth) MountRoutes(r chi.Router, middlewares ...func(http.Handler) http.Handler) {
|
||||
r.Group(func(r chi.Router) {
|
||||
r.Use(middlewares...)
|
||||
r.Route("/auth", func(r chi.Router) {
|
||||
r.Get("/check", ah.Check)
|
||||
})
|
||||
})
|
||||
}
|
||||
@@ -22,7 +22,7 @@ import (
|
||||
|
||||
"github.com/titpetric/factory/resputil"
|
||||
|
||||
"github.com/crusttech/crust/sam/rest/request"
|
||||
"github.com/crusttech/crust/system/rest/request"
|
||||
)
|
||||
|
||||
// Internal API interface
|
||||
@@ -22,7 +22,7 @@ import (
|
||||
|
||||
"github.com/titpetric/factory/resputil"
|
||||
|
||||
"github.com/crusttech/crust/sam/rest/request"
|
||||
"github.com/crusttech/crust/system/rest/request"
|
||||
)
|
||||
|
||||
// Internal API interface
|
||||
@@ -22,7 +22,7 @@ import (
|
||||
|
||||
"github.com/titpetric/factory/resputil"
|
||||
|
||||
"github.com/crusttech/crust/sam/rest/request"
|
||||
"github.com/crusttech/crust/system/rest/request"
|
||||
)
|
||||
|
||||
// Internal API interface
|
||||
@@ -7,11 +7,11 @@ import (
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
"github.com/crusttech/crust/auth/repository"
|
||||
"github.com/crusttech/crust/auth/service"
|
||||
"github.com/crusttech/crust/auth/types"
|
||||
"github.com/crusttech/crust/internal/auth"
|
||||
"github.com/crusttech/crust/internal/config"
|
||||
"github.com/crusttech/crust/system/repository"
|
||||
"github.com/crusttech/crust/system/service"
|
||||
"github.com/crusttech/crust/system/types"
|
||||
"github.com/crusttech/go-oidc"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/titpetric/factory/resputil"
|
||||
@@ -2,10 +2,12 @@ package rest
|
||||
|
||||
import (
|
||||
"context"
|
||||
"github.com/crusttech/crust/sam/rest/request"
|
||||
"github.com/crusttech/crust/sam/service"
|
||||
"github.com/crusttech/crust/sam/types"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
|
||||
"github.com/crusttech/crust/system/rest/request"
|
||||
"github.com/crusttech/crust/system/service"
|
||||
"github.com/crusttech/crust/system/types"
|
||||
)
|
||||
|
||||
var _ = errors.Wrap
|
||||
@@ -0,0 +1,71 @@
|
||||
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 `auth.go`, `auth.util.go` or `auth_test.go` to
|
||||
implement your API calls, helper functions and tests. The file `auth.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{}
|
||||
|
||||
// Auth check request parameters
|
||||
type AuthCheck struct {
|
||||
}
|
||||
|
||||
func NewAuthCheck() *AuthCheck {
|
||||
return &AuthCheck{}
|
||||
}
|
||||
|
||||
func (a *AuthCheck) Fill(r *http.Request) (err error) {
|
||||
if strings.ToLower(r.Header.Get("content-type")) == "application/json" {
|
||||
err = json.NewDecoder(r.Body).Decode(a)
|
||||
|
||||
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 = NewAuthCheck()
|
||||
@@ -0,0 +1,10 @@
|
||||
package request
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
)
|
||||
|
||||
// RequestFiller is an interface for typed request parameters
|
||||
type RequestFiller interface {
|
||||
Fill(r *http.Request) error
|
||||
}
|
||||
@@ -0,0 +1,70 @@
|
||||
package request
|
||||
|
||||
import (
|
||||
"regexp"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/jmoiron/sqlx/types"
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
var truthy = regexp.MustCompile("^\\s*(t(rue)?|y(es)?|1)\\s*$")
|
||||
|
||||
func parseJSONText(s string) (types.JSONText, error) {
|
||||
result := &types.JSONText{}
|
||||
err := errors.Wrap(result.Scan(s), "error when parsing JSONText")
|
||||
return *result, err
|
||||
}
|
||||
|
||||
// parseInt parses a string to int
|
||||
func parseInt(s string) int {
|
||||
if s == "" {
|
||||
return 0
|
||||
}
|
||||
i, _ := strconv.Atoi(s)
|
||||
return i
|
||||
}
|
||||
|
||||
// parseInt64 parses a string to int64
|
||||
func parseInt64(s string) int64 {
|
||||
if s == "" {
|
||||
return 0
|
||||
}
|
||||
i, _ := strconv.ParseInt(s, 10, 64)
|
||||
return i
|
||||
}
|
||||
|
||||
// parseUInt64 parses a string to uint64
|
||||
func parseUInt64(s string) uint64 {
|
||||
if s == "" {
|
||||
return 0
|
||||
}
|
||||
i, _ := strconv.ParseUint(s, 10, 64)
|
||||
return i
|
||||
}
|
||||
|
||||
func parseUInt64A(values []string) []uint64 {
|
||||
var result []uint64
|
||||
if values != nil && len(values) > 0 {
|
||||
for _, val := range values {
|
||||
result = append(result, parseUInt64(val))
|
||||
}
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
// parseUInt64 parses a string to uint64
|
||||
func parseBool(s string) bool {
|
||||
return truthy.MatchString(strings.ToLower(s))
|
||||
}
|
||||
|
||||
// is checks if string s is contained in matches
|
||||
func is(s string, matches ...string) bool {
|
||||
for _, v := range matches {
|
||||
if s == v {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
package request
|
||||
|
||||
import (
|
||||
"testing"
|
||||
)
|
||||
|
||||
func Test_parseBool(t *testing.T) {
|
||||
truthies := []string{"y", "yes", "TRUE", "true", "t", "1", " T "}
|
||||
falsies := []string{"a", "FALSE", "tr", "11111", " FALSE ", "0"}
|
||||
|
||||
for _, truth := range truthies {
|
||||
if !parseBool(truth) {
|
||||
t.Errorf("Must parse '%s' as boolean value TRUE", truth)
|
||||
}
|
||||
}
|
||||
|
||||
for _, falsie := range falsies {
|
||||
if parseBool(falsie) {
|
||||
t.Errorf("Must not parse '%s' as boolean value TRUE", falsie)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -5,16 +5,15 @@ import (
|
||||
"log"
|
||||
"net/http"
|
||||
|
||||
"github.com/crusttech/crust/auth/repository"
|
||||
"github.com/crusttech/crust/internal/auth"
|
||||
"github.com/crusttech/crust/internal/payload"
|
||||
"github.com/crusttech/crust/internal/payload/outgoing"
|
||||
|
||||
"github.com/go-chi/chi"
|
||||
"github.com/titpetric/factory/resputil"
|
||||
|
||||
"github.com/crusttech/crust/auth/service"
|
||||
"github.com/crusttech/crust/internal/auth"
|
||||
"github.com/crusttech/crust/internal/config"
|
||||
"github.com/crusttech/crust/internal/payload"
|
||||
"github.com/crusttech/crust/internal/payload/outgoing"
|
||||
"github.com/crusttech/crust/system/repository"
|
||||
"github.com/crusttech/crust/system/service"
|
||||
)
|
||||
|
||||
type (
|
||||
@@ -5,9 +5,9 @@ import (
|
||||
|
||||
"github.com/pkg/errors"
|
||||
|
||||
"github.com/crusttech/crust/sam/rest/request"
|
||||
"github.com/crusttech/crust/sam/service"
|
||||
"github.com/crusttech/crust/sam/types"
|
||||
"github.com/crusttech/crust/system/rest/request"
|
||||
"github.com/crusttech/crust/system/service"
|
||||
"github.com/crusttech/crust/system/types"
|
||||
)
|
||||
|
||||
var _ = errors.Wrap
|
||||
@@ -0,0 +1,30 @@
|
||||
package rest
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
|
||||
"github.com/crusttech/crust/system/rest/request"
|
||||
"github.com/crusttech/crust/system/service"
|
||||
"github.com/crusttech/crust/system/types"
|
||||
)
|
||||
|
||||
var _ = errors.Wrap
|
||||
|
||||
type (
|
||||
User struct {
|
||||
user service.UserService
|
||||
}
|
||||
)
|
||||
|
||||
func (User) New() *User {
|
||||
ctrl := &User{}
|
||||
ctrl.user = service.DefaultUser
|
||||
return ctrl
|
||||
}
|
||||
|
||||
// Searches the users table in the database to find users by matching (by-prefix) their.Username
|
||||
func (ctrl *User) Search(ctx context.Context, r *request.UserSearch) (interface{}, error) {
|
||||
return ctrl.user.With(ctx).Find(&types.UserFilter{Query: r.Query})
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
package auth
|
||||
package service
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
@@ -5,8 +5,8 @@ import (
|
||||
|
||||
"github.com/titpetric/factory"
|
||||
|
||||
"github.com/crusttech/crust/sam/repository"
|
||||
"github.com/crusttech/crust/sam/types"
|
||||
"github.com/crusttech/crust/system/repository"
|
||||
"github.com/crusttech/crust/system/types"
|
||||
)
|
||||
|
||||
type (
|
||||
@@ -1,12 +1,12 @@
|
||||
// Code generated by MockGen. DO NOT EDIT.
|
||||
// Source: sam/service/organisation.go
|
||||
// Source: system/service/organisation.go
|
||||
|
||||
// Package service is a generated GoMock package.
|
||||
package service
|
||||
|
||||
import (
|
||||
context "context"
|
||||
types "github.com/crusttech/crust/sam/types"
|
||||
types "github.com/crusttech/crust/system/types"
|
||||
gomock "github.com/golang/mock/gomock"
|
||||
reflect "reflect"
|
||||
)
|
||||
@@ -0,0 +1,20 @@
|
||||
package service
|
||||
|
||||
import (
|
||||
"sync"
|
||||
)
|
||||
|
||||
var (
|
||||
o sync.Once
|
||||
DefaultUser UserService
|
||||
DefaultTeam TeamService
|
||||
DefaultOrganisation OrganisationService
|
||||
)
|
||||
|
||||
func Init() {
|
||||
o.Do(func() {
|
||||
DefaultUser = User()
|
||||
DefaultTeam = Team()
|
||||
DefaultOrganisation = Organisation()
|
||||
})
|
||||
}
|
||||
@@ -5,8 +5,8 @@ import (
|
||||
|
||||
"github.com/titpetric/factory"
|
||||
|
||||
"github.com/crusttech/crust/sam/repository"
|
||||
"github.com/crusttech/crust/sam/types"
|
||||
"github.com/crusttech/crust/system/repository"
|
||||
"github.com/crusttech/crust/system/types"
|
||||
)
|
||||
|
||||
type (
|
||||
@@ -1,12 +1,12 @@
|
||||
// Code generated by MockGen. DO NOT EDIT.
|
||||
// Source: sam/service/team.go
|
||||
// Source: system/service/team.go
|
||||
|
||||
// Package service is a generated GoMock package.
|
||||
package service
|
||||
|
||||
import (
|
||||
context "context"
|
||||
types "github.com/crusttech/crust/sam/types"
|
||||
types "github.com/crusttech/crust/system/types"
|
||||
gomock "github.com/golang/mock/gomock"
|
||||
reflect "reflect"
|
||||
)
|
||||
@@ -3,10 +3,11 @@ package service
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/crusttech/crust/auth/repository"
|
||||
"github.com/crusttech/crust/auth/types"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/titpetric/factory"
|
||||
|
||||
"github.com/crusttech/crust/system/repository"
|
||||
"github.com/crusttech/crust/system/types"
|
||||
)
|
||||
|
||||
const (
|
||||
@@ -1,12 +1,12 @@
|
||||
// Code generated by MockGen. DO NOT EDIT.
|
||||
// Source: auth/service/user.go
|
||||
// Source: system/service/user.go
|
||||
|
||||
// Package service is a generated GoMock package.
|
||||
package service
|
||||
|
||||
import (
|
||||
context "context"
|
||||
types "github.com/crusttech/crust/auth/types"
|
||||
types "github.com/crusttech/crust/system/types"
|
||||
gomock "github.com/golang/mock/gomock"
|
||||
reflect "reflect"
|
||||
)
|
||||
@@ -4,7 +4,7 @@ import (
|
||||
"context"
|
||||
"testing"
|
||||
|
||||
"github.com/crusttech/crust/sam/types"
|
||||
"github.com/crusttech/crust/system/types"
|
||||
"github.com/golang/mock/gomock"
|
||||
"github.com/titpetric/factory"
|
||||
)
|
||||
@@ -1,4 +1,4 @@
|
||||
package auth
|
||||
package service
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
@@ -13,9 +13,9 @@ import (
|
||||
"github.com/titpetric/factory"
|
||||
"github.com/titpetric/factory/resputil"
|
||||
|
||||
migrate "github.com/crusttech/crust/auth/db"
|
||||
"github.com/crusttech/crust/auth/rest"
|
||||
"github.com/crusttech/crust/auth/service"
|
||||
migrate "github.com/crusttech/crust/system/db"
|
||||
"github.com/crusttech/crust/system/rest"
|
||||
"github.com/crusttech/crust/system/service"
|
||||
|
||||
"github.com/crusttech/crust/internal/auth"
|
||||
"github.com/crusttech/crust/internal/metrics"
|
||||
@@ -0,0 +1,22 @@
|
||||
package types
|
||||
|
||||
import (
|
||||
"time"
|
||||
)
|
||||
|
||||
type (
|
||||
// Organisations - Organisations represent a top-level grouping entity. There may be many organisations defined in a single deployment.
|
||||
Organisation struct {
|
||||
ID uint64 `json:"id" db:"id"`
|
||||
FQN string `json:"fqn" db:"fqn"`
|
||||
Name string `json:"name" db:"name"`
|
||||
CreatedAt time.Time `json:"createdAt,omitempty" db:"created_at"`
|
||||
UpdatedAt *time.Time `json:"updatedAt,omitempty" db:"updated_at"`
|
||||
ArchivedAt *time.Time `json:"archivedAt,omitempty" db:"archived_at"`
|
||||
DeletedAt *time.Time `json:"deletedAt,omitempty" db:"deleted_at"`
|
||||
}
|
||||
|
||||
OrganisationFilter struct {
|
||||
Query string
|
||||
}
|
||||
)
|
||||
@@ -0,0 +1,22 @@
|
||||
package types
|
||||
|
||||
import (
|
||||
"time"
|
||||
)
|
||||
|
||||
type (
|
||||
// Teams - An organisation may have many teams. Teams may have many channels available. Access to channels may be shared between teams.
|
||||
Team struct {
|
||||
ID uint64 `json:"id" db:"id"`
|
||||
Name string `json:"name" db:"name"`
|
||||
Handle string `json:"handle" db:"handle"`
|
||||
CreatedAt time.Time `json:"createdAt,omitempty" db:"created_at"`
|
||||
UpdatedAt *time.Time `json:"updatedAt,omitempty" db:"updated_at"`
|
||||
ArchivedAt *time.Time `json:"archivedAt,omitempty" db:"archived_at"`
|
||||
DeletedAt *time.Time `json:"deletedAt,omitempty" db:"deleted_at"`
|
||||
}
|
||||
|
||||
TeamFilter struct {
|
||||
Query string
|
||||
}
|
||||
)
|
||||
Reference in New Issue
Block a user