Add settings service to compose
This commit is contained in:
parent
8aee952aa9
commit
08860a90e4
@ -1854,5 +1854,91 @@
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"title": "Settings",
|
||||
"path": "/settings",
|
||||
"entrypoint": "settings",
|
||||
"authentication": [],
|
||||
"struct": [{
|
||||
"imports": [
|
||||
"sqlxTypes github.com/jmoiron/sqlx/types"
|
||||
]
|
||||
}],
|
||||
"apis": [{
|
||||
"name": "list",
|
||||
"method": "GET",
|
||||
"title": "List settings",
|
||||
"path": "/",
|
||||
"parameters": {
|
||||
"get": [
|
||||
{
|
||||
"name": "prefix",
|
||||
"type": "string",
|
||||
"title": "Key prefix"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "update",
|
||||
"method": "PATCH",
|
||||
"title": "Update settings",
|
||||
"path": "/",
|
||||
"parameters": {
|
||||
"post": [{
|
||||
"name": "values",
|
||||
"type": "sqlxTypes.JSONText",
|
||||
"title": "Array of new settings: `[{ name: ..., value: ... }]`. Omit value to remove setting",
|
||||
"required": true
|
||||
}]
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "get",
|
||||
"method": "GET",
|
||||
"title": "Get a value for a key",
|
||||
"path": "/{key}",
|
||||
"parameters": {
|
||||
"path": [{
|
||||
"name": "key",
|
||||
"type": "string",
|
||||
"title": "Setting key",
|
||||
"required": true
|
||||
}],
|
||||
"get": [{
|
||||
"name": "ownerID",
|
||||
"type": "uint64",
|
||||
"title": "Owner ID"
|
||||
}]
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "set",
|
||||
"method": "PUT",
|
||||
"title": "Set a value for a key",
|
||||
"path": "/{key}",
|
||||
"parameters": {
|
||||
"path": [{
|
||||
"name": "key",
|
||||
"type": "string",
|
||||
"title": "Setting key",
|
||||
"required": true
|
||||
}],
|
||||
"post": [{
|
||||
"name": "ownerID",
|
||||
"type": "uint64",
|
||||
"title": "Owner"
|
||||
},
|
||||
{
|
||||
"name": "value",
|
||||
"type": "sqlxTypes.JSONText",
|
||||
"required": true,
|
||||
"title": "Setting value"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
|
||||
100
api/compose/spec/settings.json
Normal file
100
api/compose/spec/settings.json
Normal file
@ -0,0 +1,100 @@
|
||||
{
|
||||
"Title": "Settings",
|
||||
"Interface": "Settings",
|
||||
"Struct": [
|
||||
{
|
||||
"imports": [
|
||||
"sqlxTypes github.com/jmoiron/sqlx/types"
|
||||
]
|
||||
}
|
||||
],
|
||||
"Parameters": null,
|
||||
"Protocol": "",
|
||||
"Authentication": [],
|
||||
"Path": "/settings",
|
||||
"APIs": [
|
||||
{
|
||||
"Name": "list",
|
||||
"Method": "GET",
|
||||
"Title": "List settings",
|
||||
"Path": "/",
|
||||
"Parameters": {
|
||||
"get": [
|
||||
{
|
||||
"name": "prefix",
|
||||
"title": "Key prefix",
|
||||
"type": "string"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"Name": "update",
|
||||
"Method": "PATCH",
|
||||
"Title": "Update settings",
|
||||
"Path": "/",
|
||||
"Parameters": {
|
||||
"post": [
|
||||
{
|
||||
"name": "values",
|
||||
"required": true,
|
||||
"title": "Array of new settings: `[{ name: ..., value: ... }]`. Omit value to remove setting",
|
||||
"type": "sqlxTypes.JSONText"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"Name": "get",
|
||||
"Method": "GET",
|
||||
"Title": "Get a value for a key",
|
||||
"Path": "/{key}",
|
||||
"Parameters": {
|
||||
"get": [
|
||||
{
|
||||
"name": "ownerID",
|
||||
"title": "Owner ID",
|
||||
"type": "uint64"
|
||||
}
|
||||
],
|
||||
"path": [
|
||||
{
|
||||
"name": "key",
|
||||
"required": true,
|
||||
"title": "Setting key",
|
||||
"type": "string"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"Name": "set",
|
||||
"Method": "PUT",
|
||||
"Title": "Set a value for a key",
|
||||
"Path": "/{key}",
|
||||
"Parameters": {
|
||||
"path": [
|
||||
{
|
||||
"name": "key",
|
||||
"required": true,
|
||||
"title": "Setting key",
|
||||
"type": "string"
|
||||
}
|
||||
],
|
||||
"post": [
|
||||
{
|
||||
"name": "ownerID",
|
||||
"title": "Owner",
|
||||
"type": "uint64"
|
||||
},
|
||||
{
|
||||
"name": "value",
|
||||
"required": true,
|
||||
"title": "Setting value",
|
||||
"type": "sqlxTypes.JSONText"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
File diff suppressed because one or more lines are too long
10
compose/db/schema/mysql/20191008152820.settings.up.sql
Normal file
10
compose/db/schema/mysql/20191008152820.settings.up.sql
Normal file
@ -0,0 +1,10 @@
|
||||
CREATE TABLE IF NOT EXISTS `compose_settings` (
|
||||
rel_owner BIGINT UNSIGNED NOT NULL DEFAULT 0 COMMENT 'Value owner, 0 for global settings',
|
||||
name VARCHAR(200) NOT NULL COMMENT 'Unique set of setting keys',
|
||||
value JSON COMMENT 'Setting value',
|
||||
|
||||
updated_at DATETIME NOT NULL DEFAULT NOW() COMMENT 'When was the value updated',
|
||||
updated_by BIGINT UNSIGNED NOT NULL DEFAULT 0 COMMENT 'Who created/updated the value',
|
||||
|
||||
PRIMARY KEY (name, rel_owner)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
|
||||
139
compose/rest/handlers/settings.go
Normal file
139
compose/rest/handlers/settings.go
Normal file
@ -0,0 +1,139 @@
|
||||
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 `settings.go`, `settings.util.go` or `settings_test.go` to
|
||||
implement your API calls, helper functions and tests. The file `settings.go`
|
||||
is only generated the first time, and will not be overwritten if it exists.
|
||||
*/
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"net/http"
|
||||
|
||||
"github.com/go-chi/chi"
|
||||
"github.com/titpetric/factory/resputil"
|
||||
|
||||
"github.com/cortezaproject/corteza-server/compose/rest/request"
|
||||
"github.com/cortezaproject/corteza-server/pkg/logger"
|
||||
)
|
||||
|
||||
// Internal API interface
|
||||
type SettingsAPI interface {
|
||||
List(context.Context, *request.SettingsList) (interface{}, error)
|
||||
Update(context.Context, *request.SettingsUpdate) (interface{}, error)
|
||||
Get(context.Context, *request.SettingsGet) (interface{}, error)
|
||||
Set(context.Context, *request.SettingsSet) (interface{}, error)
|
||||
}
|
||||
|
||||
// HTTP API interface
|
||||
type Settings struct {
|
||||
List func(http.ResponseWriter, *http.Request)
|
||||
Update func(http.ResponseWriter, *http.Request)
|
||||
Get func(http.ResponseWriter, *http.Request)
|
||||
Set func(http.ResponseWriter, *http.Request)
|
||||
}
|
||||
|
||||
func NewSettings(h SettingsAPI) *Settings {
|
||||
return &Settings{
|
||||
List: func(w http.ResponseWriter, r *http.Request) {
|
||||
defer r.Body.Close()
|
||||
params := request.NewSettingsList()
|
||||
if err := params.Fill(r); err != nil {
|
||||
logger.LogParamError("Settings.List", r, err)
|
||||
resputil.JSON(w, err)
|
||||
return
|
||||
}
|
||||
|
||||
value, err := h.List(r.Context(), params)
|
||||
if err != nil {
|
||||
logger.LogControllerError("Settings.List", r, err, params.Auditable())
|
||||
resputil.JSON(w, err)
|
||||
return
|
||||
}
|
||||
logger.LogControllerCall("Settings.List", r, params.Auditable())
|
||||
if !serveHTTP(value, w, r) {
|
||||
resputil.JSON(w, value)
|
||||
}
|
||||
},
|
||||
Update: func(w http.ResponseWriter, r *http.Request) {
|
||||
defer r.Body.Close()
|
||||
params := request.NewSettingsUpdate()
|
||||
if err := params.Fill(r); err != nil {
|
||||
logger.LogParamError("Settings.Update", r, err)
|
||||
resputil.JSON(w, err)
|
||||
return
|
||||
}
|
||||
|
||||
value, err := h.Update(r.Context(), params)
|
||||
if err != nil {
|
||||
logger.LogControllerError("Settings.Update", r, err, params.Auditable())
|
||||
resputil.JSON(w, err)
|
||||
return
|
||||
}
|
||||
logger.LogControllerCall("Settings.Update", r, params.Auditable())
|
||||
if !serveHTTP(value, w, r) {
|
||||
resputil.JSON(w, value)
|
||||
}
|
||||
},
|
||||
Get: func(w http.ResponseWriter, r *http.Request) {
|
||||
defer r.Body.Close()
|
||||
params := request.NewSettingsGet()
|
||||
if err := params.Fill(r); err != nil {
|
||||
logger.LogParamError("Settings.Get", r, err)
|
||||
resputil.JSON(w, err)
|
||||
return
|
||||
}
|
||||
|
||||
value, err := h.Get(r.Context(), params)
|
||||
if err != nil {
|
||||
logger.LogControllerError("Settings.Get", r, err, params.Auditable())
|
||||
resputil.JSON(w, err)
|
||||
return
|
||||
}
|
||||
logger.LogControllerCall("Settings.Get", r, params.Auditable())
|
||||
if !serveHTTP(value, w, r) {
|
||||
resputil.JSON(w, value)
|
||||
}
|
||||
},
|
||||
Set: func(w http.ResponseWriter, r *http.Request) {
|
||||
defer r.Body.Close()
|
||||
params := request.NewSettingsSet()
|
||||
if err := params.Fill(r); err != nil {
|
||||
logger.LogParamError("Settings.Set", r, err)
|
||||
resputil.JSON(w, err)
|
||||
return
|
||||
}
|
||||
|
||||
value, err := h.Set(r.Context(), params)
|
||||
if err != nil {
|
||||
logger.LogControllerError("Settings.Set", r, err, params.Auditable())
|
||||
resputil.JSON(w, err)
|
||||
return
|
||||
}
|
||||
logger.LogControllerCall("Settings.Set", r, params.Auditable())
|
||||
if !serveHTTP(value, w, r) {
|
||||
resputil.JSON(w, value)
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func (h Settings) MountRoutes(r chi.Router, middlewares ...func(http.Handler) http.Handler) {
|
||||
r.Group(func(r chi.Router) {
|
||||
r.Use(middlewares...)
|
||||
r.Get("/settings/", h.List)
|
||||
r.Patch("/settings/", h.Update)
|
||||
r.Get("/settings/{key}", h.Get)
|
||||
r.Put("/settings/{key}", h.Set)
|
||||
})
|
||||
}
|
||||
262
compose/rest/request/settings.go
Normal file
262
compose/rest/request/settings.go
Normal file
@ -0,0 +1,262 @@
|
||||
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 `settings.go`, `settings.util.go` or `settings_test.go` to
|
||||
implement your API calls, helper functions and tests. The file `settings.go`
|
||||
is only generated the first time, and will not be overwritten if it exists.
|
||||
*/
|
||||
|
||||
import (
|
||||
"io"
|
||||
"strings"
|
||||
|
||||
"encoding/json"
|
||||
"mime/multipart"
|
||||
"net/http"
|
||||
|
||||
"github.com/go-chi/chi"
|
||||
"github.com/pkg/errors"
|
||||
|
||||
sqlxTypes "github.com/jmoiron/sqlx/types"
|
||||
)
|
||||
|
||||
var _ = chi.URLParam
|
||||
var _ = multipart.FileHeader{}
|
||||
|
||||
// Settings list request parameters
|
||||
type SettingsList struct {
|
||||
Prefix string
|
||||
}
|
||||
|
||||
func NewSettingsList() *SettingsList {
|
||||
return &SettingsList{}
|
||||
}
|
||||
|
||||
func (r SettingsList) Auditable() map[string]interface{} {
|
||||
var out = map[string]interface{}{}
|
||||
|
||||
out["prefix"] = r.Prefix
|
||||
|
||||
return out
|
||||
}
|
||||
|
||||
func (r *SettingsList) Fill(req *http.Request) (err error) {
|
||||
if strings.ToLower(req.Header.Get("content-type")) == "application/json" {
|
||||
err = json.NewDecoder(req.Body).Decode(r)
|
||||
|
||||
switch {
|
||||
case err == io.EOF:
|
||||
err = nil
|
||||
case err != nil:
|
||||
return errors.Wrap(err, "error parsing http request body")
|
||||
}
|
||||
}
|
||||
|
||||
if err = req.ParseForm(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
get := map[string]string{}
|
||||
post := map[string]string{}
|
||||
urlQuery := req.URL.Query()
|
||||
for name, param := range urlQuery {
|
||||
get[name] = string(param[0])
|
||||
}
|
||||
postVars := req.Form
|
||||
for name, param := range postVars {
|
||||
post[name] = string(param[0])
|
||||
}
|
||||
|
||||
if val, ok := get["prefix"]; ok {
|
||||
r.Prefix = val
|
||||
}
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
var _ RequestFiller = NewSettingsList()
|
||||
|
||||
// Settings update request parameters
|
||||
type SettingsUpdate struct {
|
||||
Values sqlxTypes.JSONText
|
||||
}
|
||||
|
||||
func NewSettingsUpdate() *SettingsUpdate {
|
||||
return &SettingsUpdate{}
|
||||
}
|
||||
|
||||
func (r SettingsUpdate) Auditable() map[string]interface{} {
|
||||
var out = map[string]interface{}{}
|
||||
|
||||
out["values"] = r.Values
|
||||
|
||||
return out
|
||||
}
|
||||
|
||||
func (r *SettingsUpdate) Fill(req *http.Request) (err error) {
|
||||
if strings.ToLower(req.Header.Get("content-type")) == "application/json" {
|
||||
err = json.NewDecoder(req.Body).Decode(r)
|
||||
|
||||
switch {
|
||||
case err == io.EOF:
|
||||
err = nil
|
||||
case err != nil:
|
||||
return errors.Wrap(err, "error parsing http request body")
|
||||
}
|
||||
}
|
||||
|
||||
if err = req.ParseForm(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
get := map[string]string{}
|
||||
post := map[string]string{}
|
||||
urlQuery := req.URL.Query()
|
||||
for name, param := range urlQuery {
|
||||
get[name] = string(param[0])
|
||||
}
|
||||
postVars := req.Form
|
||||
for name, param := range postVars {
|
||||
post[name] = string(param[0])
|
||||
}
|
||||
|
||||
if val, ok := post["values"]; ok {
|
||||
|
||||
if r.Values, err = parseJSONTextWithErr(val); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
var _ RequestFiller = NewSettingsUpdate()
|
||||
|
||||
// Settings get request parameters
|
||||
type SettingsGet struct {
|
||||
OwnerID uint64 `json:",string"`
|
||||
Key string
|
||||
}
|
||||
|
||||
func NewSettingsGet() *SettingsGet {
|
||||
return &SettingsGet{}
|
||||
}
|
||||
|
||||
func (r SettingsGet) Auditable() map[string]interface{} {
|
||||
var out = map[string]interface{}{}
|
||||
|
||||
out["ownerID"] = r.OwnerID
|
||||
out["key"] = r.Key
|
||||
|
||||
return out
|
||||
}
|
||||
|
||||
func (r *SettingsGet) Fill(req *http.Request) (err error) {
|
||||
if strings.ToLower(req.Header.Get("content-type")) == "application/json" {
|
||||
err = json.NewDecoder(req.Body).Decode(r)
|
||||
|
||||
switch {
|
||||
case err == io.EOF:
|
||||
err = nil
|
||||
case err != nil:
|
||||
return errors.Wrap(err, "error parsing http request body")
|
||||
}
|
||||
}
|
||||
|
||||
if err = req.ParseForm(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
get := map[string]string{}
|
||||
post := map[string]string{}
|
||||
urlQuery := req.URL.Query()
|
||||
for name, param := range urlQuery {
|
||||
get[name] = string(param[0])
|
||||
}
|
||||
postVars := req.Form
|
||||
for name, param := range postVars {
|
||||
post[name] = string(param[0])
|
||||
}
|
||||
|
||||
if val, ok := get["ownerID"]; ok {
|
||||
r.OwnerID = parseUInt64(val)
|
||||
}
|
||||
r.Key = chi.URLParam(req, "key")
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
var _ RequestFiller = NewSettingsGet()
|
||||
|
||||
// Settings set request parameters
|
||||
type SettingsSet struct {
|
||||
Key string
|
||||
OwnerID uint64 `json:",string"`
|
||||
Value sqlxTypes.JSONText
|
||||
}
|
||||
|
||||
func NewSettingsSet() *SettingsSet {
|
||||
return &SettingsSet{}
|
||||
}
|
||||
|
||||
func (r SettingsSet) Auditable() map[string]interface{} {
|
||||
var out = map[string]interface{}{}
|
||||
|
||||
out["key"] = r.Key
|
||||
out["ownerID"] = r.OwnerID
|
||||
out["value"] = r.Value
|
||||
|
||||
return out
|
||||
}
|
||||
|
||||
func (r *SettingsSet) Fill(req *http.Request) (err error) {
|
||||
if strings.ToLower(req.Header.Get("content-type")) == "application/json" {
|
||||
err = json.NewDecoder(req.Body).Decode(r)
|
||||
|
||||
switch {
|
||||
case err == io.EOF:
|
||||
err = nil
|
||||
case err != nil:
|
||||
return errors.Wrap(err, "error parsing http request body")
|
||||
}
|
||||
}
|
||||
|
||||
if err = req.ParseForm(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
get := map[string]string{}
|
||||
post := map[string]string{}
|
||||
urlQuery := req.URL.Query()
|
||||
for name, param := range urlQuery {
|
||||
get[name] = string(param[0])
|
||||
}
|
||||
postVars := req.Form
|
||||
for name, param := range postVars {
|
||||
post[name] = string(param[0])
|
||||
}
|
||||
|
||||
r.Key = chi.URLParam(req, "key")
|
||||
if val, ok := post["ownerID"]; ok {
|
||||
r.OwnerID = parseUInt64(val)
|
||||
}
|
||||
if val, ok := post["value"]; ok {
|
||||
|
||||
if r.Value, err = parseJSONTextWithErr(val); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
var _ RequestFiller = NewSettingsSet()
|
||||
@ -39,6 +39,7 @@ func MountRoutes(r chi.Router) {
|
||||
handlers.NewChart(chart).MountRoutes(r)
|
||||
handlers.NewNotification(notification).MountRoutes(r)
|
||||
handlers.NewPermissions(Permissions{}.New()).MountRoutes(r)
|
||||
handlers.NewSettings(Settings{}.New()).MountRoutes(r)
|
||||
|
||||
handlers.NewAutomationScript(automationScript).MountRoutes(r)
|
||||
handlers.NewAutomationTrigger(automationTrigger).MountRoutes(r)
|
||||
|
||||
61
compose/rest/settings.go
Normal file
61
compose/rest/settings.go
Normal file
@ -0,0 +1,61 @@
|
||||
package rest
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
"github.com/titpetric/factory/resputil"
|
||||
|
||||
"github.com/cortezaproject/corteza-server/compose/rest/request"
|
||||
"github.com/cortezaproject/corteza-server/compose/service"
|
||||
"github.com/cortezaproject/corteza-server/pkg/settings"
|
||||
)
|
||||
|
||||
var _ = errors.Wrap
|
||||
|
||||
type (
|
||||
Settings struct {
|
||||
svc struct {
|
||||
settings service.SettingsService
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
func (Settings) New() *Settings {
|
||||
ctrl := &Settings{}
|
||||
ctrl.svc.settings = service.DefaultSettings
|
||||
|
||||
return ctrl
|
||||
}
|
||||
|
||||
func (ctrl *Settings) List(ctx context.Context, r *request.SettingsList) (interface{}, error) {
|
||||
if vv, err := ctrl.svc.settings.With(ctx).FindByPrefix(r.Prefix); err != nil {
|
||||
return nil, err
|
||||
} else {
|
||||
return vv, err
|
||||
}
|
||||
}
|
||||
|
||||
func (ctrl *Settings) Update(ctx context.Context, r *request.SettingsUpdate) (interface{}, error) {
|
||||
values := settings.ValueSet{}
|
||||
|
||||
if err := r.Values.Unmarshal(&values); err != nil {
|
||||
return nil, err
|
||||
} else if err := ctrl.svc.settings.With(ctx).BulkSet(values); err != nil {
|
||||
return nil, err
|
||||
} else {
|
||||
return true, nil
|
||||
}
|
||||
}
|
||||
|
||||
func (ctrl *Settings) Get(ctx context.Context, r *request.SettingsGet) (interface{}, error) {
|
||||
if v, err := ctrl.svc.settings.With(ctx).Get(r.Key, r.OwnerID); err != nil {
|
||||
return nil, err
|
||||
} else {
|
||||
return v, nil
|
||||
}
|
||||
}
|
||||
|
||||
func (ctrl *Settings) Set(ctx context.Context, r *request.SettingsSet) (interface{}, error) {
|
||||
return resputil.OK(), errors.New("Not implemented: Settings.set")
|
||||
}
|
||||
@ -49,6 +49,14 @@ func (svc accessControl) CanGrant(ctx context.Context) bool {
|
||||
return svc.can(ctx, types.ComposePermissionResource, "grant")
|
||||
}
|
||||
|
||||
func (svc accessControl) CanReadSettings(ctx context.Context) bool {
|
||||
return svc.can(ctx, types.ComposePermissionResource, "settings.read")
|
||||
}
|
||||
|
||||
func (svc accessControl) CanManageSettings(ctx context.Context) bool {
|
||||
return svc.can(ctx, types.ComposePermissionResource, "settings.manage")
|
||||
}
|
||||
|
||||
func (svc accessControl) CanCreateNamespace(ctx context.Context) bool {
|
||||
return svc.can(ctx, types.ComposePermissionResource, "namespace.create")
|
||||
}
|
||||
|
||||
@ -12,6 +12,7 @@ import (
|
||||
"github.com/cortezaproject/corteza-server/pkg/automation/corredor"
|
||||
"github.com/cortezaproject/corteza-server/pkg/cli/options"
|
||||
"github.com/cortezaproject/corteza-server/pkg/permissions"
|
||||
internalSettings "github.com/cortezaproject/corteza-server/pkg/settings"
|
||||
"github.com/cortezaproject/corteza-server/pkg/store"
|
||||
"github.com/cortezaproject/corteza-server/pkg/store/minio"
|
||||
"github.com/cortezaproject/corteza-server/pkg/store/plain"
|
||||
@ -42,6 +43,9 @@ var (
|
||||
|
||||
DefaultLogger *zap.Logger
|
||||
|
||||
DefaultInternalSettings internalSettings.Service
|
||||
DefaultSettings SettingsService
|
||||
|
||||
// DefaultPermissions Retrieves & stores permissions
|
||||
DefaultPermissions permissionServicer
|
||||
|
||||
@ -78,6 +82,8 @@ func Init(ctx context.Context, log *zap.Logger, c Config) (err error) {
|
||||
|
||||
DefaultLogger = log.Named("service")
|
||||
|
||||
DefaultInternalSettings = internalSettings.NewService(internalSettings.NewRepository(repository.DB(ctx), "compose_settings"))
|
||||
|
||||
if DefaultStore == nil {
|
||||
if c.Storage.MinioEndpoint != "" {
|
||||
if c.Storage.MinioBucket == "" {
|
||||
@ -119,6 +125,8 @@ func Init(ctx context.Context, log *zap.Logger, c Config) (err error) {
|
||||
}
|
||||
DefaultAccessControl = AccessControl(DefaultPermissions)
|
||||
|
||||
DefaultSettings = Settings(ctx, DefaultInternalSettings)
|
||||
|
||||
DefaultNamespace = Namespace()
|
||||
DefaultModule = Module()
|
||||
|
||||
|
||||
96
compose/service/settings.go
Normal file
96
compose/service/settings.go
Normal file
@ -0,0 +1,96 @@
|
||||
package service
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
"github.com/titpetric/factory"
|
||||
"go.uber.org/zap"
|
||||
"go.uber.org/zap/zapcore"
|
||||
|
||||
"github.com/cortezaproject/corteza-server/compose/repository"
|
||||
"github.com/cortezaproject/corteza-server/pkg/logger"
|
||||
internalSettings "github.com/cortezaproject/corteza-server/pkg/settings"
|
||||
)
|
||||
|
||||
type (
|
||||
// Wrapper service for compose around internal settings service
|
||||
settings struct {
|
||||
ctx context.Context
|
||||
db *factory.DB
|
||||
logger *zap.Logger
|
||||
|
||||
ac settingsAccessController
|
||||
internalSettings internalSettings.Service
|
||||
}
|
||||
|
||||
settingsAccessController interface {
|
||||
CanReadSettings(ctx context.Context) bool
|
||||
CanManageSettings(ctx context.Context) bool
|
||||
}
|
||||
|
||||
SettingsService interface {
|
||||
With(ctx context.Context) SettingsService
|
||||
FindByPrefix(prefix string) (vv internalSettings.ValueSet, err error)
|
||||
Set(v *internalSettings.Value) (err error)
|
||||
BulkSet(vv internalSettings.ValueSet) (err error)
|
||||
Get(name string, ownedBy uint64) (out *internalSettings.Value, err error)
|
||||
}
|
||||
)
|
||||
|
||||
func Settings(ctx context.Context, intSet internalSettings.Service) SettingsService {
|
||||
return (&settings{
|
||||
internalSettings: intSet,
|
||||
ac: DefaultAccessControl,
|
||||
logger: DefaultLogger.Named("settings"),
|
||||
}).With(ctx)
|
||||
}
|
||||
|
||||
func (svc settings) With(ctx context.Context) SettingsService {
|
||||
db := repository.DB(ctx)
|
||||
|
||||
return &settings{
|
||||
ctx: ctx,
|
||||
db: db,
|
||||
ac: svc.ac,
|
||||
logger: svc.logger,
|
||||
|
||||
internalSettings: svc.internalSettings.With(ctx),
|
||||
}
|
||||
}
|
||||
|
||||
func (svc settings) log(ctx context.Context, fields ...zapcore.Field) *zap.Logger {
|
||||
return logger.AddRequestID(ctx, svc.logger).With(fields...)
|
||||
}
|
||||
|
||||
func (svc settings) FindByPrefix(prefix string) (vv internalSettings.ValueSet, err error) {
|
||||
if !svc.ac.CanReadSettings(svc.ctx) {
|
||||
return nil, errors.New("not allowed to read settings")
|
||||
}
|
||||
|
||||
return svc.internalSettings.FindByPrefix(prefix)
|
||||
}
|
||||
|
||||
func (svc settings) Set(v *internalSettings.Value) (err error) {
|
||||
if !svc.ac.CanManageSettings(svc.ctx) {
|
||||
return errors.New("not allowed to manage settings")
|
||||
}
|
||||
|
||||
return svc.internalSettings.Set(v)
|
||||
}
|
||||
|
||||
func (svc settings) BulkSet(vv internalSettings.ValueSet) (err error) {
|
||||
if !svc.ac.CanManageSettings(svc.ctx) {
|
||||
return errors.New("not allowed to manage settings")
|
||||
}
|
||||
|
||||
return svc.internalSettings.BulkSet(vv)
|
||||
}
|
||||
|
||||
func (svc settings) Get(name string, ownedBy uint64) (out *internalSettings.Value, err error) {
|
||||
if !svc.ac.CanReadSettings(svc.ctx) {
|
||||
return nil, errors.New("not allowed to read settings")
|
||||
}
|
||||
|
||||
return svc.internalSettings.Get(name, ownedBy)
|
||||
}
|
||||
@ -1183,4 +1183,77 @@ Compose records
|
||||
| namespaceID | uint64 | PATH | Namespace ID | N/A | YES |
|
||||
| moduleID | uint64 | PATH | Module ID | N/A | YES |
|
||||
|
||||
---
|
||||
|
||||
|
||||
|
||||
|
||||
# Settings
|
||||
|
||||
| Method | Endpoint | Purpose |
|
||||
| ------ | -------- | ------- |
|
||||
| `GET` | `/settings/` | List settings |
|
||||
| `PATCH` | `/settings/` | Update settings |
|
||||
| `GET` | `/settings/{key}` | Get a value for a key |
|
||||
| `PUT` | `/settings/{key}` | Set a value for a key |
|
||||
|
||||
## List settings
|
||||
|
||||
#### Method
|
||||
|
||||
| URI | Protocol | Method | Authentication |
|
||||
| --- | -------- | ------ | -------------- |
|
||||
| `/settings/` | HTTP/S | GET | |
|
||||
|
||||
#### Request parameters
|
||||
|
||||
| Parameter | Type | Method | Description | Default | Required? |
|
||||
| --------- | ---- | ------ | ----------- | ------- | --------- |
|
||||
| prefix | string | GET | Key prefix | N/A | NO |
|
||||
|
||||
## Update settings
|
||||
|
||||
#### Method
|
||||
|
||||
| URI | Protocol | Method | Authentication |
|
||||
| --- | -------- | ------ | -------------- |
|
||||
| `/settings/` | HTTP/S | PATCH | |
|
||||
|
||||
#### Request parameters
|
||||
|
||||
| Parameter | Type | Method | Description | Default | Required? |
|
||||
| --------- | ---- | ------ | ----------- | ------- | --------- |
|
||||
| values | sqlxTypes.JSONText | POST | Array of new settings: `[{ name: ..., value: ... }]`. Omit value to remove setting | N/A | YES |
|
||||
|
||||
## Get a value for a key
|
||||
|
||||
#### Method
|
||||
|
||||
| URI | Protocol | Method | Authentication |
|
||||
| --- | -------- | ------ | -------------- |
|
||||
| `/settings/{key}` | HTTP/S | GET | |
|
||||
|
||||
#### Request parameters
|
||||
|
||||
| Parameter | Type | Method | Description | Default | Required? |
|
||||
| --------- | ---- | ------ | ----------- | ------- | --------- |
|
||||
| ownerID | uint64 | GET | Owner ID | N/A | NO |
|
||||
| key | string | PATH | Setting key | N/A | YES |
|
||||
|
||||
## Set a value for a key
|
||||
|
||||
#### Method
|
||||
|
||||
| URI | Protocol | Method | Authentication |
|
||||
| --- | -------- | ------ | -------------- |
|
||||
| `/settings/{key}` | HTTP/S | PUT | |
|
||||
|
||||
#### Request parameters
|
||||
|
||||
| Parameter | Type | Method | Description | Default | Required? |
|
||||
| --------- | ---- | ------ | ----------- | ------- | --------- |
|
||||
| key | string | PATH | Setting key | N/A | YES |
|
||||
| ownerID | uint64 | POST | Owner | N/A | NO |
|
||||
| value | sqlxTypes.JSONText | POST | Setting value | N/A | YES |
|
||||
|
||||
---
|
||||
File diff suppressed because one or more lines are too long
@ -3,4 +3,4 @@
|
||||
// Package contains static assets.
|
||||
package messaging
|
||||
|
||||
var Asset = "PK\x03\x04\x14\x00\x08\x00\x00\x00\x00\x00!(\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x18\x00 \x000000_access_control.yamlUT\x05\x00\x01\x80Cm8allow:\n everyone:\n messaging:\n - access\n\n admins:\n messaging:\n - access\n - grant\n - channel.public.create\n - channel.private.create\n - channel.group.create\n\n messaging:channel:\n - update\n - leave\n - read\n - join\n - delete\n - undelete\n - archive\n - unarchive\n - members.manage\n - attachments.manage\n - message.attach\n - message.update.all\n - message.update.own\n - message.delete.all\n - message.delete.own\n - message.embed\n - message.send\n - message.reply\n - message.react\n\nPK\x07\x08\xa5\xf4PT`\x02\x00\x00`\x02\x00\x00PK\x03\x04\x14\x00\x08\x00\x00\x00\x00\x00!(\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x12\x00 \x001000_channels.yamlUT\x05\x00\x01\x80Cm8channels:\n - name: General\n type: public\n - name: Random\n type: public\nPK\x07\x08\xe8\x83F\xf8O\x00\x00\x00O\x00\x00\x00PK\x01\x02\x14\x03\x14\x00\x08\x00\x00\x00\x00\x00!(\xa5\xf4PT`\x02\x00\x00`\x02\x00\x00\x18\x00 \x00\x00\x00\x00\x00\x00\x00\x00\x00\xa4\x81\x00\x00\x00\x000000_access_control.yamlUT\x05\x00\x01\x80Cm8PK\x01\x02\x14\x03\x14\x00\x08\x00\x00\x00\x00\x00!(\xe8\x83F\xf8O\x00\x00\x00O\x00\x00\x00\x12\x00 \x00\x00\x00\x00\x00\x00\x00\x00\x00\xa4\x81\xaf\x02\x00\x001000_channels.yamlUT\x05\x00\x01\x80Cm8PK\x05\x06\x00\x00\x00\x00\x02\x00\x02\x00\x98\x00\x00\x00G\x03\x00\x00\x00\x00"
|
||||
var Asset = "PK\x03\x04\x14\x00\x08\x00\x00\x00\x00\x00!(\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x18\x00 \x000000_access_control.yamlUT\x05\x00\x01\x80Cm8allow:\n everyone:\n messaging:\n - access\n\n admins:\n messaging:\n - access\n - grant\n - channel.public.create\n - channel.private.create\n - channel.group.create\n\n messaging:channel:\n - update\n - leave\n - read\n - join\n - delete\n - undelete\n - archive\n - unarchive\n - members.manage\n - attachments.manage\n - message.attach\n - message.update.all\n - message.update.own\n - message.delete.all\n - message.delete.own\n - message.embed\n - message.send\n - message.reply\n - message.react\n\nPK\x07\x08\xa5\xf4PT`\x02\x00\x00`\x02\x00\x00PK\x03\x04\x14\x00\x08\x00\x00\x00\x00\x00!(\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x12\x00 \x001000_channels.yamlUT\x05\x00\x01\x80Cm8channels:\n - name: General\n type: public\n - name: Random\n type: public\nPK\x07\x08\xe8\x83F\xf8O\x00\x00\x00O\x00\x00\x00PK\x01\x02\x14\x03\x14\x00\x08\x00\x00\x00\x00\x00!(\xa5\xf4PT`\x02\x00\x00`\x02\x00\x00\x18\x00 \x00\x00\x00\x00\x00\x00\x00\x00\x00\xb4\x81\x00\x00\x00\x000000_access_control.yamlUT\x05\x00\x01\x80Cm8PK\x01\x02\x14\x03\x14\x00\x08\x00\x00\x00\x00\x00!(\xe8\x83F\xf8O\x00\x00\x00O\x00\x00\x00\x12\x00 \x00\x00\x00\x00\x00\x00\x00\x00\x00\xb4\x81\xaf\x02\x00\x001000_channels.yamlUT\x05\x00\x01\x80Cm8PK\x05\x06\x00\x00\x00\x00\x02\x00\x02\x00\x98\x00\x00\x00G\x03\x00\x00\x00\x00"
|
||||
|
||||
@ -3,4 +3,4 @@
|
||||
// Package contains static assets.
|
||||
package system
|
||||
|
||||
var Asset = "PK\x03\x04\x14\x00\x08\x00\x00\x00\x00\x00!(\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x18\x00 \x000000_access_control.yamlUT\x05\x00\x01\x80Cm8allow:\n admins:\n system:\n - access\n - grant\n - settings.read\n - settings.manage\n - organisation.create\n - application.create\n - user.create\n - role.create\n - automation-script.create\n\n system:application:\n - read\n - update\n - delete\n\n system:user:\n - read\n - update\n - suspend\n - unsuspend\n - delete\n\n system:role:\n - read\n - update\n - delete\n - members.manage\n\n system:automation-script:\n - read\n - update\n - delete\nPK\x07\x08\xd3\xa84K)\x02\x00\x00)\x02\x00\x00PK\x01\x02\x14\x03\x14\x00\x08\x00\x00\x00\x00\x00!(\xd3\xa84K)\x02\x00\x00)\x02\x00\x00\x18\x00 \x00\x00\x00\x00\x00\x00\x00\x00\x00\xa4\x81\x00\x00\x00\x000000_access_control.yamlUT\x05\x00\x01\x80Cm8PK\x05\x06\x00\x00\x00\x00\x01\x00\x01\x00O\x00\x00\x00x\x02\x00\x00\x00\x00"
|
||||
var Asset = "PK\x03\x04\x14\x00\x08\x00\x00\x00\x00\x00!(\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x18\x00 \x000000_access_control.yamlUT\x05\x00\x01\x80Cm8allow:\n admins:\n system:\n - access\n - grant\n - settings.read\n - settings.manage\n - organisation.create\n - application.create\n - user.create\n - role.create\n - automation-script.create\n\n system:application:\n - read\n - update\n - delete\n\n system:user:\n - read\n - update\n - suspend\n - unsuspend\n - delete\n\n system:role:\n - read\n - update\n - delete\n - members.manage\n\n system:automation-script:\n - read\n - update\n - delete\nPK\x07\x08\xd3\xa84K)\x02\x00\x00)\x02\x00\x00PK\x01\x02\x14\x03\x14\x00\x08\x00\x00\x00\x00\x00!(\xd3\xa84K)\x02\x00\x00)\x02\x00\x00\x18\x00 \x00\x00\x00\x00\x00\x00\x00\x00\x00\xb4\x81\x00\x00\x00\x000000_access_control.yamlUT\x05\x00\x01\x80Cm8PK\x05\x06\x00\x00\x00\x00\x01\x00\x01\x00O\x00\x00\x00x\x02\x00\x00\x00\x00"
|
||||
|
||||
File diff suppressed because one or more lines are too long
Loading…
x
Reference in New Issue
Block a user