mirror of
https://github.com/cuigh/swirl
synced 2024-12-28 14:51:57 +00:00
Refactor setting module
This commit is contained in:
parent
bb48beec82
commit
62bbe9254d
@ -1,10 +1,8 @@
|
||||
package api
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
|
||||
"github.com/cuigh/auxo/data"
|
||||
"github.com/cuigh/auxo/net/web"
|
||||
"github.com/cuigh/swirl/biz"
|
||||
)
|
||||
@ -42,15 +40,8 @@ func settingSave(b biz.SettingBiz) web.HandlerFunc {
|
||||
return func(ctx web.Context) (err error) {
|
||||
args := &Args{}
|
||||
err = ctx.Bind(args)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
options := data.Map{}
|
||||
d := json.NewDecoder(bytes.NewBuffer(args.Options))
|
||||
d.UseNumber()
|
||||
if err = d.Decode(&options); err == nil {
|
||||
err = b.Save(args.ID, options, ctx.User())
|
||||
if err == nil {
|
||||
err = b.Save(args.ID, args.Options, ctx.User())
|
||||
}
|
||||
return ajax(ctx, err)
|
||||
}
|
||||
|
@ -1,22 +1,21 @@
|
||||
package biz
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"encoding/json"
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
"github.com/cuigh/auxo/data"
|
||||
"github.com/cuigh/auxo/net/web"
|
||||
"github.com/cuigh/auxo/util/cast"
|
||||
"github.com/cuigh/swirl/dao"
|
||||
"github.com/cuigh/swirl/model"
|
||||
)
|
||||
|
||||
type SettingBiz interface {
|
||||
Find(id string) (options data.Map, err error)
|
||||
Find(id string) (options interface{}, err error)
|
||||
Load() (options data.Map, err error)
|
||||
Save(id string, options data.Map, user web.User) (err error)
|
||||
Save(id string, options interface{}, user web.User) (err error)
|
||||
}
|
||||
|
||||
func NewSetting(d dao.Interface, eb EventBiz) SettingBiz {
|
||||
@ -28,17 +27,11 @@ type settingBiz struct {
|
||||
eb EventBiz
|
||||
}
|
||||
|
||||
func (b *settingBiz) Find(id string) (options data.Map, err error) {
|
||||
func (b *settingBiz) Find(id string) (options interface{}, err error) {
|
||||
var setting *model.Setting
|
||||
setting, err = b.d.SettingGet(context.TODO(), id)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
if setting != nil {
|
||||
options = b.toMap(setting.Options)
|
||||
} else {
|
||||
options = make(data.Map)
|
||||
if err == nil && setting != nil {
|
||||
return b.unmarshal(setting.Options)
|
||||
}
|
||||
return
|
||||
}
|
||||
@ -53,82 +46,45 @@ func (b *settingBiz) Load() (options data.Map, err error) {
|
||||
|
||||
options = data.Map{}
|
||||
for _, s := range settings {
|
||||
options[s.ID] = b.toMap(s.Options)
|
||||
var v interface{}
|
||||
if v, err = b.unmarshal(s.Options); err != nil {
|
||||
return
|
||||
}
|
||||
options[s.ID] = v
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (b *settingBiz) Save(id string, options data.Map, user web.User) (err error) {
|
||||
func (b *settingBiz) Save(id string, options interface{}, user web.User) (err error) {
|
||||
setting := &model.Setting{
|
||||
ID: id,
|
||||
Options: b.toOptions(options),
|
||||
UpdatedAt: time.Now(),
|
||||
}
|
||||
if user != nil {
|
||||
setting.UpdatedBy = model.Operator{ID: user.ID(), Name: user.Name()}
|
||||
}
|
||||
|
||||
setting.Options, err = b.marshal(options)
|
||||
if err == nil {
|
||||
err = b.d.SettingUpdate(context.TODO(), setting)
|
||||
}
|
||||
if err == nil && user != nil {
|
||||
b.eb.CreateSetting(EventActionUpdate, user)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (b *settingBiz) toOptions(m data.Map) []*model.SettingOption {
|
||||
var opts []*model.SettingOption
|
||||
for k, v := range m {
|
||||
opt := &model.SettingOption{Name: k}
|
||||
switch v.(type) {
|
||||
case bool:
|
||||
opt.Type = "bool"
|
||||
opt.Value = strconv.FormatBool(v.(bool))
|
||||
case json.Number:
|
||||
opt.Type = "number"
|
||||
opt.Value = cast.ToString(v)
|
||||
case string:
|
||||
opt.Type = "string"
|
||||
opt.Value = v.(string)
|
||||
default:
|
||||
opt.Type = "json"
|
||||
opt.Value = b.toJSON(v)
|
||||
func (b *settingBiz) marshal(v interface{}) (s string, err error) {
|
||||
var buf []byte
|
||||
if buf, err = json.Marshal(v); err == nil {
|
||||
s = string(buf)
|
||||
}
|
||||
opts = append(opts, opt)
|
||||
}
|
||||
return opts
|
||||
return
|
||||
}
|
||||
|
||||
func (b *settingBiz) toMap(options []*model.SettingOption) data.Map {
|
||||
m := data.Map{}
|
||||
for _, opt := range options {
|
||||
var v interface{}
|
||||
switch opt.Type {
|
||||
case "bool":
|
||||
v = opt.Value == "true"
|
||||
case "number":
|
||||
v = cast.ToInt32(opt.Value)
|
||||
case "string":
|
||||
v = opt.Value
|
||||
default:
|
||||
v = b.fromJSON(opt.Value)
|
||||
}
|
||||
m[opt.Name] = v
|
||||
}
|
||||
return m
|
||||
}
|
||||
|
||||
func (b *settingBiz) toJSON(v interface{}) string {
|
||||
d, err := json.Marshal(v)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return string(d)
|
||||
}
|
||||
|
||||
func (b *settingBiz) fromJSON(v string) interface{} {
|
||||
var i interface{}
|
||||
err := json.Unmarshal([]byte(v), &i)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return i
|
||||
func (b *settingBiz) unmarshal(s string) (v interface{}, err error) {
|
||||
d := json.NewDecoder(bytes.NewBuffer([]byte(s)))
|
||||
d.UseNumber()
|
||||
err = d.Decode(&v)
|
||||
return
|
||||
}
|
||||
|
@ -79,7 +79,7 @@ func newInterface() (i Interface) {
|
||||
case "bolt":
|
||||
i, err = bolt.New(misc.Options.DBAddress)
|
||||
default:
|
||||
err = errors.New("Unknown database type: " + misc.Options.DBType)
|
||||
err = errors.New("unknown database type: " + misc.Options.DBType)
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
|
13
main.go
13
main.go
@ -2,6 +2,7 @@ package main
|
||||
|
||||
import (
|
||||
"embed"
|
||||
"encoding/json"
|
||||
"io/fs"
|
||||
"net/http"
|
||||
"strings"
|
||||
@ -10,7 +11,7 @@ import (
|
||||
"github.com/cuigh/auxo/app/container"
|
||||
"github.com/cuigh/auxo/app/flag"
|
||||
_ "github.com/cuigh/auxo/cache/memory"
|
||||
"github.com/cuigh/auxo/config"
|
||||
"github.com/cuigh/auxo/data"
|
||||
"github.com/cuigh/auxo/data/valid"
|
||||
"github.com/cuigh/auxo/errors"
|
||||
"github.com/cuigh/auxo/log"
|
||||
@ -103,12 +104,14 @@ func initSystem() error {
|
||||
func loadSetting(sb biz.SettingBiz) *misc.Setting {
|
||||
var (
|
||||
err error
|
||||
opts data.Map
|
||||
b []byte
|
||||
s = &misc.Setting{}
|
||||
)
|
||||
|
||||
config.AddSource(sb)
|
||||
if err = config.Load(); err == nil {
|
||||
err = config.Unmarshal(s)
|
||||
if opts, err = sb.Load(); err == nil {
|
||||
if b, err = json.Marshal(opts); err == nil {
|
||||
err = json.Unmarshal(b, s)
|
||||
}
|
||||
}
|
||||
if err != nil {
|
||||
log.Get("misc").Error("failed to load setting: ", err)
|
||||
|
@ -49,28 +49,24 @@ func LoadOptions() (err error) {
|
||||
// Setting represents the settings of Swirl.
|
||||
type Setting struct {
|
||||
System struct {
|
||||
Version string
|
||||
}
|
||||
Region struct {
|
||||
Language string `option:"lang"`
|
||||
Timezone int32
|
||||
}
|
||||
Version string `json:"version"`
|
||||
} `json:"system"`
|
||||
LDAP struct {
|
||||
Enabled bool
|
||||
Address string
|
||||
Security int32 // 0, 1, 2
|
||||
Authentication string `option:"auth"` // simple, bind
|
||||
BindDN string
|
||||
BindPassword string `option:"bind_pwd"` // Bind DN password
|
||||
BaseDN string // Base search path for users
|
||||
UserDN string // Template for the DN of the user for simple auth
|
||||
UserFilter string // Search filter for user
|
||||
NameAttr string
|
||||
EmailAttr string
|
||||
}
|
||||
Enabled bool `json:"enabled"`
|
||||
Address string `json:"address"`
|
||||
Security int32 `json:"security"` // 0, 1, 2
|
||||
Authentication string `json:"auth"` // simple, bind
|
||||
BindDN string `json:"bind_dn"`
|
||||
BindPassword string `json:"bind_pwd"` // Bind DN password
|
||||
BaseDN string `json:"base_dn"` // Base search path for users
|
||||
UserDN string `json:"user_dn"` // Template for the DN of the user for simple auth
|
||||
UserFilter string `json:"user_filter"` // Search filter for user
|
||||
NameAttr string `json:"name_attr"`
|
||||
EmailAttr string `json:"email_attr"`
|
||||
} `json:"ldap"`
|
||||
Metric struct {
|
||||
Prometheus string
|
||||
}
|
||||
Prometheus string `json:"prometheus"`
|
||||
} `json:"metric"`
|
||||
}
|
||||
|
||||
func init() {
|
||||
|
@ -59,17 +59,11 @@ type Operator struct {
|
||||
// Setting represents the options of swirl.
|
||||
type Setting struct {
|
||||
ID string `json:"id" bson:"_id"`
|
||||
Options []*SettingOption `json:"options" bson:"options"`
|
||||
Options string `json:"options" bson:"options"`
|
||||
UpdatedAt time.Time `json:"updatedAt" bson:"updated_at"`
|
||||
UpdatedBy Operator `json:"updatedBy" bson:"updated_by"`
|
||||
}
|
||||
|
||||
type SettingOption struct {
|
||||
Name string `json:"name" bson:"name"`
|
||||
Value string `json:"value" bson:"value"`
|
||||
Type string `json:"type" bson:"type"`
|
||||
}
|
||||
|
||||
type Role struct {
|
||||
ID string `json:"id,omitempty" bson:"_id"`
|
||||
Name string `json:"name,omitempty" bson:"name" valid:"required"`
|
||||
|
@ -1,14 +1,17 @@
|
||||
import ajax, { Result } from './ajax'
|
||||
|
||||
export interface Setting {
|
||||
region: RegionSetting;
|
||||
ldap: LdapSetting;
|
||||
metric: MetricSetting;
|
||||
deploy: DeployOptions;
|
||||
}
|
||||
|
||||
export interface RegionSetting {
|
||||
lang: string;
|
||||
timezone: number;
|
||||
export interface DeployOptions {
|
||||
keys: {
|
||||
name: string;
|
||||
token: string;
|
||||
expiry: number;
|
||||
}[];
|
||||
}
|
||||
|
||||
export interface LdapSetting {
|
||||
|
@ -73,7 +73,16 @@ const columns = [
|
||||
fixed: "left" as const,
|
||||
render: (c: Container) => {
|
||||
const node = c.labels?.find(l => l.name === 'com.docker.swarm.node.id')
|
||||
return renderLink({ name: 'container_detail', params: { id: c.id, node: node?.value || '-' } }, c.name)
|
||||
const name = c.name.length > 32 ? c.name.substring(0, 32) + '...' : c.name
|
||||
return renderLink({ name: 'container_detail', params: { id: c.id, node: node?.value || '-' } }, name)
|
||||
},
|
||||
},
|
||||
{
|
||||
title: t('objects.service'),
|
||||
key: "service",
|
||||
render: (c: Container) => {
|
||||
const service = c.labels?.find(l => l.name === 'com.docker.swarm.service.name')?.value
|
||||
return service ? renderLink({ name: 'service_detail', params: { name: service } }, service) : ''
|
||||
},
|
||||
},
|
||||
{
|
||||
|
@ -1,36 +1,36 @@
|
||||
<template>
|
||||
<x-page-header />
|
||||
<n-space class="page-body" vertical :size="12">
|
||||
<x-panel title="Region" divider="bottom" :collapsed="panel !== 'region'" v-if="false">
|
||||
<x-panel title="Deployment" divider="bottom" :collapsed="panel !== 'deploy'" v-if="false">
|
||||
<template #action>
|
||||
<n-button
|
||||
secondary
|
||||
strong
|
||||
class="toggle"
|
||||
size="small"
|
||||
@click="togglePanel('region')"
|
||||
>{{ panel === 'region' ? t('buttons.collapse') : t('buttons.expand') }}</n-button>
|
||||
@click="togglePanel('deploy')"
|
||||
>{{ panel === 'deploy' ? t('buttons.collapse') : t('buttons.expand') }}</n-button>
|
||||
</template>
|
||||
<div style="padding: 4px 0 0 12px">
|
||||
<n-form
|
||||
inline
|
||||
:model="setting"
|
||||
ref="formRegion"
|
||||
label-placement="left"
|
||||
:show-feedback="false"
|
||||
<n-form :model="setting" ref="formDeploy" :show-feedback="false">
|
||||
<n-form-item :label="t('fields.keys')" path="deploy.keys">
|
||||
<n-dynamic-input
|
||||
v-model:value="setting.deploy.keys"
|
||||
#="{ index, value }"
|
||||
:on-create="newKey"
|
||||
>
|
||||
<n-form-item label="Timezone" path="region.timezone">
|
||||
<n-select
|
||||
v-model:value="setting.region.timezone"
|
||||
:options="timezones"
|
||||
style="width: 240px"
|
||||
/>
|
||||
<n-input-group>
|
||||
<n-input :placeholder="t('fields.name')" v-model:value="value.name" />
|
||||
<n-input :placeholder="t('fields.token')" v-model:value="value.token" />
|
||||
<n-date-picker :placeholder="t('fields.expiry')" v-model:value="value.expiry" type="date" clearable style="min-width: 200px"/>
|
||||
</n-input-group>
|
||||
</n-dynamic-input>
|
||||
</n-form-item>
|
||||
</n-form>
|
||||
<n-button
|
||||
type="primary"
|
||||
style="margin-top: 12px"
|
||||
@click="() => save('region', setting.region)"
|
||||
@click="() => save('deploy', setting.deploy)"
|
||||
>{{ t('buttons.save') }}</n-button>
|
||||
</div>
|
||||
</x-panel>
|
||||
@ -55,10 +55,7 @@
|
||||
<n-switch v-model:value="setting.ldap.enabled" />
|
||||
</n-form-item>
|
||||
<n-form-item :label="t('fields.address')" path="ldap.address" label-align="right">
|
||||
<n-input
|
||||
:placeholder="t('tips.ldap_address')"
|
||||
v-model:value="setting.ldap.address"
|
||||
/>
|
||||
<n-input :placeholder="t('tips.ldap_address')" v-model:value="setting.ldap.address" />
|
||||
</n-form-item>
|
||||
<n-form-item :label="t('fields.security')" path="ldap.security">
|
||||
<n-radio-group v-model:value="setting.ldap.security">
|
||||
@ -79,10 +76,7 @@
|
||||
label-align="right"
|
||||
v-show="setting.ldap.auth === 'simple'"
|
||||
>
|
||||
<n-input
|
||||
:placeholder="t('tips.ldap_user_dn')"
|
||||
v-model:value="setting.ldap.user_dn"
|
||||
/>
|
||||
<n-input :placeholder="t('tips.ldap_user_dn')" v-model:value="setting.ldap.user_dn" />
|
||||
</n-form-item>
|
||||
<n-form-item
|
||||
:label="t('fields.bind_dn')"
|
||||
@ -103,16 +97,17 @@
|
||||
<n-form-item-gi path="ldap.bind_pwd">
|
||||
<n-input-group>
|
||||
<n-input-group-label style="min-width: 60px">{{ t('fields.password') }}</n-input-group-label>
|
||||
<n-input type="password" :placeholder="t('tips.ldap_bind_pwd')" v-model:value="setting.ldap.bind_pwd" />
|
||||
<n-input
|
||||
type="password"
|
||||
:placeholder="t('tips.ldap_bind_pwd')"
|
||||
v-model:value="setting.ldap.bind_pwd"
|
||||
/>
|
||||
</n-input-group>
|
||||
</n-form-item-gi>
|
||||
</n-grid>
|
||||
</n-form-item>
|
||||
<n-form-item :label="t('fields.base_dn')" path="ldap.base_dn" label-align="right">
|
||||
<n-input
|
||||
:placeholder="t('tips.ldap_base_dn')"
|
||||
v-model:value="setting.ldap.base_dn"
|
||||
/>
|
||||
<n-input :placeholder="t('tips.ldap_base_dn')" v-model:value="setting.ldap.base_dn" />
|
||||
</n-form-item>
|
||||
<n-form-item :label="t('fields.user_filter')" path="ldap.user_filter" label-align="right">
|
||||
<n-input
|
||||
@ -160,10 +155,7 @@
|
||||
style="padding: 4px 0 0 12px"
|
||||
>
|
||||
<n-form-item label="Prometheus" path="metric.prometheus" label-align="right">
|
||||
<n-input
|
||||
:placeholder="t('tips.prometheus')"
|
||||
v-model:value="setting.metric.prometheus"
|
||||
/>
|
||||
<n-input :placeholder="t('tips.prometheus')" v-model:value="setting.metric.prometheus" />
|
||||
</n-form-item>
|
||||
<n-button
|
||||
type="primary"
|
||||
@ -189,9 +181,10 @@ import {
|
||||
NFormItemGi,
|
||||
NRadioGroup,
|
||||
NRadio,
|
||||
NSelect,
|
||||
NDynamicInput,
|
||||
NSwitch,
|
||||
NAlert,
|
||||
NDatePicker,
|
||||
} from "naive-ui";
|
||||
import XPageHeader from "@/components/PageHeader.vue";
|
||||
import XPanel from "@/components/Panel.vue";
|
||||
@ -201,41 +194,13 @@ import { useI18n } from 'vue-i18n'
|
||||
|
||||
const { t } = useI18n()
|
||||
const setting = ref({
|
||||
region: {
|
||||
timezone: 8,
|
||||
},
|
||||
ldap: {
|
||||
security: 0,
|
||||
auth: 'simple',
|
||||
},
|
||||
metric: {},
|
||||
deploy: {},
|
||||
} as Setting);
|
||||
const timezones = [
|
||||
{ label: 'UTC-11(Pacific/Midway)', value: -11 },
|
||||
{ label: 'UTC-10(Pacific/Honolulu)', value: -10 },
|
||||
{ label: 'UTC-9(America/Anchorage)', value: -9 },
|
||||
{ label: 'UTC-8(America/Los_Angeles)', value: -8 },
|
||||
{ label: 'UTC-7(America/Phoenix)', value: -7 },
|
||||
{ label: 'UTC-6(America/Regina)', value: -6 },
|
||||
{ label: 'UTC-5(America/Panama)', value: -5 },
|
||||
{ label: 'UTC-4(America/Asuncion)', value: -4 },
|
||||
{ label: 'UTC-3(America/Bahia)', value: -3 },
|
||||
{ label: 'UTC-2(America/Noronha)', value: -2 },
|
||||
{ label: 'UTC-1(Atlantic/Cape_Verde)', value: -1 },
|
||||
{ label: 'UTC(Europe/London)', value: 0 },
|
||||
{ label: 'UTC+1(Africa/Algiers)', value: 1 },
|
||||
{ label: 'UTC+2(Africa/Cairo)', value: 2 },
|
||||
{ label: 'UTC+3(Europe/Moscow)', value: 3 },
|
||||
{ label: 'UTC+4(Indian/Mahe)', value: 4 },
|
||||
{ label: 'UTC+5(Asia/Karachi)', value: 5 },
|
||||
{ label: 'UTC+6(Asia/Almaty)', value: 6 },
|
||||
{ label: 'UTC+7(Asia/Bangkok)', value: 7 },
|
||||
{ label: 'UTC+8(Asia/Shanghai)', value: 8 },
|
||||
{ label: 'UTC+9(Asia/Tokyo)', value: 9 },
|
||||
{ label: 'UTC+10(Australia/Sydney)', value: 10 },
|
||||
{ label: 'UTC+11(Pacific/Efate)', value: 11 },
|
||||
{ label: 'UTC+12(Asia/Anadyr)', value: 12 },
|
||||
]
|
||||
const panel = ref('')
|
||||
|
||||
function togglePanel(name: string) {
|
||||
@ -246,6 +211,10 @@ function togglePanel(name: string) {
|
||||
}
|
||||
}
|
||||
|
||||
function newKey() {
|
||||
return { name: '', token: '', expiry: undefined }
|
||||
}
|
||||
|
||||
async function save(id: string, options: any) {
|
||||
await settingApi.save(id, options)
|
||||
window.message.info(t('texts.action_success'));
|
||||
|
Loading…
Reference in New Issue
Block a user