mirror of
https://github.com/0xJacky/nginx-ui.git
synced 2025-05-10 18:05:48 +02:00
feat: add Lark and Lark Custom notification support
This commit is contained in:
parent
e364353cd1
commit
7a0972495f
17 changed files with 174 additions and 38 deletions
|
@ -4,6 +4,12 @@
|
|||
|
||||
const notifications: Record<string, { title: () => string, content: (args: any) => string }> = {
|
||||
|
||||
// user module notifications
|
||||
'All Recovery Codes Have Been Used': {
|
||||
title: () => $gettext('All Recovery Codes Have Been Used'),
|
||||
content: (args: any) => $gettext('Please generate new recovery codes in the preferences immediately to prevent lockout.', args),
|
||||
},
|
||||
|
||||
// cluster module notifications
|
||||
'Reload Remote Nginx Error': {
|
||||
title: () => $gettext('Reload Remote Nginx Error'),
|
||||
|
@ -149,12 +155,6 @@ const notifications: Record<string, { title: () => string, content: (args: any)
|
|||
title: () => $gettext('Save Remote Stream Success'),
|
||||
content: (args: any) => $gettext('Save stream %{name} to %{node} successfully', args),
|
||||
},
|
||||
|
||||
// user module notifications
|
||||
'All Recovery Codes Have Been Used': {
|
||||
title: () => $gettext('All Recovery Codes Have Been Used'),
|
||||
content: (args: any) => $gettext('Please generate new recovery codes in the preferences immediately to prevent lockout.', args),
|
||||
},
|
||||
}
|
||||
|
||||
export default notifications
|
||||
|
|
|
@ -26,7 +26,6 @@ const columns = computed<Column[]>(() => {
|
|||
type: input,
|
||||
config: {
|
||||
label: item.label,
|
||||
required: true,
|
||||
},
|
||||
},
|
||||
}))
|
||||
|
|
|
@ -6,11 +6,11 @@ const BarkConfig: ExternalNotifyConfig = {
|
|||
config: [
|
||||
{
|
||||
key: 'device_key',
|
||||
label: () => $gettext('Device Key'),
|
||||
label: 'Device Key',
|
||||
},
|
||||
{
|
||||
key: 'server_url',
|
||||
label: () => $gettext('Server URL'),
|
||||
label: 'Server URL',
|
||||
},
|
||||
],
|
||||
}
|
||||
|
|
|
@ -6,11 +6,11 @@ const DingTalkConfig: ExternalNotifyConfig = {
|
|||
config: [
|
||||
{
|
||||
key: 'access_token',
|
||||
label: () => $gettext('Access Token'),
|
||||
label: 'Access Token',
|
||||
},
|
||||
{
|
||||
key: 'secret',
|
||||
label: () => $gettext('Secret (Optional)'),
|
||||
label: 'Secret (Optional)',
|
||||
},
|
||||
],
|
||||
}
|
||||
|
|
|
@ -1,11 +1,15 @@
|
|||
// This file is auto-generated by notification generator. DO NOT EDIT.
|
||||
import BarkConfig from './bark'
|
||||
import DingTalkConfig from './dingtalk'
|
||||
import LarkConfig from './lark'
|
||||
import LarkCustomConfig from './lark_custom'
|
||||
import TelegramConfig from './telegram'
|
||||
|
||||
const configMap = {
|
||||
bark: BarkConfig,
|
||||
dingtalk: DingTalkConfig,
|
||||
lark: LarkConfig,
|
||||
lark_custom: LarkCustomConfig,
|
||||
telegram: TelegramConfig,
|
||||
}
|
||||
|
||||
|
|
14
app/src/views/preference/components/ExternalNotify/lark.ts
Normal file
14
app/src/views/preference/components/ExternalNotify/lark.ts
Normal file
|
@ -0,0 +1,14 @@
|
|||
// This file is auto-generated by notification generator. DO NOT EDIT.
|
||||
import type { ExternalNotifyConfig } from './types'
|
||||
|
||||
const LarkConfig: ExternalNotifyConfig = {
|
||||
name: () => $gettext('Lark'),
|
||||
config: [
|
||||
{
|
||||
key: 'webhook_url',
|
||||
label: 'Webhook URL',
|
||||
},
|
||||
],
|
||||
}
|
||||
|
||||
export default LarkConfig
|
|
@ -0,0 +1,38 @@
|
|||
// This file is auto-generated by notification generator. DO NOT EDIT.
|
||||
import type { ExternalNotifyConfig } from './types'
|
||||
|
||||
const LarkCustomConfig: ExternalNotifyConfig = {
|
||||
name: () => $gettext('Lark Custom'),
|
||||
config: [
|
||||
{
|
||||
key: 'app_id',
|
||||
label: 'App ID',
|
||||
},
|
||||
{
|
||||
key: 'app_secret',
|
||||
label: 'App Secret',
|
||||
},
|
||||
{
|
||||
key: 'open_id',
|
||||
label: 'Open ID',
|
||||
},
|
||||
{
|
||||
key: 'user_id',
|
||||
label: 'User ID',
|
||||
},
|
||||
{
|
||||
key: 'union_id',
|
||||
label: 'Union ID',
|
||||
},
|
||||
{
|
||||
key: 'email',
|
||||
label: 'Email',
|
||||
},
|
||||
{
|
||||
key: 'chat_id',
|
||||
label: 'Chat ID',
|
||||
},
|
||||
],
|
||||
}
|
||||
|
||||
export default LarkCustomConfig
|
|
@ -6,11 +6,11 @@ const TelegramConfig: ExternalNotifyConfig = {
|
|||
config: [
|
||||
{
|
||||
key: 'bot_token',
|
||||
label: () => $gettext('Bot Token'),
|
||||
label: 'Bot Token',
|
||||
},
|
||||
{
|
||||
key: 'chat_id',
|
||||
label: () => $gettext('Chat ID'),
|
||||
label: 'Chat ID',
|
||||
},
|
||||
],
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
export interface ExternalNotifyConfigItem {
|
||||
key: string
|
||||
label: () => string
|
||||
label: string
|
||||
}
|
||||
|
||||
export interface ExternalNotifyConfig {
|
||||
|
|
|
@ -0,0 +1,6 @@
|
|||
// This file is auto-generated by notification generator. DO NOT EDIT.
|
||||
|
||||
const configMap = {
|
||||
}
|
||||
|
||||
export default configMap
|
|
@ -32,23 +32,23 @@ type FieldInfo struct {
|
|||
const tsConfigTemplate = `// This file is auto-generated by notification generator. DO NOT EDIT.
|
||||
import type { ExternalNotifyConfig } from './types'
|
||||
|
||||
const {{.Name}}Config: ExternalNotifyConfig = {
|
||||
const {{.Name | replaceSpaces}}Config: ExternalNotifyConfig = {
|
||||
name: () => $gettext('{{.Name}}'),
|
||||
config: [
|
||||
{{- range .Fields}}
|
||||
{
|
||||
key: '{{.Key}}',
|
||||
label: () => $gettext('{{.Title}}'),
|
||||
label: '{{.Title}}',
|
||||
},
|
||||
{{- end}}
|
||||
],
|
||||
}
|
||||
|
||||
export default {{.Name}}Config
|
||||
export default {{.Name | replaceSpaces}}Config
|
||||
`
|
||||
|
||||
// Regular expression to extract @external_notifier annotation
|
||||
var externalNotifierRegex = regexp.MustCompile(`@external_notifier\((\w+)\)`)
|
||||
var externalNotifierRegex = regexp.MustCompile(`@external_notifier\(([a-zA-Z0-9 _]+)\)`)
|
||||
|
||||
func main() {
|
||||
if err := GenerateExternalNotifiers(); err != nil {
|
||||
|
@ -142,7 +142,7 @@ func extractNotifierInfo(filePath string) (NotifierInfo, bool) {
|
|||
if len(matches) > 1 {
|
||||
notifierInfo.Name = matches[1]
|
||||
notifierInfo.ConfigKey = strings.ToLower(typeSpec.Name.Name)
|
||||
notifierInfo.FileName = strings.ToLower(matches[1])
|
||||
notifierInfo.FileName = strings.ToLower(strings.ReplaceAll(matches[1], " ", "_"))
|
||||
found = true
|
||||
|
||||
// Extract fields
|
||||
|
@ -205,8 +205,15 @@ func extractNotifierInfo(filePath string) (NotifierInfo, bool) {
|
|||
|
||||
// Generate TypeScript config file for a notifier
|
||||
func generateTSConfig(notifier NotifierInfo, outputDir string) error {
|
||||
// Create template
|
||||
tmpl, err := template.New("tsConfig").Parse(tsConfigTemplate)
|
||||
// Create function map for template
|
||||
funcMap := template.FuncMap{
|
||||
"replaceSpaces": func(s string) string {
|
||||
return strings.ReplaceAll(s, " ", "")
|
||||
},
|
||||
}
|
||||
|
||||
// Create template with function map
|
||||
tmpl, err := template.New("tsConfig").Funcs(funcMap).Parse(tsConfigTemplate)
|
||||
if err != nil {
|
||||
return fmt.Errorf("error creating template: %w", err)
|
||||
}
|
||||
|
@ -242,7 +249,7 @@ func updateIndexFile(notifiers []NotifierInfo, outputDir string) error {
|
|||
|
||||
for _, notifier := range notifiers {
|
||||
fileName := notifier.FileName
|
||||
configName := notifier.Name + "Config"
|
||||
configName := strings.ReplaceAll(notifier.Name, " ", "") + "Config"
|
||||
|
||||
imports.WriteString(fmt.Sprintf("import %s from './%s'\n", configName, fileName))
|
||||
}
|
||||
|
@ -250,7 +257,8 @@ func updateIndexFile(notifiers []NotifierInfo, outputDir string) error {
|
|||
// Generate the map
|
||||
configMap.WriteString("const configMap = {\n")
|
||||
for _, notifier := range notifiers {
|
||||
configMap.WriteString(fmt.Sprintf(" %s: %sConfig", strings.ToLower(notifier.Name), notifier.Name))
|
||||
configKey := strings.ToLower(strings.ReplaceAll(notifier.Name, " ", "_"))
|
||||
configMap.WriteString(fmt.Sprintf(" %s: %sConfig", configKey, strings.ReplaceAll(notifier.Name, " ", "")))
|
||||
configMap.WriteString(",\n")
|
||||
}
|
||||
configMap.WriteString("}\n")
|
||||
|
|
|
@ -4,7 +4,6 @@ import (
|
|||
"context"
|
||||
|
||||
"github.com/0xJacky/Nginx-UI/model"
|
||||
"github.com/nikoksr/notify"
|
||||
"github.com/nikoksr/notify/service/bark"
|
||||
"github.com/uozi-tech/cosy/map2struct"
|
||||
)
|
||||
|
@ -26,8 +25,6 @@ func init() {
|
|||
return ErrInvalidNotifierConfig
|
||||
}
|
||||
barkService := bark.NewWithServers(barkConfig.DeviceKey, barkConfig.ServerURL)
|
||||
externalNotify := notify.New()
|
||||
externalNotify.UseServices(barkService)
|
||||
return externalNotify.Send(ctx, msg.GetTitle(n.Language), msg.GetContent(n.Language))
|
||||
return barkService.Send(ctx, msg.GetTitle(n.Language), msg.GetContent(n.Language))
|
||||
})
|
||||
}
|
||||
|
|
|
@ -4,7 +4,6 @@ import (
|
|||
"context"
|
||||
|
||||
"github.com/0xJacky/Nginx-UI/model"
|
||||
"github.com/nikoksr/notify"
|
||||
"github.com/nikoksr/notify/service/dingding"
|
||||
"github.com/uozi-tech/cosy/map2struct"
|
||||
)
|
||||
|
@ -31,9 +30,6 @@ func init() {
|
|||
Token: dingTalkConfig.AccessToken,
|
||||
Secret: dingTalkConfig.Secret,
|
||||
})
|
||||
// Use the service
|
||||
externalNotify := notify.New()
|
||||
externalNotify.UseServices(dingTalkService)
|
||||
return externalNotify.Send(ctx, msg.GetTitle(n.Language), msg.GetContent(n.Language))
|
||||
return dingTalkService.Send(ctx, msg.GetTitle(n.Language), msg.GetContent(n.Language))
|
||||
})
|
||||
}
|
||||
|
|
30
internal/notification/lark.go
Normal file
30
internal/notification/lark.go
Normal file
|
@ -0,0 +1,30 @@
|
|||
package notification
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/0xJacky/Nginx-UI/model"
|
||||
"github.com/nikoksr/notify/service/lark"
|
||||
"github.com/uozi-tech/cosy/map2struct"
|
||||
)
|
||||
|
||||
// @external_notifier(Lark)
|
||||
type Lark struct {
|
||||
WebhookURL string `json:"webhook_url" title:"Webhook URL"`
|
||||
}
|
||||
|
||||
func init() {
|
||||
RegisterExternalNotifier("lark", func(ctx context.Context, n *model.ExternalNotify, msg *ExternalMessage) error {
|
||||
larkConfig := &Lark{}
|
||||
err := map2struct.WeakDecode(n.Config, larkConfig)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if larkConfig.WebhookURL == "" {
|
||||
return ErrInvalidNotifierConfig
|
||||
}
|
||||
|
||||
larkService := lark.NewWebhookService(larkConfig.WebhookURL)
|
||||
return larkService.Send(ctx, msg.GetTitle(n.Language), msg.GetContent(n.Language))
|
||||
})
|
||||
}
|
43
internal/notification/lark_custom.go
Normal file
43
internal/notification/lark_custom.go
Normal file
|
@ -0,0 +1,43 @@
|
|||
package notification
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/0xJacky/Nginx-UI/model"
|
||||
"github.com/nikoksr/notify/service/lark"
|
||||
"github.com/uozi-tech/cosy/map2struct"
|
||||
)
|
||||
|
||||
// @external_notifier(Lark Custom)
|
||||
type LarkCustom struct {
|
||||
AppID string `json:"app_id" title:"App ID"`
|
||||
AppSecret string `json:"app_secret" title:"App Secret"`
|
||||
OpenID string `json:"open_id" title:"Open ID"`
|
||||
UserID string `json:"user_id" title:"User ID"`
|
||||
UnionID string `json:"union_id" title:"Union ID"`
|
||||
Email string `json:"email" title:"Email"`
|
||||
ChatID string `json:"chat_id" title:"Chat ID"`
|
||||
}
|
||||
|
||||
func init() {
|
||||
RegisterExternalNotifier("lark_custom", func(ctx context.Context, n *model.ExternalNotify, msg *ExternalMessage) error {
|
||||
larkCustomConfig := &LarkCustom{}
|
||||
err := map2struct.WeakDecode(n.Config, larkCustomConfig)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if larkCustomConfig.AppID == "" || larkCustomConfig.AppSecret == "" {
|
||||
return ErrInvalidNotifierConfig
|
||||
}
|
||||
|
||||
larkCustomAppService := lark.NewCustomAppService(larkCustomConfig.AppID, larkCustomConfig.AppSecret)
|
||||
larkCustomAppService.AddReceivers(
|
||||
lark.OpenID(larkCustomConfig.OpenID),
|
||||
lark.UserID(larkCustomConfig.UserID),
|
||||
lark.UnionID(larkCustomConfig.UnionID),
|
||||
lark.Email(larkCustomConfig.Email),
|
||||
lark.ChatID(larkCustomConfig.ChatID),
|
||||
)
|
||||
return larkCustomAppService.Send(ctx, msg.GetTitle(n.Language), msg.GetContent(n.Language))
|
||||
})
|
||||
}
|
|
@ -7,7 +7,6 @@ import (
|
|||
"strconv"
|
||||
|
||||
"github.com/0xJacky/Nginx-UI/model"
|
||||
"github.com/nikoksr/notify"
|
||||
"github.com/nikoksr/notify/service/telegram"
|
||||
"github.com/uozi-tech/cosy/map2struct"
|
||||
)
|
||||
|
@ -46,9 +45,7 @@ func init() {
|
|||
}
|
||||
|
||||
telegramService.AddReceivers(chatIDInt)
|
||||
|
||||
externalNotify := notify.New()
|
||||
externalNotify.UseServices(telegramService)
|
||||
return externalNotify.Send(ctx, msg.GetTitle(n.Language), msg.GetContent(n.Language))
|
||||
|
||||
return telegramService.Send(ctx, msg.GetTitle(n.Language), msg.GetContent(n.Language))
|
||||
})
|
||||
}
|
||||
|
|
|
@ -33,6 +33,7 @@ func newExternalNotify(db *gorm.DB, opts ...gen.DOOption) externalNotify {
|
|||
_externalNotify.UpdatedAt = field.NewTime(tableName, "updated_at")
|
||||
_externalNotify.DeletedAt = field.NewField(tableName, "deleted_at")
|
||||
_externalNotify.Type = field.NewString(tableName, "type")
|
||||
_externalNotify.Language = field.NewString(tableName, "language")
|
||||
_externalNotify.Config = field.NewField(tableName, "config")
|
||||
|
||||
_externalNotify.fillFieldMap()
|
||||
|
@ -49,6 +50,7 @@ type externalNotify struct {
|
|||
UpdatedAt field.Time
|
||||
DeletedAt field.Field
|
||||
Type field.String
|
||||
Language field.String
|
||||
Config field.Field
|
||||
|
||||
fieldMap map[string]field.Expr
|
||||
|
@ -71,6 +73,7 @@ func (e *externalNotify) updateTableName(table string) *externalNotify {
|
|||
e.UpdatedAt = field.NewTime(table, "updated_at")
|
||||
e.DeletedAt = field.NewField(table, "deleted_at")
|
||||
e.Type = field.NewString(table, "type")
|
||||
e.Language = field.NewString(table, "language")
|
||||
e.Config = field.NewField(table, "config")
|
||||
|
||||
e.fillFieldMap()
|
||||
|
@ -88,12 +91,13 @@ func (e *externalNotify) GetFieldByName(fieldName string) (field.OrderExpr, bool
|
|||
}
|
||||
|
||||
func (e *externalNotify) fillFieldMap() {
|
||||
e.fieldMap = make(map[string]field.Expr, 6)
|
||||
e.fieldMap = make(map[string]field.Expr, 7)
|
||||
e.fieldMap["id"] = e.ID
|
||||
e.fieldMap["created_at"] = e.CreatedAt
|
||||
e.fieldMap["updated_at"] = e.UpdatedAt
|
||||
e.fieldMap["deleted_at"] = e.DeletedAt
|
||||
e.fieldMap["type"] = e.Type
|
||||
e.fieldMap["language"] = e.Language
|
||||
e.fieldMap["config"] = e.Config
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue