Add improve settings for messaging
This commit is contained in:
@@ -37,15 +37,23 @@ func (imp *Importer) Cast(in interface{}) (err error) {
|
||||
return deinterfacer.Each(in, func(index int, key string, val interface{}) (err error) {
|
||||
switch key {
|
||||
case "channels":
|
||||
return imp.channels.CastSet(val)
|
||||
if imp.channels != nil {
|
||||
return imp.channels.CastSet(val)
|
||||
}
|
||||
case "channel":
|
||||
return imp.channels.CastSet([]interface{}{val})
|
||||
if imp.channels != nil {
|
||||
return imp.channels.CastSet([]interface{}{val})
|
||||
}
|
||||
|
||||
case "settings":
|
||||
return imp.settings.CastSet(val)
|
||||
if imp.settings != nil {
|
||||
return imp.settings.CastSet(val)
|
||||
}
|
||||
|
||||
case "allow", "deny":
|
||||
return imp.permissions.CastResourcesSet(key, val)
|
||||
if imp.permissions != nil {
|
||||
return imp.permissions.CastResourcesSet(key, val)
|
||||
}
|
||||
|
||||
default:
|
||||
err = fmt.Errorf("unexpected key %q", key)
|
||||
@@ -56,25 +64,31 @@ func (imp *Importer) Cast(in interface{}) (err error) {
|
||||
}
|
||||
|
||||
func (imp *Importer) Store(ctx context.Context, rk channelKeeper, pk permissions.ImportKeeper, sk settings.ImportKeeper, roles sysTypes.RoleSet) (err error) {
|
||||
err = imp.channels.Store(ctx, rk)
|
||||
if err != nil {
|
||||
return
|
||||
if imp.channels != nil {
|
||||
err = imp.channels.Store(ctx, rk)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
// Make sure we properly replace channel handles with IDs
|
||||
roles.Walk(func(r *sysTypes.Role) error {
|
||||
imp.permissions.UpdateRoles(r.Handle, r.ID)
|
||||
return nil
|
||||
})
|
||||
if imp.permissions != nil {
|
||||
// Make sure we properly replace channel handles with IDs
|
||||
roles.Walk(func(r *sysTypes.Role) error {
|
||||
imp.permissions.UpdateRoles(r.Handle, r.ID)
|
||||
return nil
|
||||
})
|
||||
|
||||
err = imp.permissions.Store(ctx, pk)
|
||||
if err != nil {
|
||||
return
|
||||
err = imp.permissions.Store(ctx, pk)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
err = imp.settings.Store(ctx, sk)
|
||||
if err != nil {
|
||||
return
|
||||
if imp.settings != nil {
|
||||
err = imp.settings.Store(ctx, sk)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
|
||||
@@ -2,9 +2,11 @@ package messaging
|
||||
|
||||
import (
|
||||
"context"
|
||||
"io"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
"github.com/spf13/cobra"
|
||||
"gopkg.in/yaml.v2"
|
||||
|
||||
"github.com/cortezaproject/corteza-server/messaging/importer"
|
||||
"github.com/cortezaproject/corteza-server/messaging/service"
|
||||
@@ -12,21 +14,23 @@ import (
|
||||
"github.com/cortezaproject/corteza-server/pkg/auth"
|
||||
"github.com/cortezaproject/corteza-server/pkg/cli"
|
||||
impAux "github.com/cortezaproject/corteza-server/pkg/importer"
|
||||
"github.com/cortezaproject/corteza-server/pkg/settings"
|
||||
provision "github.com/cortezaproject/corteza-server/provision/messaging"
|
||||
)
|
||||
|
||||
func provisionConfig(ctx context.Context, cmd *cobra.Command, c *cli.Config) error {
|
||||
func provisionConfig(ctx context.Context, cmd *cobra.Command, c *cli.Config) (err error) {
|
||||
c.Log.Debug("running configuration provision")
|
||||
c.InitServices(ctx, c)
|
||||
|
||||
var provisioned bool
|
||||
|
||||
// Make sure we have all full access for provisioning
|
||||
ctx = auth.SetSuperUserContext(ctx)
|
||||
|
||||
if provisioned, err := isProvisioned(ctx); err != nil {
|
||||
if provisioned, err = isProvisioned(ctx); err != nil {
|
||||
return err
|
||||
} else if provisioned {
|
||||
c.Log.Debug("configuration already provisioned")
|
||||
return nil
|
||||
}
|
||||
|
||||
readers, err := impAux.ReadStatic(provision.Asset)
|
||||
@@ -34,6 +38,10 @@ func provisionConfig(ctx context.Context, cmd *cobra.Command, c *cli.Config) err
|
||||
return err
|
||||
}
|
||||
|
||||
if provisioned {
|
||||
return partialImportSettings(ctx, service.DefaultSettings, readers...)
|
||||
}
|
||||
|
||||
return errors.Wrap(
|
||||
importer.Import(ctx, readers...),
|
||||
"could not provision configuration for messaging service",
|
||||
@@ -45,3 +53,53 @@ func isProvisioned(ctx context.Context) (bool, error) {
|
||||
cc, _, err := service.DefaultChannel.With(ctx).Find(types.ChannelFilter{IncludeDeleted: true})
|
||||
return len(cc) > 0, err
|
||||
}
|
||||
|
||||
// Partial import of settings from provision files
|
||||
func partialImportSettings(ctx context.Context, ss service.SettingsService, ff ...io.Reader) (err error) {
|
||||
var (
|
||||
// decoded content from YAML files
|
||||
aux interface{}
|
||||
|
||||
si = settings.NewImporter()
|
||||
|
||||
// importer w/o permissions & roles
|
||||
// we need only settings
|
||||
imp = importer.NewImporter(nil, si, nil)
|
||||
|
||||
// current value
|
||||
current settings.ValueSet
|
||||
|
||||
// unexisting values
|
||||
unex settings.ValueSet
|
||||
)
|
||||
|
||||
for _, f := range ff {
|
||||
if err = yaml.NewDecoder(f).Decode(&aux); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
err = imp.Cast(aux)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
ss = ss.With(ctx)
|
||||
|
||||
// Get all "current" settings storage
|
||||
current, err = ss.FindByPrefix("")
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
// Compare current settings with imported, get all that do not exist yet
|
||||
if unex = si.GetValues(); len(unex) > 0 {
|
||||
// Store non existing
|
||||
err = ss.BulkSet(current.New(unex))
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -7,6 +7,7 @@ import (
|
||||
"go.uber.org/zap"
|
||||
|
||||
"github.com/cortezaproject/corteza-server/messaging/repository"
|
||||
"github.com/cortezaproject/corteza-server/messaging/types"
|
||||
"github.com/cortezaproject/corteza-server/pkg/cli/options"
|
||||
"github.com/cortezaproject/corteza-server/pkg/http"
|
||||
"github.com/cortezaproject/corteza-server/pkg/permissions"
|
||||
@@ -41,6 +42,9 @@ var (
|
||||
DefaultSettings SettingsService
|
||||
DefaultAccessControl *accessControl
|
||||
|
||||
// CurrentSettings represents current messaging settings
|
||||
CurrentSettings = &types.Settings{}
|
||||
|
||||
DefaultAttachment AttachmentService
|
||||
DefaultChannel ChannelService
|
||||
DefaultMessage MessageService
|
||||
@@ -101,7 +105,7 @@ func Init(ctx context.Context, log *zap.Logger, c Config) (err error) {
|
||||
}
|
||||
DefaultAccessControl = AccessControl(DefaultPermissions)
|
||||
|
||||
DefaultSettings = Settings(ctx, DefaultInternalSettings)
|
||||
DefaultSettings = Settings(ctx, DefaultInternalSettings, CurrentSettings)
|
||||
|
||||
DefaultEvent = Event(ctx)
|
||||
DefaultChannel = Channel(ctx)
|
||||
|
||||
@@ -9,6 +9,7 @@ import (
|
||||
"go.uber.org/zap/zapcore"
|
||||
|
||||
"github.com/cortezaproject/corteza-server/messaging/repository"
|
||||
"github.com/cortezaproject/corteza-server/messaging/types"
|
||||
"github.com/cortezaproject/corteza-server/pkg/logger"
|
||||
internalSettings "github.com/cortezaproject/corteza-server/pkg/settings"
|
||||
)
|
||||
@@ -22,6 +23,7 @@ type (
|
||||
|
||||
ac settingsAccessController
|
||||
internalSettings internalSettings.Service
|
||||
current *types.Settings
|
||||
}
|
||||
|
||||
settingsAccessController interface {
|
||||
@@ -30,7 +32,7 @@ type (
|
||||
}
|
||||
|
||||
SettingsService interface {
|
||||
With(ctx context.Context) SettingsService
|
||||
With(ctx context.Context) *settings
|
||||
FindByPrefix(prefix string) (vv internalSettings.ValueSet, err error)
|
||||
Set(v *internalSettings.Value) (err error)
|
||||
BulkSet(vv internalSettings.ValueSet) (err error)
|
||||
@@ -38,15 +40,16 @@ type (
|
||||
}
|
||||
)
|
||||
|
||||
func Settings(ctx context.Context, intSet internalSettings.Service) SettingsService {
|
||||
func Settings(ctx context.Context, intSet internalSettings.Service, current *types.Settings) *settings {
|
||||
return (&settings{
|
||||
internalSettings: intSet,
|
||||
ac: DefaultAccessControl,
|
||||
logger: DefaultLogger.Named("settings"),
|
||||
current: current,
|
||||
}).With(ctx)
|
||||
}
|
||||
|
||||
func (svc settings) With(ctx context.Context) SettingsService {
|
||||
func (svc settings) With(ctx context.Context) *settings {
|
||||
db := repository.DB(ctx)
|
||||
|
||||
return &settings{
|
||||
@@ -56,6 +59,8 @@ func (svc settings) With(ctx context.Context) SettingsService {
|
||||
logger: svc.logger,
|
||||
|
||||
internalSettings: svc.internalSettings.With(ctx),
|
||||
|
||||
current: svc.current,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -71,12 +76,28 @@ func (svc settings) FindByPrefix(prefix string) (vv internalSettings.ValueSet, e
|
||||
return svc.internalSettings.FindByPrefix(prefix)
|
||||
}
|
||||
|
||||
// UpdateCurrent loads settings values from storage and updates current settings variable
|
||||
//
|
||||
// It accesses internal settings directly because
|
||||
// we do not want any security checks for this
|
||||
func (svc settings) UpdateCurrent() error {
|
||||
if vv, err := svc.internalSettings.FindByPrefix(""); err != nil {
|
||||
return err
|
||||
} else {
|
||||
return svc.updateCurrent(vv.KV())
|
||||
}
|
||||
}
|
||||
|
||||
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)
|
||||
if err = svc.internalSettings.Set(v); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
return svc.updateCurrent(internalSettings.KV{v.Name: v.Value})
|
||||
}
|
||||
|
||||
func (svc settings) BulkSet(vv internalSettings.ValueSet) (err error) {
|
||||
@@ -84,7 +105,34 @@ func (svc settings) BulkSet(vv internalSettings.ValueSet) (err error) {
|
||||
return errors.New("not allowed to manage settings")
|
||||
}
|
||||
|
||||
return svc.internalSettings.BulkSet(vv)
|
||||
var old internalSettings.ValueSet
|
||||
if old, err = svc.internalSettings.FindByPrefix(""); err != nil {
|
||||
return
|
||||
} else {
|
||||
vv = old.Changed(vv)
|
||||
}
|
||||
|
||||
if err = svc.internalSettings.BulkSet(vv); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
for _, v := range vv {
|
||||
svc.log(svc.ctx,
|
||||
zap.String("name", v.Name),
|
||||
zap.Stringer("value", v.Value)).Info("settings changed")
|
||||
}
|
||||
|
||||
return svc.updateCurrent(vv.KV())
|
||||
}
|
||||
|
||||
func (svc settings) updateCurrent(kv internalSettings.KV) (err error) {
|
||||
// update current settings with new values
|
||||
if err = kv.Decode(svc.current); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
svc.log(svc.ctx).Info("current settings updated")
|
||||
return
|
||||
}
|
||||
|
||||
func (svc settings) Get(name string, ownedBy uint64) (out *internalSettings.Value, err error) {
|
||||
|
||||
@@ -0,0 +1,43 @@
|
||||
package types
|
||||
|
||||
type (
|
||||
Settings struct {
|
||||
// UI related settings
|
||||
UI struct {
|
||||
// Emoji
|
||||
// @todo implementation
|
||||
Emoji struct {
|
||||
Enabled bool
|
||||
}
|
||||
|
||||
// In-browser notifications
|
||||
// @todo implementation
|
||||
BrowserNotifications struct {
|
||||
Enabled bool
|
||||
Header string
|
||||
MessageTrim uint `kv:"message-trim"`
|
||||
} `kv:"browser-notifications"`
|
||||
} `kv:"ui"`
|
||||
|
||||
// Message related settings
|
||||
Message struct {
|
||||
// @todo implementation
|
||||
Attachments struct {
|
||||
// Completely disable attachments
|
||||
Enabled bool
|
||||
|
||||
// What is max size (in MB, so: MaxSize x 2^20)
|
||||
MaxSize uint `kv:"max-size"`
|
||||
|
||||
// List of mime-types we support,
|
||||
Mimetypes []string
|
||||
|
||||
// Enable/disable individual attachment sources (mobile)
|
||||
Source struct {
|
||||
Gallery struct{ Enabled bool }
|
||||
Camera struct{ Enabled bool }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
)
|
||||
@@ -1,10 +1,10 @@
|
||||
settings:
|
||||
emoji.enabled: true
|
||||
message.attachment.enabled: true
|
||||
message.attachment.source.gallery.enabled: true
|
||||
message.attachment.source.camera.enabled: true
|
||||
message.attachment.max-size: 10
|
||||
message.attachment.type.whitelist: []
|
||||
notification.enabled: true
|
||||
notification.header.template: ${user} in ${channel} | Corteza
|
||||
notification.message.max-length: 200
|
||||
ui.emoji.enabled: true
|
||||
ui.browser-notifications.enabled: true
|
||||
ui.browser-notifications.header: ${user} in ${channel}
|
||||
ui.browser-notifications.message-trim: 200
|
||||
message.attachments.enabled: true
|
||||
message.attachments.max-size: 10
|
||||
message.attachments.mimetypes: []
|
||||
message.attachments.source.gallery.enabled: true
|
||||
message.attachments.source.camera.enabled: true
|
||||
|
||||
@@ -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 - settings.read\n - settings.manage\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\xae\x83\x83d\x8e\x02\x00\x00\x8e\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 \x000100_settings.yamlUT\x05\x00\x01\x80Cm8settings:\n emoji.enabled: true\n message.attachment.enabled: true\n message.attachment.source.gallery.enabled: true\n message.attachment.source.camera.enabled: true\n message.attachment.max-size: 10\n message.attachment.type.whitelist: []\n notification.enabled: true\n notification.header.template: ${user} in ${channel} | Corteza\n notification.message.max-length: 200\nPK\x07\x08\xc2\x0c\xfdkt\x01\x00\x00t\x01\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!(\xae\x83\x83d\x8e\x02\x00\x00\x8e\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!(\xc2\x0c\xfdkt\x01\x00\x00t\x01\x00\x00\x12\x00 \x00\x00\x00\x00\x00\x00\x00\x00\x00\xa4\x81\xdd\x02\x00\x000100_settings.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\x9a\x04\x00\x001000_channels.yamlUT\x05\x00\x01\x80Cm8PK\x05\x06\x00\x00\x00\x00\x03\x00\x03\x00\xe1\x00\x00\x002\x05\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 - settings.read\n - settings.manage\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\xae\x83\x83d\x8e\x02\x00\x00\x8e\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 \x000100_settings.yamlUT\x05\x00\x01\x80Cm8settings:\n ui.emoji.enabled: true\n ui.browser-notifications.enabled: true\n ui.browser-notifications.header: ${user} in ${channel}\n ui.browser-notifications.message-trim: 200\n message.attachments.enabled: true\n message.attachments.max-size: 10\n message.attachments.mimetypes: []\n message.attachments.source.gallery.enabled: true\n message.attachments.source.camera.enabled: true\nPK\x07\x08Cy\xf0y\x82\x01\x00\x00\x82\x01\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!(\xae\x83\x83d\x8e\x02\x00\x00\x8e\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!(Cy\xf0y\x82\x01\x00\x00\x82\x01\x00\x00\x12\x00 \x00\x00\x00\x00\x00\x00\x00\x00\x00\xa4\x81\xdd\x02\x00\x000100_settings.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\xa8\x04\x00\x001000_channels.yamlUT\x05\x00\x01\x80Cm8PK\x05\x06\x00\x00\x00\x00\x03\x00\x03\x00\xe1\x00\x00\x00@\x05\x00\x00\x00\x00"
|
||||
|
||||
Reference in New Issue
Block a user