3
0

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:
Tit Petric
2018-11-05 12:04:04 +01:00
parent 67c1a47b16
commit fdf24b3e2c
86 changed files with 2063 additions and 1370 deletions
-10
View File
@@ -1,10 +0,0 @@
[
{
"title": "Authentication",
"package": "auth",
"path": "/auth",
"entrypoint": "auth",
"authentication": [],
"apis": []
}
]
-68
View File
@@ -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"
}
]
}
}
]
}
-16
View File
@@ -1,16 +0,0 @@
package service
import (
"sync"
)
var (
o sync.Once
DefaultUser UserService
)
func Init() {
o.Do(func() {
DefaultUser = User()
})
}
+4 -4
View File
@@ -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
View File
@@ -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))
+36
View File
@@ -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";
}
+30
View File
@@ -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";
}
}
+36
View File
@@ -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
View File
@@ -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
View File
@@ -1,4 +1,4 @@
package crm
package service
import (
"github.com/pkg/errors"
+1 -1
View File
@@ -1,4 +1,4 @@
package crm
package service
import (
"fmt"
+1 -1
View File
@@ -1,4 +1,4 @@
package crm
package service
import (
"fmt"
+3 -3
View File
@@ -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
View File
@@ -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
View File
File diff suppressed because it is too large Load Diff
+1 -1
View File
@@ -1,4 +1,4 @@
package sam
package service
import (
"github.com/pkg/errors"
-3
View File
@@ -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)
})
}
-35
View File
@@ -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
View File
@@ -1,4 +1,4 @@
package sam
package service
import (
"fmt"
+3 -3
View File
@@ -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())
}
+3 -4
View File
@@ -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())
}
+2 -2
View File
@@ -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 }
+5 -5
View File
@@ -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 {
+2 -2
View File
@@ -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
View File
@@ -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
View File
@@ -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 -3
View File
@@ -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
View File
@@ -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
+3 -14
View File
@@ -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
View File
@@ -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
+9 -9
View File
@@ -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
)
+3 -3
View File
@@ -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
}
+2 -2
View File
@@ -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 {
+339
View File
@@ -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"
}
]
}
}
]
}
]
+19
View File
@@ -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 -1
View File
@@ -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"
)
+19
View File
@@ -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")
}
+57
View File
@@ -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
+3 -3
View File
@@ -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
+71
View File
@@ -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()
+10
View File
@@ -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
}
+70
View File
@@ -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
}
+23
View File
@@ -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 (
+3 -3
View File
@@ -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
+30
View File
@@ -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 -1
View File
@@ -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"
)
+20
View File
@@ -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"
)
+4 -4
View File
@@ -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"
+22
View File
@@ -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
}
)
+22
View File
@@ -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
}
)