You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
settings/cmd/microsettingsd/db/settings.go

213 lines
5.3 KiB
Go

package db
import (
"context"
"encoding/json"
"errors"
"time"
"github.com/google/uuid"
"github.com/uptrace/bun"
"go-micro.dev/v4/util/log"
"jochum.dev/jo-micro/auth2"
"jochum.dev/jo-micro/buncomponent"
"jochum.dev/jo-micro/components"
"jochum.dev/jo-micro/settings/proto/settingspb"
)
type Setting struct {
bun.BaseModel `bun:"settings,alias:s"`
ID uuid.UUID `bun:"id,pk,type:uuid,default:uuid_generate_v4()" json:"id" yaml:"id"`
OwnerID uuid.UUID `bun:"owner_id,type:uuid" json:"owner_id" yaml:"owner_id"`
Service string `json:"service" yaml:"service"`
Name string `json:"name" yaml:"name"`
Content json.RawMessage `bun:"type:jsonb" json:"content" yaml:"content"`
RolesRead []string `bun:"roles_read,array" json:"roles_read" yaml:"roles_read"`
RolesUpdate []string `bun:"roles_update,array" json:"roles_update" yaml:"roles_update"`
// Timestampable
CreatedAt time.Time `bun:"created_at,nullzero,notnull,default:current_timestamp" json:"created_at" yaml:"created_at"`
UpdatedAt bun.NullTime `bun:"updated_at" json:"updated_at" yaml:"updated_at"`
// Softdelete
DeletedAt bun.NullTime `bun:"deleted_at,soft_delete,nullzero" json:"deleted_at" yaml:"deleted_at"`
}
func (s *Setting) UserHasReadPermission(cReg *components.Registry, ctx context.Context) bool {
user, err := auth2.ClientAuthMustReg(cReg).Plugin().Inspect(ctx)
if err != nil {
log.Error(err)
return false
}
if auth2.HasRole(user, auth2.ROLE_SUPERADMIN) {
return true
}
if user.Id == s.OwnerID.String() {
return true
}
if auth2.IntersectsRoles(user, s.RolesRead...) {
return true
}
return false
}
func (s *Setting) UserHasUpdatePermission(cReg *components.Registry, ctx context.Context) bool {
user, err := auth2.ClientAuthMustReg(cReg).Plugin().Inspect(ctx)
if err != nil {
return false
}
if auth2.HasRole(user, auth2.ROLE_SUPERADMIN) {
return true
}
if user.Id == s.OwnerID.String() {
return true
}
if auth2.IntersectsRoles(user, s.RolesUpdate...) {
return true
}
return false
}
func SettingsCreate(cReg *components.Registry, ctx context.Context, in *settingspb.CreateRequest) (*Setting, error) {
var result Setting
if len(in.OwnerId) > 0 {
result.OwnerID = uuid.MustParse(in.OwnerId)
}
result.Service = in.Service
result.Name = in.Name
result.Content = in.Content
result.RolesRead = in.RolesRead
result.RolesUpdate = in.RolesUpdate
_, err := buncomponent.MustReg(cReg).Bun().NewInsert().Model(&result).Exec(ctx)
if err != nil {
return nil, err
}
return &result, nil
}
func SettingsUpdate(cReg *components.Registry, ctx context.Context, id, ownerID, service, name string, content json.RawMessage) (*Setting, error) {
// Fetch current setting
s, err := SettingsGet(cReg, ctx, id, ownerID, service, name)
if err != nil {
return nil, err
}
if !s.UserHasUpdatePermission(cReg, ctx) {
return nil, errors.New("unauthorized")
}
s.Content = content
s.UpdatedAt.Time = time.Now()
// Update
_, err = buncomponent.MustReg(cReg).Bun().NewUpdate().Model(s).Where("id = ?", s.ID).Exec(ctx)
if err != nil {
return nil, err
}
return s, nil
}
func SettingsUpsert(cReg *components.Registry, ctx context.Context, in *settingspb.UpsertRequest) (*Setting, error) {
s, err := SettingsUpdate(cReg, ctx, "", in.OwnerId, in.Service, in.Name, in.Content)
if err == nil {
return s, nil
}
req := settingspb.CreateRequest{}
req.Service = in.Service
req.Name = in.Name
req.Content = in.Content
req.RolesRead = in.RolesRead
req.RolesUpdate = in.RolesUpdate
return SettingsCreate(cReg, ctx, &req)
}
func SettingsGet(cReg *components.Registry, ctx context.Context, id, ownerID, service, name string) (*Setting, error) {
var result Setting
sql := buncomponent.MustReg(cReg).Bun().NewSelect().
Model(&result).
ColumnExpr("s.*").
Limit(1)
if len(id) > 1 {
sql.Where("id = ?", id)
} else if len(service) > 1 {
if len(name) > 1 {
sql.Where("service = ? AND name = ?", service, name)
} else {
sql.Where("service = ?", service)
}
} else if len(ownerID) > 1 {
if len(name) > 1 {
sql.Where("owner_id = ? AND name = ?", ownerID, name)
} else {
sql.Where("owner_id = ?", ownerID)
}
} else {
return nil, errors.New("not enough parameters")
}
err := sql.Scan(ctx)
if err != nil {
return nil, err
}
if !result.UserHasReadPermission(cReg, ctx) {
return nil, errors.New("unauthorized")
}
return &result, nil
}
func SettingsList(cReg *components.Registry, ctx context.Context, id, ownerID, service, name string, limit, offset uint64) ([]Setting, error) {
// Get the data from the db.
var settings []Setting
sql := buncomponent.MustReg(cReg).Bun().NewSelect().
Model(&settings).
ColumnExpr("s.*").
Limit(int(limit)).
Offset(int(offset))
if len(id) > 1 {
sql.Where("id = ?", id)
} else if len(service) > 1 {
if len(name) > 1 {
sql.Where("service = ? AND name = ?", service, name)
} else {
sql.Where("service = ?", service)
}
} else if len(ownerID) > 1 {
if len(name) > 1 {
sql.Where("owner_id = ? AND name = ?", ownerID, name)
} else {
sql.Where("owner_id = ?", ownerID)
}
}
err := sql.Scan(ctx)
if err != nil {
return nil, err
}
var result []Setting
for _, s := range settings {
if s.UserHasReadPermission(cReg, ctx) {
result = append(result, s)
}
}
return result, nil
}