@@ -121,25 +129,45 @@ const log = computed(() => {
-
+
+
+
+
+
-
+
+
+ {{ data.name }}
+
+
+
-
+
+ {{ data.ssl_certificate_path }}
+
+
-
+
+ {{ data.ssl_certificate_key_path }}
+
+
{
})"
>
-
+import { useGettext } from 'vue3-gettext'
+import { message } from 'ant-design-vue'
+import StdCurd from '@/components/StdDesign/StdDataDisplay/StdCurd.vue'
+import notification from '@/api/notification'
+import type { Column } from '@/components/StdDesign/types'
+import type { customRender } from '@/components/StdDesign/StdDataDisplay/StdTableTransformer'
+import { datetime, mask } from '@/components/StdDesign/StdDataDisplay/StdTableTransformer'
+import { NotificationType } from '@/constants'
+import { useUserStore } from '@/pinia'
+
+const { $gettext } = useGettext()
+
+const columns: Column[] = [{
+ title: () => $gettext('Type'),
+ dataIndex: 'type',
+ customRender: (args: customRender) => mask(args, NotificationType),
+ sortable: true,
+ pithy: true,
+}, {
+ title: () => $gettext('Title'),
+ dataIndex: 'title',
+ customRender: (args: customRender) => {
+ return h('span', $gettext(args.text))
+ },
+ pithy: true,
+}, {
+ title: () => $gettext('Details'),
+ dataIndex: 'details',
+ pithy: true,
+}, {
+ title: () => $gettext('Created at'),
+ dataIndex: 'created_at',
+ sortable: true,
+ customRender: datetime,
+ pithy: true,
+}, {
+ title: () => $gettext('Action'),
+ dataIndex: 'action',
+}]
+
+const { unreadCount } = storeToRefs(useUserStore())
+
+const curd = ref()
+function clear() {
+ notification.clear().then(() => {
+ message.success($gettext('Cleared successfully'))
+ curd.value.get_list()
+ unreadCount.value = 0
+ }).catch(e => {
+ message.error($gettext(e?.message ?? 'Server error'))
+ })
+}
+
+watch(unreadCount, () => {
+ curd.value.get_list()
+})
+
+
+
+
+
+
+
+ {{ $gettext('Clear') }}
+
+
+
+
+
+
+
diff --git a/cmd/generate/generate.go b/cmd/generate/generate.go
index 3f5f63d9..1e5c1e9d 100644
--- a/cmd/generate/generate.go
+++ b/cmd/generate/generate.go
@@ -17,7 +17,7 @@ func main() {
// specify the output directory (default: "./query")
// ### if you want to query without context constrain, set mode gen.WithoutContext ###
g := gen.NewGenerator(gen.Config{
- OutPath: "../../server/query",
+ OutPath: "../../query",
Mode: gen.WithoutContext | gen.WithDefaultQuery,
//if you want the nullable field generation property to be pointer type, set FieldNullable true
FieldNullable: true,
diff --git a/internal/cert/auto_cert.go b/internal/cert/auto_cert.go
index 2cb5dcb4..7787b6fb 100644
--- a/internal/cert/auto_cert.go
+++ b/internal/cert/auto_cert.go
@@ -2,8 +2,10 @@ package cert
import (
"github.com/0xJacky/Nginx-UI/internal/logger"
+ "github.com/0xJacky/Nginx-UI/internal/notification"
"github.com/0xJacky/Nginx-UI/model"
"github.com/pkg/errors"
+ "runtime"
"strings"
"time"
)
@@ -11,7 +13,9 @@ import (
func AutoObtain() {
defer func() {
if err := recover(); err != nil {
- logger.Error("AutoCert Recover", err)
+ buf := make([]byte, 1024)
+ runtime.Stack(buf, false)
+ logger.Error("AutoCert Recover", err, string(buf))
}
}()
logger.Info("AutoCert Worker Started")
@@ -38,21 +42,29 @@ func renew(certModel *model.Cert) {
if len(certModel.Domains) == 0 {
log.Error(errors.New("domains list is empty, " +
"try to reopen auto-cert for this config:" + confName))
+ notification.Error("Renew Certificate Error", confName)
return
}
- if certModel.SSLCertificatePath != "" {
- cert, err := GetCertInfo(certModel.SSLCertificatePath)
- if err != nil {
- // Get certificate info error, ignore this certificate
- log.Error(errors.Wrap(err, "get certificate info error"))
- return
- }
- if time.Now().Sub(cert.NotBefore).Hours()/24 < 7 {
- // not between 1 week, ignore this certificate
- return
- }
+ if certModel.SSLCertificatePath == "" {
+ log.Error(errors.New("ssl certificate path is empty, " +
+ "try to reopen auto-cert for this config:" + confName))
+ notification.Error("Renew Certificate Error", confName)
+ return
}
+
+ cert, err := GetCertInfo(certModel.SSLCertificatePath)
+ if err != nil {
+ // Get certificate info error, ignore this certificate
+ log.Error(errors.Wrap(err, "get certificate info error"))
+ notification.Error("Renew Certificate Error", strings.Join(certModel.Domains, ", "))
+ return
+ }
+ if time.Now().Sub(cert.NotBefore).Hours()/24 < 7 {
+ // not between 1 week, ignore this certificate
+ return
+ }
+
// after 1 mo, reissue certificate
logChan := make(chan string, 1)
errChan := make(chan error, 1)
@@ -76,5 +88,9 @@ func renew(certModel *model.Cert) {
// block, unless errChan closed
for err := range errChan {
log.Error(err)
+ notification.Error("Renew Certificate Error", strings.Join(payload.ServerName, ", "))
+ return
}
+
+ notification.Success("Renew Certificate Success", strings.Join(payload.ServerName, ", "))
}
diff --git a/internal/notification/notification.go b/internal/notification/notification.go
new file mode 100644
index 00000000..b7d19c7f
--- /dev/null
+++ b/internal/notification/notification.go
@@ -0,0 +1,32 @@
+package notification
+
+import (
+ "github.com/0xJacky/Nginx-UI/model"
+ "github.com/0xJacky/Nginx-UI/query"
+)
+
+func Info(title string, details string) {
+ push(model.NotificationInfo, title, details)
+}
+
+func Error(title string, details string) {
+ push(model.NotificationError, title, details)
+}
+
+func Warning(title string, details string) {
+ push(model.NotificationWarning, title, details)
+}
+
+func Success(title string, details string) {
+ push(model.NotificationSuccess, title, details)
+}
+
+func push(nType model.NotificationType, title string, details string) {
+ n := query.Notification
+
+ _ = n.Create(&model.Notification{
+ Type: nType,
+ Title: title,
+ Details: details,
+ })
+}
diff --git a/model/model.go b/model/model.go
index df456cb8..0e33b109 100644
--- a/model/model.go
+++ b/model/model.go
@@ -34,6 +34,7 @@ func GenerateAllModel() []any {
Site{},
DnsCredential{},
Environment{},
+ Notification{},
}
}
@@ -99,12 +100,8 @@ func OrderAndPaginate(c *gin.Context) func(db *gorm.DB) *gorm.DB {
return func(db *gorm.DB) *gorm.DB {
sort := c.DefaultQuery("order", "desc")
- sortBy := DefaultQuery(c, "sort_by", "")
-
- if sortBy != "" {
- order := fmt.Sprintf("`%s` %s", DefaultQuery(c, "sort_by", "id"), sort)
- db = db.Order(order)
- }
+ order := fmt.Sprintf("`%s` %s", DefaultQuery(c, "sort_by", "id"), sort)
+ db = db.Order(order)
page := cast.ToInt(c.Query("page"))
if page == 0 {
diff --git a/model/notification.go b/model/notification.go
new file mode 100644
index 00000000..d9934549
--- /dev/null
+++ b/model/notification.go
@@ -0,0 +1,17 @@
+package model
+
+type NotificationType int
+
+const (
+ NotificationError NotificationType = iota
+ NotificationWarning
+ NotificationInfo
+ NotificationSuccess
+)
+
+type Notification struct {
+ Model
+ Type NotificationType `json:"type"`
+ Title string `json:"title"`
+ Details string `json:"details"`
+}
diff --git a/query/auth_tokens.gen.go b/query/auth_tokens.gen.go
index d80cd0b0..b06d7ced 100644
--- a/query/auth_tokens.gen.go
+++ b/query/auth_tokens.gen.go
@@ -6,7 +6,6 @@ package query
import (
"context"
- "github.com/0xJacky/Nginx-UI/model"
"strings"
"gorm.io/gorm"
@@ -17,6 +16,8 @@ import (
"gorm.io/gen/field"
"gorm.io/plugin/dbresolver"
+
+ "github.com/0xJacky/Nginx-UI/model"
)
func newAuthToken(db *gorm.DB, opts ...gen.DOOption) authToken {
@@ -162,10 +163,6 @@ func (a authTokenDo) Where(conds ...gen.Condition) *authTokenDo {
return a.withDO(a.DO.Where(conds...))
}
-func (a authTokenDo) Exists(subquery interface{ UnderlyingDB() *gorm.DB }) *authTokenDo {
- return a.Where(field.CompareSubQuery(field.ExistsOp, nil, subquery.UnderlyingDB()))
-}
-
func (a authTokenDo) Order(conds ...field.Expr) *authTokenDo {
return a.withDO(a.DO.Order(conds...))
}
diff --git a/query/auths.gen.go b/query/auths.gen.go
index c1419090..c96a4ad0 100644
--- a/query/auths.gen.go
+++ b/query/auths.gen.go
@@ -6,7 +6,6 @@ package query
import (
"context"
- "github.com/0xJacky/Nginx-UI/model"
"strings"
"gorm.io/gorm"
@@ -17,6 +16,8 @@ import (
"gorm.io/gen/field"
"gorm.io/plugin/dbresolver"
+
+ "github.com/0xJacky/Nginx-UI/model"
)
func newAuth(db *gorm.DB, opts ...gen.DOOption) auth {
@@ -182,10 +183,6 @@ func (a authDo) Where(conds ...gen.Condition) *authDo {
return a.withDO(a.DO.Where(conds...))
}
-func (a authDo) Exists(subquery interface{ UnderlyingDB() *gorm.DB }) *authDo {
- return a.Where(field.CompareSubQuery(field.ExistsOp, nil, subquery.UnderlyingDB()))
-}
-
func (a authDo) Order(conds ...field.Expr) *authDo {
return a.withDO(a.DO.Order(conds...))
}
diff --git a/query/certs.gen.go b/query/certs.gen.go
index 682765da..718990cf 100644
--- a/query/certs.gen.go
+++ b/query/certs.gen.go
@@ -6,7 +6,6 @@ package query
import (
"context"
- model2 "github.com/0xJacky/Nginx-UI/model"
"strings"
"gorm.io/gorm"
@@ -17,13 +16,15 @@ import (
"gorm.io/gen/field"
"gorm.io/plugin/dbresolver"
+
+ "github.com/0xJacky/Nginx-UI/model"
)
func newCert(db *gorm.DB, opts ...gen.DOOption) cert {
_cert := cert{}
_cert.certDo.UseDB(db, opts...)
- _cert.certDo.UseModel(&model2.Cert{})
+ _cert.certDo.UseModel(&model.Cert{})
tableName := _cert.certDo.TableName()
_cert.ALL = field.NewAsterisk(tableName)
@@ -67,8 +68,8 @@ type cert struct {
AutoCert field.Int
ChallengeMethod field.String
DnsCredentialID field.Int
- Log field.String
- DnsCredential certBelongsToDnsCredential
+ Log field.String
+ DnsCredential certBelongsToDnsCredential
fieldMap map[string]field.Expr
}
@@ -170,17 +171,17 @@ func (a certBelongsToDnsCredential) Session(session *gorm.Session) *certBelongsT
return &a
}
-func (a certBelongsToDnsCredential) Model(m *model2.Cert) *certBelongsToDnsCredentialTx {
+func (a certBelongsToDnsCredential) Model(m *model.Cert) *certBelongsToDnsCredentialTx {
return &certBelongsToDnsCredentialTx{a.db.Model(m).Association(a.Name())}
}
type certBelongsToDnsCredentialTx struct{ tx *gorm.Association }
-func (a certBelongsToDnsCredentialTx) Find() (result *model2.DnsCredential, err error) {
+func (a certBelongsToDnsCredentialTx) Find() (result *model.DnsCredential, err error) {
return result, a.tx.Find(&result)
}
-func (a certBelongsToDnsCredentialTx) Append(values ...*model2.DnsCredential) (err error) {
+func (a certBelongsToDnsCredentialTx) Append(values ...*model.DnsCredential) (err error) {
targetValues := make([]interface{}, len(values))
for i, v := range values {
targetValues[i] = v
@@ -188,7 +189,7 @@ func (a certBelongsToDnsCredentialTx) Append(values ...*model2.DnsCredential) (e
return a.tx.Append(targetValues...)
}
-func (a certBelongsToDnsCredentialTx) Replace(values ...*model2.DnsCredential) (err error) {
+func (a certBelongsToDnsCredentialTx) Replace(values ...*model.DnsCredential) (err error) {
targetValues := make([]interface{}, len(values))
for i, v := range values {
targetValues[i] = v
@@ -196,7 +197,7 @@ func (a certBelongsToDnsCredentialTx) Replace(values ...*model2.DnsCredential) (
return a.tx.Replace(targetValues...)
}
-func (a certBelongsToDnsCredentialTx) Delete(values ...*model2.DnsCredential) (err error) {
+func (a certBelongsToDnsCredentialTx) Delete(values ...*model.DnsCredential) (err error) {
targetValues := make([]interface{}, len(values))
for i, v := range values {
targetValues[i] = v
@@ -215,7 +216,7 @@ func (a certBelongsToDnsCredentialTx) Count() int64 {
type certDo struct{ gen.DO }
// FirstByID Where("id=@id")
-func (c certDo) FirstByID(id int) (result *model2.Cert, err error) {
+func (c certDo) FirstByID(id int) (result *model.Cert, err error) {
var params []interface{}
var generateSQL strings.Builder
@@ -288,10 +289,6 @@ func (c certDo) Where(conds ...gen.Condition) *certDo {
return c.withDO(c.DO.Where(conds...))
}
-func (c certDo) Exists(subquery interface{ UnderlyingDB() *gorm.DB }) *certDo {
- return c.Where(field.CompareSubQuery(field.ExistsOp, nil, subquery.UnderlyingDB()))
-}
-
func (c certDo) Order(conds ...field.Expr) *certDo {
return c.withDO(c.DO.Order(conds...))
}
@@ -340,57 +337,57 @@ func (c certDo) Unscoped() *certDo {
return c.withDO(c.DO.Unscoped())
}
-func (c certDo) Create(values ...*model2.Cert) error {
+func (c certDo) Create(values ...*model.Cert) error {
if len(values) == 0 {
return nil
}
return c.DO.Create(values)
}
-func (c certDo) CreateInBatches(values []*model2.Cert, batchSize int) error {
+func (c certDo) CreateInBatches(values []*model.Cert, batchSize int) error {
return c.DO.CreateInBatches(values, batchSize)
}
// Save : !!! underlying implementation is different with GORM
// The method is equivalent to executing the statement: db.Clauses(clause.OnConflict{UpdateAll: true}).Create(values)
-func (c certDo) Save(values ...*model2.Cert) error {
+func (c certDo) Save(values ...*model.Cert) error {
if len(values) == 0 {
return nil
}
return c.DO.Save(values)
}
-func (c certDo) First() (*model2.Cert, error) {
+func (c certDo) First() (*model.Cert, error) {
if result, err := c.DO.First(); err != nil {
return nil, err
} else {
- return result.(*model2.Cert), nil
+ return result.(*model.Cert), nil
}
}
-func (c certDo) Take() (*model2.Cert, error) {
+func (c certDo) Take() (*model.Cert, error) {
if result, err := c.DO.Take(); err != nil {
return nil, err
} else {
- return result.(*model2.Cert), nil
+ return result.(*model.Cert), nil
}
}
-func (c certDo) Last() (*model2.Cert, error) {
+func (c certDo) Last() (*model.Cert, error) {
if result, err := c.DO.Last(); err != nil {
return nil, err
} else {
- return result.(*model2.Cert), nil
+ return result.(*model.Cert), nil
}
}
-func (c certDo) Find() ([]*model2.Cert, error) {
+func (c certDo) Find() ([]*model.Cert, error) {
result, err := c.DO.Find()
- return result.([]*model2.Cert), err
+ return result.([]*model.Cert), err
}
-func (c certDo) FindInBatch(batchSize int, fc func(tx gen.Dao, batch int) error) (results []*model2.Cert, err error) {
- buf := make([]*model2.Cert, 0, batchSize)
+func (c certDo) FindInBatch(batchSize int, fc func(tx gen.Dao, batch int) error) (results []*model.Cert, err error) {
+ buf := make([]*model.Cert, 0, batchSize)
err = c.DO.FindInBatches(&buf, batchSize, func(tx gen.Dao, batch int) error {
defer func() { results = append(results, buf...) }()
return fc(tx, batch)
@@ -398,7 +395,7 @@ func (c certDo) FindInBatch(batchSize int, fc func(tx gen.Dao, batch int) error)
return results, err
}
-func (c certDo) FindInBatches(result *[]*model2.Cert, batchSize int, fc func(tx gen.Dao, batch int) error) error {
+func (c certDo) FindInBatches(result *[]*model.Cert, batchSize int, fc func(tx gen.Dao, batch int) error) error {
return c.DO.FindInBatches(result, batchSize, fc)
}
@@ -424,23 +421,23 @@ func (c certDo) Preload(fields ...field.RelationField) *certDo {
return &c
}
-func (c certDo) FirstOrInit() (*model2.Cert, error) {
+func (c certDo) FirstOrInit() (*model.Cert, error) {
if result, err := c.DO.FirstOrInit(); err != nil {
return nil, err
} else {
- return result.(*model2.Cert), nil
+ return result.(*model.Cert), nil
}
}
-func (c certDo) FirstOrCreate() (*model2.Cert, error) {
+func (c certDo) FirstOrCreate() (*model.Cert, error) {
if result, err := c.DO.FirstOrCreate(); err != nil {
return nil, err
} else {
- return result.(*model2.Cert), nil
+ return result.(*model.Cert), nil
}
}
-func (c certDo) FindByPage(offset int, limit int) (result []*model2.Cert, count int64, err error) {
+func (c certDo) FindByPage(offset int, limit int) (result []*model.Cert, count int64, err error) {
result, err = c.Offset(offset).Limit(limit).Find()
if err != nil {
return
@@ -469,7 +466,7 @@ func (c certDo) Scan(result interface{}) (err error) {
return c.DO.Scan(result)
}
-func (c certDo) Delete(models ...*model2.Cert) (result gen.ResultInfo, err error) {
+func (c certDo) Delete(models ...*model.Cert) (result gen.ResultInfo, err error) {
return c.DO.Delete(models)
}
diff --git a/query/chat_gpt_logs.gen.go b/query/chat_gpt_logs.gen.go
index b7ebc914..56c86b9e 100644
--- a/query/chat_gpt_logs.gen.go
+++ b/query/chat_gpt_logs.gen.go
@@ -6,7 +6,6 @@ package query
import (
"context"
- "github.com/0xJacky/Nginx-UI/model"
"strings"
"gorm.io/gorm"
@@ -17,6 +16,8 @@ import (
"gorm.io/gen/field"
"gorm.io/plugin/dbresolver"
+
+ "github.com/0xJacky/Nginx-UI/model"
)
func newChatGPTLog(db *gorm.DB, opts ...gen.DOOption) chatGPTLog {
@@ -166,10 +167,6 @@ func (c chatGPTLogDo) Where(conds ...gen.Condition) *chatGPTLogDo {
return c.withDO(c.DO.Where(conds...))
}
-func (c chatGPTLogDo) Exists(subquery interface{ UnderlyingDB() *gorm.DB }) *chatGPTLogDo {
- return c.Where(field.CompareSubQuery(field.ExistsOp, nil, subquery.UnderlyingDB()))
-}
-
func (c chatGPTLogDo) Order(conds ...field.Expr) *chatGPTLogDo {
return c.withDO(c.DO.Order(conds...))
}
diff --git a/query/config_backups.gen.go b/query/config_backups.gen.go
index 5e7ee870..2c870c6a 100644
--- a/query/config_backups.gen.go
+++ b/query/config_backups.gen.go
@@ -6,7 +6,6 @@ package query
import (
"context"
- "github.com/0xJacky/Nginx-UI/model"
"strings"
"gorm.io/gorm"
@@ -17,6 +16,8 @@ import (
"gorm.io/gen/field"
"gorm.io/plugin/dbresolver"
+
+ "github.com/0xJacky/Nginx-UI/model"
)
func newConfigBackup(db *gorm.DB, opts ...gen.DOOption) configBackup {
@@ -186,10 +187,6 @@ func (c configBackupDo) Where(conds ...gen.Condition) *configBackupDo {
return c.withDO(c.DO.Where(conds...))
}
-func (c configBackupDo) Exists(subquery interface{ UnderlyingDB() *gorm.DB }) *configBackupDo {
- return c.Where(field.CompareSubQuery(field.ExistsOp, nil, subquery.UnderlyingDB()))
-}
-
func (c configBackupDo) Order(conds ...field.Expr) *configBackupDo {
return c.withDO(c.DO.Order(conds...))
}
diff --git a/query/dns_credentials.gen.go b/query/dns_credentials.gen.go
index dccc24d4..37e06bbc 100644
--- a/query/dns_credentials.gen.go
+++ b/query/dns_credentials.gen.go
@@ -6,7 +6,6 @@ package query
import (
"context"
- "github.com/0xJacky/Nginx-UI/model"
"strings"
"gorm.io/gorm"
@@ -17,6 +16,8 @@ import (
"gorm.io/gen/field"
"gorm.io/plugin/dbresolver"
+
+ "github.com/0xJacky/Nginx-UI/model"
)
func newDnsCredential(db *gorm.DB, opts ...gen.DOOption) dnsCredential {
@@ -186,10 +187,6 @@ func (d dnsCredentialDo) Where(conds ...gen.Condition) *dnsCredentialDo {
return d.withDO(d.DO.Where(conds...))
}
-func (d dnsCredentialDo) Exists(subquery interface{ UnderlyingDB() *gorm.DB }) *dnsCredentialDo {
- return d.Where(field.CompareSubQuery(field.ExistsOp, nil, subquery.UnderlyingDB()))
-}
-
func (d dnsCredentialDo) Order(conds ...field.Expr) *dnsCredentialDo {
return d.withDO(d.DO.Order(conds...))
}
diff --git a/query/environments.gen.go b/query/environments.gen.go
index a8b4500d..a82cdcec 100644
--- a/query/environments.gen.go
+++ b/query/environments.gen.go
@@ -6,7 +6,6 @@ package query
import (
"context"
- "github.com/0xJacky/Nginx-UI/model"
"strings"
"gorm.io/gorm"
@@ -17,6 +16,8 @@ import (
"gorm.io/gen/field"
"gorm.io/plugin/dbresolver"
+
+ "github.com/0xJacky/Nginx-UI/model"
)
func newEnvironment(db *gorm.DB, opts ...gen.DOOption) environment {
@@ -194,10 +195,6 @@ func (e environmentDo) Where(conds ...gen.Condition) *environmentDo {
return e.withDO(e.DO.Where(conds...))
}
-func (e environmentDo) Exists(subquery interface{ UnderlyingDB() *gorm.DB }) *environmentDo {
- return e.Where(field.CompareSubQuery(field.ExistsOp, nil, subquery.UnderlyingDB()))
-}
-
func (e environmentDo) Order(conds ...field.Expr) *environmentDo {
return e.withDO(e.DO.Order(conds...))
}
diff --git a/query/gen.go b/query/gen.go
index af3e082a..27d040af 100644
--- a/query/gen.go
+++ b/query/gen.go
@@ -24,6 +24,7 @@ var (
ConfigBackup *configBackup
DnsCredential *dnsCredential
Environment *environment
+ Notification *notification
Site *site
)
@@ -36,6 +37,7 @@ func SetDefault(db *gorm.DB, opts ...gen.DOOption) {
ConfigBackup = &Q.ConfigBackup
DnsCredential = &Q.DnsCredential
Environment = &Q.Environment
+ Notification = &Q.Notification
Site = &Q.Site
}
@@ -49,6 +51,7 @@ func Use(db *gorm.DB, opts ...gen.DOOption) *Query {
ConfigBackup: newConfigBackup(db, opts...),
DnsCredential: newDnsCredential(db, opts...),
Environment: newEnvironment(db, opts...),
+ Notification: newNotification(db, opts...),
Site: newSite(db, opts...),
}
}
@@ -63,6 +66,7 @@ type Query struct {
ConfigBackup configBackup
DnsCredential dnsCredential
Environment environment
+ Notification notification
Site site
}
@@ -78,6 +82,7 @@ func (q *Query) clone(db *gorm.DB) *Query {
ConfigBackup: q.ConfigBackup.clone(db),
DnsCredential: q.DnsCredential.clone(db),
Environment: q.Environment.clone(db),
+ Notification: q.Notification.clone(db),
Site: q.Site.clone(db),
}
}
@@ -100,6 +105,7 @@ func (q *Query) ReplaceDB(db *gorm.DB) *Query {
ConfigBackup: q.ConfigBackup.replaceDB(db),
DnsCredential: q.DnsCredential.replaceDB(db),
Environment: q.Environment.replaceDB(db),
+ Notification: q.Notification.replaceDB(db),
Site: q.Site.replaceDB(db),
}
}
@@ -112,6 +118,7 @@ type queryCtx struct {
ConfigBackup *configBackupDo
DnsCredential *dnsCredentialDo
Environment *environmentDo
+ Notification *notificationDo
Site *siteDo
}
@@ -124,6 +131,7 @@ func (q *Query) WithContext(ctx context.Context) *queryCtx {
ConfigBackup: q.ConfigBackup.WithContext(ctx),
DnsCredential: q.DnsCredential.WithContext(ctx),
Environment: q.Environment.WithContext(ctx),
+ Notification: q.Notification.WithContext(ctx),
Site: q.Site.WithContext(ctx),
}
}
diff --git a/query/notifications.gen.go b/query/notifications.gen.go
new file mode 100644
index 00000000..d7eff9f6
--- /dev/null
+++ b/query/notifications.gen.go
@@ -0,0 +1,374 @@
+// Code generated by gorm.io/gen. DO NOT EDIT.
+// Code generated by gorm.io/gen. DO NOT EDIT.
+// Code generated by gorm.io/gen. DO NOT EDIT.
+
+package query
+
+import (
+ "context"
+ "strings"
+
+ "gorm.io/gorm"
+ "gorm.io/gorm/clause"
+ "gorm.io/gorm/schema"
+
+ "gorm.io/gen"
+ "gorm.io/gen/field"
+
+ "gorm.io/plugin/dbresolver"
+
+ "github.com/0xJacky/Nginx-UI/model"
+)
+
+func newNotification(db *gorm.DB, opts ...gen.DOOption) notification {
+ _notification := notification{}
+
+ _notification.notificationDo.UseDB(db, opts...)
+ _notification.notificationDo.UseModel(&model.Notification{})
+
+ tableName := _notification.notificationDo.TableName()
+ _notification.ALL = field.NewAsterisk(tableName)
+ _notification.ID = field.NewInt(tableName, "id")
+ _notification.CreatedAt = field.NewTime(tableName, "created_at")
+ _notification.UpdatedAt = field.NewTime(tableName, "updated_at")
+ _notification.DeletedAt = field.NewField(tableName, "deleted_at")
+ _notification.Type = field.NewInt(tableName, "type")
+ _notification.Title = field.NewString(tableName, "title")
+ _notification.Details = field.NewString(tableName, "details")
+
+ _notification.fillFieldMap()
+
+ return _notification
+}
+
+type notification struct {
+ notificationDo
+
+ ALL field.Asterisk
+ ID field.Int
+ CreatedAt field.Time
+ UpdatedAt field.Time
+ DeletedAt field.Field
+ Type field.Int
+ Title field.String
+ Details field.String
+
+ fieldMap map[string]field.Expr
+}
+
+func (n notification) Table(newTableName string) *notification {
+ n.notificationDo.UseTable(newTableName)
+ return n.updateTableName(newTableName)
+}
+
+func (n notification) As(alias string) *notification {
+ n.notificationDo.DO = *(n.notificationDo.As(alias).(*gen.DO))
+ return n.updateTableName(alias)
+}
+
+func (n *notification) updateTableName(table string) *notification {
+ n.ALL = field.NewAsterisk(table)
+ n.ID = field.NewInt(table, "id")
+ n.CreatedAt = field.NewTime(table, "created_at")
+ n.UpdatedAt = field.NewTime(table, "updated_at")
+ n.DeletedAt = field.NewField(table, "deleted_at")
+ n.Type = field.NewInt(table, "type")
+ n.Title = field.NewString(table, "title")
+ n.Details = field.NewString(table, "details")
+
+ n.fillFieldMap()
+
+ return n
+}
+
+func (n *notification) GetFieldByName(fieldName string) (field.OrderExpr, bool) {
+ _f, ok := n.fieldMap[fieldName]
+ if !ok || _f == nil {
+ return nil, false
+ }
+ _oe, ok := _f.(field.OrderExpr)
+ return _oe, ok
+}
+
+func (n *notification) fillFieldMap() {
+ n.fieldMap = make(map[string]field.Expr, 7)
+ n.fieldMap["id"] = n.ID
+ n.fieldMap["created_at"] = n.CreatedAt
+ n.fieldMap["updated_at"] = n.UpdatedAt
+ n.fieldMap["deleted_at"] = n.DeletedAt
+ n.fieldMap["type"] = n.Type
+ n.fieldMap["title"] = n.Title
+ n.fieldMap["details"] = n.Details
+}
+
+func (n notification) clone(db *gorm.DB) notification {
+ n.notificationDo.ReplaceConnPool(db.Statement.ConnPool)
+ return n
+}
+
+func (n notification) replaceDB(db *gorm.DB) notification {
+ n.notificationDo.ReplaceDB(db)
+ return n
+}
+
+type notificationDo struct{ gen.DO }
+
+// FirstByID Where("id=@id")
+func (n notificationDo) FirstByID(id int) (result *model.Notification, err error) {
+ var params []interface{}
+
+ var generateSQL strings.Builder
+ params = append(params, id)
+ generateSQL.WriteString("id=? ")
+
+ var executeSQL *gorm.DB
+ executeSQL = n.UnderlyingDB().Where(generateSQL.String(), params...).Take(&result) // ignore_security_alert
+ err = executeSQL.Error
+
+ return
+}
+
+// DeleteByID update @@table set deleted_at=strftime('%Y-%m-%d %H:%M:%S','now') where id=@id
+func (n notificationDo) DeleteByID(id int) (err error) {
+ var params []interface{}
+
+ var generateSQL strings.Builder
+ params = append(params, id)
+ generateSQL.WriteString("update notifications set deleted_at=strftime('%Y-%m-%d %H:%M:%S','now') where id=? ")
+
+ var executeSQL *gorm.DB
+ executeSQL = n.UnderlyingDB().Exec(generateSQL.String(), params...) // ignore_security_alert
+ err = executeSQL.Error
+
+ return
+}
+
+func (n notificationDo) Debug() *notificationDo {
+ return n.withDO(n.DO.Debug())
+}
+
+func (n notificationDo) WithContext(ctx context.Context) *notificationDo {
+ return n.withDO(n.DO.WithContext(ctx))
+}
+
+func (n notificationDo) ReadDB() *notificationDo {
+ return n.Clauses(dbresolver.Read)
+}
+
+func (n notificationDo) WriteDB() *notificationDo {
+ return n.Clauses(dbresolver.Write)
+}
+
+func (n notificationDo) Session(config *gorm.Session) *notificationDo {
+ return n.withDO(n.DO.Session(config))
+}
+
+func (n notificationDo) Clauses(conds ...clause.Expression) *notificationDo {
+ return n.withDO(n.DO.Clauses(conds...))
+}
+
+func (n notificationDo) Returning(value interface{}, columns ...string) *notificationDo {
+ return n.withDO(n.DO.Returning(value, columns...))
+}
+
+func (n notificationDo) Not(conds ...gen.Condition) *notificationDo {
+ return n.withDO(n.DO.Not(conds...))
+}
+
+func (n notificationDo) Or(conds ...gen.Condition) *notificationDo {
+ return n.withDO(n.DO.Or(conds...))
+}
+
+func (n notificationDo) Select(conds ...field.Expr) *notificationDo {
+ return n.withDO(n.DO.Select(conds...))
+}
+
+func (n notificationDo) Where(conds ...gen.Condition) *notificationDo {
+ return n.withDO(n.DO.Where(conds...))
+}
+
+func (n notificationDo) Order(conds ...field.Expr) *notificationDo {
+ return n.withDO(n.DO.Order(conds...))
+}
+
+func (n notificationDo) Distinct(cols ...field.Expr) *notificationDo {
+ return n.withDO(n.DO.Distinct(cols...))
+}
+
+func (n notificationDo) Omit(cols ...field.Expr) *notificationDo {
+ return n.withDO(n.DO.Omit(cols...))
+}
+
+func (n notificationDo) Join(table schema.Tabler, on ...field.Expr) *notificationDo {
+ return n.withDO(n.DO.Join(table, on...))
+}
+
+func (n notificationDo) LeftJoin(table schema.Tabler, on ...field.Expr) *notificationDo {
+ return n.withDO(n.DO.LeftJoin(table, on...))
+}
+
+func (n notificationDo) RightJoin(table schema.Tabler, on ...field.Expr) *notificationDo {
+ return n.withDO(n.DO.RightJoin(table, on...))
+}
+
+func (n notificationDo) Group(cols ...field.Expr) *notificationDo {
+ return n.withDO(n.DO.Group(cols...))
+}
+
+func (n notificationDo) Having(conds ...gen.Condition) *notificationDo {
+ return n.withDO(n.DO.Having(conds...))
+}
+
+func (n notificationDo) Limit(limit int) *notificationDo {
+ return n.withDO(n.DO.Limit(limit))
+}
+
+func (n notificationDo) Offset(offset int) *notificationDo {
+ return n.withDO(n.DO.Offset(offset))
+}
+
+func (n notificationDo) Scopes(funcs ...func(gen.Dao) gen.Dao) *notificationDo {
+ return n.withDO(n.DO.Scopes(funcs...))
+}
+
+func (n notificationDo) Unscoped() *notificationDo {
+ return n.withDO(n.DO.Unscoped())
+}
+
+func (n notificationDo) Create(values ...*model.Notification) error {
+ if len(values) == 0 {
+ return nil
+ }
+ return n.DO.Create(values)
+}
+
+func (n notificationDo) CreateInBatches(values []*model.Notification, batchSize int) error {
+ return n.DO.CreateInBatches(values, batchSize)
+}
+
+// Save : !!! underlying implementation is different with GORM
+// The method is equivalent to executing the statement: db.Clauses(clause.OnConflict{UpdateAll: true}).Create(values)
+func (n notificationDo) Save(values ...*model.Notification) error {
+ if len(values) == 0 {
+ return nil
+ }
+ return n.DO.Save(values)
+}
+
+func (n notificationDo) First() (*model.Notification, error) {
+ if result, err := n.DO.First(); err != nil {
+ return nil, err
+ } else {
+ return result.(*model.Notification), nil
+ }
+}
+
+func (n notificationDo) Take() (*model.Notification, error) {
+ if result, err := n.DO.Take(); err != nil {
+ return nil, err
+ } else {
+ return result.(*model.Notification), nil
+ }
+}
+
+func (n notificationDo) Last() (*model.Notification, error) {
+ if result, err := n.DO.Last(); err != nil {
+ return nil, err
+ } else {
+ return result.(*model.Notification), nil
+ }
+}
+
+func (n notificationDo) Find() ([]*model.Notification, error) {
+ result, err := n.DO.Find()
+ return result.([]*model.Notification), err
+}
+
+func (n notificationDo) FindInBatch(batchSize int, fc func(tx gen.Dao, batch int) error) (results []*model.Notification, err error) {
+ buf := make([]*model.Notification, 0, batchSize)
+ err = n.DO.FindInBatches(&buf, batchSize, func(tx gen.Dao, batch int) error {
+ defer func() { results = append(results, buf...) }()
+ return fc(tx, batch)
+ })
+ return results, err
+}
+
+func (n notificationDo) FindInBatches(result *[]*model.Notification, batchSize int, fc func(tx gen.Dao, batch int) error) error {
+ return n.DO.FindInBatches(result, batchSize, fc)
+}
+
+func (n notificationDo) Attrs(attrs ...field.AssignExpr) *notificationDo {
+ return n.withDO(n.DO.Attrs(attrs...))
+}
+
+func (n notificationDo) Assign(attrs ...field.AssignExpr) *notificationDo {
+ return n.withDO(n.DO.Assign(attrs...))
+}
+
+func (n notificationDo) Joins(fields ...field.RelationField) *notificationDo {
+ for _, _f := range fields {
+ n = *n.withDO(n.DO.Joins(_f))
+ }
+ return &n
+}
+
+func (n notificationDo) Preload(fields ...field.RelationField) *notificationDo {
+ for _, _f := range fields {
+ n = *n.withDO(n.DO.Preload(_f))
+ }
+ return &n
+}
+
+func (n notificationDo) FirstOrInit() (*model.Notification, error) {
+ if result, err := n.DO.FirstOrInit(); err != nil {
+ return nil, err
+ } else {
+ return result.(*model.Notification), nil
+ }
+}
+
+func (n notificationDo) FirstOrCreate() (*model.Notification, error) {
+ if result, err := n.DO.FirstOrCreate(); err != nil {
+ return nil, err
+ } else {
+ return result.(*model.Notification), nil
+ }
+}
+
+func (n notificationDo) FindByPage(offset int, limit int) (result []*model.Notification, count int64, err error) {
+ result, err = n.Offset(offset).Limit(limit).Find()
+ if err != nil {
+ return
+ }
+
+ if size := len(result); 0 < limit && 0 < size && size < limit {
+ count = int64(size + offset)
+ return
+ }
+
+ count, err = n.Offset(-1).Limit(-1).Count()
+ return
+}
+
+func (n notificationDo) ScanByPage(result interface{}, offset int, limit int) (count int64, err error) {
+ count, err = n.Count()
+ if err != nil {
+ return
+ }
+
+ err = n.Offset(offset).Limit(limit).Scan(result)
+ return
+}
+
+func (n notificationDo) Scan(result interface{}) (err error) {
+ return n.DO.Scan(result)
+}
+
+func (n notificationDo) Delete(models ...*model.Notification) (result gen.ResultInfo, err error) {
+ return n.DO.Delete(models)
+}
+
+func (n *notificationDo) withDO(do gen.Dao) *notificationDo {
+ n.DO = *do.(*gen.DO)
+ return n
+}
diff --git a/query/sites.gen.go b/query/sites.gen.go
index 410925c5..8dbfdf2d 100644
--- a/query/sites.gen.go
+++ b/query/sites.gen.go
@@ -6,7 +6,6 @@ package query
import (
"context"
- "github.com/0xJacky/Nginx-UI/model"
"strings"
"gorm.io/gorm"
@@ -17,6 +16,8 @@ import (
"gorm.io/gen/field"
"gorm.io/plugin/dbresolver"
+
+ "github.com/0xJacky/Nginx-UI/model"
)
func newSite(db *gorm.DB, opts ...gen.DOOption) site {
@@ -182,10 +183,6 @@ func (s siteDo) Where(conds ...gen.Condition) *siteDo {
return s.withDO(s.DO.Where(conds...))
}
-func (s siteDo) Exists(subquery interface{ UnderlyingDB() *gorm.DB }) *siteDo {
- return s.Where(field.CompareSubQuery(field.ExistsOp, nil, subquery.UnderlyingDB()))
-}
-
func (s siteDo) Order(conds ...field.Expr) *siteDo {
return s.withDO(s.DO.Order(conds...))
}
diff --git a/resources/demo/demo.db b/resources/demo/demo.db
index 486b9249..b1bed81b 100644
Binary files a/resources/demo/demo.db and b/resources/demo/demo.db differ
diff --git a/router/routers.go b/router/routers.go
index 23302e96..c47c7156 100644
--- a/router/routers.go
+++ b/router/routers.go
@@ -6,6 +6,7 @@ import (
"github.com/0xJacky/Nginx-UI/api/cluster"
"github.com/0xJacky/Nginx-UI/api/config"
"github.com/0xJacky/Nginx-UI/api/nginx"
+ "github.com/0xJacky/Nginx-UI/api/notification"
"github.com/0xJacky/Nginx-UI/api/openai"
"github.com/0xJacky/Nginx-UI/api/sites"
"github.com/0xJacky/Nginx-UI/api/system"
@@ -54,6 +55,7 @@ func InitRouter() *gin.Engine {
system.InitPrivateRouter(g)
openai.InitRouter(g)
cluster.InitRouter(g)
+ notification.InitRouter(g)
}
// Authorization required and websocket request