diff --git a/README.md b/README.md index 87a4df9..d206527 100644 --- a/README.md +++ b/README.md @@ -48,7 +48,7 @@ First go to [spamhaus](https://check.spamhaus.org/) and check your domain name a ## 2、Run -`./pmail` +`./pmail` (Set the http port for the initialization interface with `-p` ) Or diff --git a/README_CN.md b/README_CN.md index 5543d85..6e338ba 100644 --- a/README_CN.md +++ b/README_CN.md @@ -53,7 +53,7 @@ PMail是一个追求极简部署流程、极致资源占用的个人域名邮箱 ## 2、运行 -`./pmail` +`./pmail` (通过`-p`参数指定初始化界面的http端口) 或者 diff --git a/server/config/config.go b/server/config/config.go index 4298441..68bb94f 100644 --- a/server/config/config.go +++ b/server/config/config.go @@ -1,11 +1,8 @@ package config import ( - "embed" "encoding/json" - "io/fs" "os" - "strings" ) var IsInit bool @@ -38,9 +35,6 @@ type Config struct { TablesInitData map[string]string `json:"-"` } -//go:embed tables/* -var tableConfig embed.FS - const DBTypeMySQL = "mysql" const DBTypeSQLite = "sqlite" const SSLTypeAuto = "0" //自动生成证书 @@ -76,38 +70,6 @@ func Init() { Instance.Domains = []string{Instance.Domain} } - // 读取表设置 - Instance.Tables = map[string]string{} - Instance.TablesInitData = map[string]string{} - - root := "tables/mysql" - if Instance.DbType == DBTypeSQLite { - root = "tables/sqlite" - } - err = fs.WalkDir(tableConfig, root, func(path string, info fs.DirEntry, err error) error { - if !info.IsDir() && strings.HasSuffix(info.Name(), ".sql") { - tableName := strings.ReplaceAll(info.Name(), ".sql", "") - i, e := tableConfig.ReadFile(path) - if e != nil { - panic(e) - } - if len(i) == 0 || strings.TrimSpace(string(i)) == "" { - return nil - } - if strings.Contains(path, "data") { - Instance.TablesInitData[tableName] = string(i) - } else { - Instance.Tables[tableName] = string(i) - } - - } - return nil - }) - - if err != nil { - panic(err) - } - if Instance.Domain != "" && Instance.IsInit { IsInit = true } diff --git a/server/config/tables/mysql/data/user.sql b/server/config/tables/mysql/data/user.sql deleted file mode 100644 index e69de29..0000000 diff --git a/server/config/tables/mysql/data/user_auth.sql b/server/config/tables/mysql/data/user_auth.sql deleted file mode 100644 index e69de29..0000000 diff --git a/server/config/tables/mysql/email.sql b/server/config/tables/mysql/email.sql deleted file mode 100644 index 3c9f9e4..0000000 --- a/server/config/tables/mysql/email.sql +++ /dev/null @@ -1,27 +0,0 @@ -CREATE table email -( - id INT unsigned AUTO_INCREMENT PRIMARY KEY COMMENT '自增id', - type tinyint(4) NOT NULL DEFAULT 0 COMMENT '邮件类型,0:收到的邮件,1:发送的邮件', - group_id int unsigned NOT NULL DEFAULT 0 COMMENT '分组id', - subject varchar(1000) NOT NULL DEFAULT '' COMMENT '邮件标题', - reply_to json COMMENT '回复人', - from_name varchar(50) NOT NULL DEFAULT '' COMMENT '发件人名称', - from_address varchar(150) NOT NULL DEFAULT '' COMMENT '发件人邮件地址', - `to` json COMMENT '收件人信息', - bcc json COMMENT '抄送', - cc json COMMENT '抄送', - `text` text COMMENT '邮件文本内容', - html mediumtext COMMENT 'html格式内容', - sender json COMMENT '发件人', - attachments json COMMENT '附件内容', - spf_check tinyint(1) DEFAULT 0 COMMENT '0未校验,1校验通过,2校验未通过', - dkim_check tinyint(1) DEFAULT 0 COMMENT '0未校验,1校验通过,2校验未通过', - status tinyint(4) NOT NULL DEFAULT 0 COMMENT '0未发送,1已发送,2发送失败,3删除', - send_user_id int unsigned NOT NULL DEFAULT 0 COMMENT '发件人用户id', - is_read tinyint(1) NOT NULL DEFAULT 0 COMMENT '未读0,已读1', - error text COMMENT '错误信息记录', - cron_send_time datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '定时发送邮件的发送时间', - send_date datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '发件日期', - create_time datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', - update_time datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间' -)COMMENT='邮件内容表' \ No newline at end of file diff --git a/server/config/tables/mysql/group.sql b/server/config/tables/mysql/group.sql deleted file mode 100644 index d6f3d68..0000000 --- a/server/config/tables/mysql/group.sql +++ /dev/null @@ -1,7 +0,0 @@ -CREATE TABLE `group` -( - id INT unsigned AUTO_INCREMENT PRIMARY KEY COMMENT '自增id', - name varchar(10) NOT NULL DEFAULT '' COMMENT '分组名称', - user_id INT unsigned NOT NULL DEFAULT 0 COMMENT '用户id', - parent_id INT unsigned COMMENT '父级组ID' -)COMMENT='分组信息表' \ No newline at end of file diff --git a/server/config/tables/mysql/rule.sql b/server/config/tables/mysql/rule.sql deleted file mode 100644 index 72f1bd0..0000000 --- a/server/config/tables/mysql/rule.sql +++ /dev/null @@ -1,10 +0,0 @@ -CREATE TABLE `rule` -( - id INT unsigned AUTO_INCREMENT PRIMARY KEY COMMENT '自增id', - user_id int NOT NULL DEFAULT 0 COMMENT '用户id', - `name` varchar(255) NOT NULL DEFAULT '' COMMENT '规则名称', - `value` json NOT NULL COMMENT '规则内容', - action int not null default 0 comment '执行动作,1已读,2转发,3删除', - params varchar(255) not null default '' comment '执行参数', - sort int not null default 0 COMMENT '排序,越大约优先' -) COMMENT '收信规则表' \ No newline at end of file diff --git a/server/config/tables/mysql/sessions.sql b/server/config/tables/mysql/sessions.sql deleted file mode 100644 index 6967261..0000000 --- a/server/config/tables/mysql/sessions.sql +++ /dev/null @@ -1,7 +0,0 @@ -CREATE TABLE sessions -( - token CHAR(43) PRIMARY KEY, - data BLOB NOT NULL, - expiry TIMESTAMP(6) NOT NULL, - KEY `sessions_expiry_idx` (`expiry`) -)COMMENT='系统session数据表'; diff --git a/server/config/tables/mysql/user.sql b/server/config/tables/mysql/user.sql deleted file mode 100644 index 7761a70..0000000 --- a/server/config/tables/mysql/user.sql +++ /dev/null @@ -1,8 +0,0 @@ -CREATE TABLE user -( - id INT unsigned AUTO_INCREMENT PRIMARY KEY COMMENT '自增id', - account varchar(20) COMMENT '账号登陆名', - name varchar(10) COMMENT '用户名', - password char(32) COMMENT '登陆密码,两次md5加盐,md5(md5(password+"pmail") +"pmail2023")', - UNIQUE INDEX udx_account ( account ) -)COMMENT='登陆信息表' \ No newline at end of file diff --git a/server/config/tables/mysql/user_auth.sql b/server/config/tables/mysql/user_auth.sql deleted file mode 100644 index bb3964f..0000000 --- a/server/config/tables/mysql/user_auth.sql +++ /dev/null @@ -1,8 +0,0 @@ -CREATE TABLE user_auth -( - id INT unsigned AUTO_INCREMENT PRIMARY KEY COMMENT '自增id', - user_id int COMMENT '用户id', - email_account varchar(30) COMMENT '收件人前缀', - UNIQUE INDEX udx_uid_ename ( user_id, email_account), - UNIQUE INDEX udx_ename_uid ( email_account,user_id ) -)COMMENT='登陆信息表' \ No newline at end of file diff --git a/server/config/tables/sqlite/data/user.sql b/server/config/tables/sqlite/data/user.sql deleted file mode 100644 index e69de29..0000000 diff --git a/server/config/tables/sqlite/data/user_auth.sql b/server/config/tables/sqlite/data/user_auth.sql deleted file mode 100644 index e69de29..0000000 diff --git a/server/config/tables/sqlite/email.sql b/server/config/tables/sqlite/email.sql deleted file mode 100644 index 2db179b..0000000 --- a/server/config/tables/sqlite/email.sql +++ /dev/null @@ -1,27 +0,0 @@ -CREATE table email -( - id INTEGER PRIMARY KEY AUTOINCREMENT, - type tinyint(4) NOT NULL DEFAULT 0, - group_id INTEGER NOT NULL DEFAULT 0, - subject varchar(1000) NOT NULL DEFAULT '', - reply_to json, - from_name varchar(50) NOT NULL DEFAULT '', - from_address varchar(150) NOT NULL DEFAULT '', - `to` json, - bcc json, - cc json, - `text` text, - html text, - sender json, - attachments json , - spf_check tinyint(1) DEFAULT 0 , - dkim_check tinyint(1) DEFAULT 0 , - status tinyint(4) NOT NULL DEFAULT 0 , - send_user_id int unsigned NOT NULL DEFAULT 0 , - is_read tinyint(1) NOT NULL DEFAULT 0 , - error text , - cron_send_time datetime NOT NULL DEFAULT CURRENT_TIMESTAMP , - send_date datetime NOT NULL DEFAULT CURRENT_TIMESTAMP , - create_time datetime NOT NULL DEFAULT CURRENT_TIMESTAMP , - update_time datetime NOT NULL DEFAULT CURRENT_TIMESTAMP -) \ No newline at end of file diff --git a/server/config/tables/sqlite/group.sql b/server/config/tables/sqlite/group.sql deleted file mode 100644 index a994239..0000000 --- a/server/config/tables/sqlite/group.sql +++ /dev/null @@ -1,7 +0,0 @@ -CREATE TABLE `group` -( - id INTEGER PRIMARY KEY AUTOINCREMENT, - name varchar(10) NOT NULL DEFAULT '', - parent_id INTEGER NOT NULL DEFAULT 0, - user_id INTEGER NOT NULL DEFAULT 0 -) \ No newline at end of file diff --git a/server/config/tables/sqlite/rule.sql b/server/config/tables/sqlite/rule.sql deleted file mode 100644 index 5e26112..0000000 --- a/server/config/tables/sqlite/rule.sql +++ /dev/null @@ -1,10 +0,0 @@ -create table rule -( - id INTEGER PRIMARY KEY AUTOINCREMENT, - user_id int, - name varchar(255) default '' not null, - value json not null, - action int default 0 not null, - params varchar(255) default '' not null, - sort int default 0 not null -) \ No newline at end of file diff --git a/server/config/tables/sqlite/sessions.sql b/server/config/tables/sqlite/sessions.sql deleted file mode 100644 index 198851f..0000000 --- a/server/config/tables/sqlite/sessions.sql +++ /dev/null @@ -1,8 +0,0 @@ -CREATE TABLE sessions -( - token TEXT PRIMARY KEY, - data BLOB NOT NULL, - expiry REAL NOT NULL -); - -CREATE INDEX sessions_expiry_idx ON sessions (expiry); \ No newline at end of file diff --git a/server/config/tables/sqlite/user.sql b/server/config/tables/sqlite/user.sql deleted file mode 100644 index d08fb9e..0000000 --- a/server/config/tables/sqlite/user.sql +++ /dev/null @@ -1,8 +0,0 @@ -CREATE TABLE user -( - id INTEGER PRIMARY KEY AUTOINCREMENT, - account varchar(20), - name varchar(10), - password char(32) -); -CREATE UNIQUE INDEX udx_account on user (account); \ No newline at end of file diff --git a/server/config/tables/sqlite/user_auth.sql b/server/config/tables/sqlite/user_auth.sql deleted file mode 100644 index 4205e0c..0000000 --- a/server/config/tables/sqlite/user_auth.sql +++ /dev/null @@ -1,9 +0,0 @@ -CREATE TABLE user_auth -( - id INTEGER PRIMARY KEY AUTOINCREMENT, - user_id int , - email_account varchar(30) -); - -CREATE UNIQUE INDEX udx_uid_ename on user_auth ( user_id, email_account); -CREATE UNIQUE INDEX udx_ename_uid on user_auth ( email_account,user_id ); \ No newline at end of file diff --git a/server/controllers/group.go b/server/controllers/group.go index 057dca7..6ef9f81 100644 --- a/server/controllers/group.go +++ b/server/controllers/group.go @@ -37,6 +37,10 @@ func GetUserGroup(ctx *context.Context, w http.ResponseWriter, req *http.Request Label: i18n.GetText(ctx.Lang, "sketch"), Tag: dto.SearchTag{Type: 1, Status: 0}.ToString(), }, + { + Label: i18n.GetText(ctx.Lang, "deleted"), + Tag: dto.SearchTag{Type: -1, Status: 3}.ToString(), + }, }, }, } diff --git a/server/controllers/login.go b/server/controllers/login.go index 1c36ca4..0a67c20 100644 --- a/server/controllers/login.go +++ b/server/controllers/login.go @@ -35,9 +35,8 @@ func Login(ctx *context.Context, w http.ResponseWriter, req *http.Request) { var user models.User encodePwd := password.Encode(reqData.Password) - - err = db.Instance.Get(&user, db.WithContext(ctx, "select * from user where account =? and password =?"), - reqData.Account, encodePwd) + + _, err = db.Instance.Where("account =? and password =?", reqData.Account, encodePwd).Get(&user) if err != nil && err != sql.ErrNoRows { log.Errorf("%+v", err) } diff --git a/server/db/init.go b/server/db/init.go index 7e665a1..6f496ba 100644 --- a/server/db/init.go +++ b/server/db/init.go @@ -3,16 +3,14 @@ package db import ( "fmt" _ "github.com/go-sql-driver/mysql" - "github.com/jmoiron/sqlx" - log "github.com/sirupsen/logrus" _ "modernc.org/sqlite" "pmail/config" "pmail/utils/context" "pmail/utils/errors" - "strings" + "xorm.io/xorm" ) -var Instance *sqlx.DB +var Instance *xorm.Engine func Init() error { dsn := config.Instance.DbDSN @@ -20,9 +18,9 @@ func Init() error { switch config.Instance.DbType { case "mysql": - Instance, err = sqlx.Open("mysql", dsn) + Instance, err = xorm.NewEngine("mysql", dsn) case "sqlite": - Instance, err = sqlx.Open("sqlite", dsn) + Instance, err = xorm.NewEngine("sqlite", dsn) default: return errors.New("Database Type Error!") } @@ -31,10 +29,7 @@ func Init() error { } Instance.SetMaxOpenConns(100) Instance.SetMaxIdleConns(10) - //showMySQLCharacterSet() - checkTable() - // 处理版本升级带来的数据表变更 - databaseUpdate() + return nil } @@ -45,74 +40,3 @@ func WithContext(ctx *context.Context, sql string) string { } return sql } - -type tables struct { - TablesInPmail string `db:"Tables_in_pmail"` -} - -func checkTable() { - var res []*tables - - var err error - if config.Instance.DbType == "sqlite" { - err = Instance.Select(&res, "select name as `Tables_in_pmail` from sqlite_master where type='table'") - } else { - err = Instance.Select(&res, "show tables") - } - if err != nil { - panic(err) - } - existTable := map[string]struct{}{} - for _, tableName := range res { - existTable[tableName.TablesInPmail] = struct{}{} - } - - for tableName, createSQL := range config.Instance.Tables { - if createSQL == "" { - continue - } - if _, ok := existTable[tableName]; !ok { - _, err = Instance.Exec(createSQL) - log.Infof("Create Table: %s", createSQL) - if err != nil { - panic(err) - } - - if initData, ok := config.Instance.TablesInitData[tableName]; ok { - if initData != "" { - _, err = Instance.Exec(initData) - log.Infof("Init Table: %s", initData) - if err != nil { - panic(err) - } - } - } - - } - } -} - -type tableSQL struct { - Table string `db:"Table"` - CreateTable string `db:"Create Table"` -} - -func databaseUpdate() { - // 检查email表是否有group id - var err error - var res []tableSQL - if config.Instance.DbType == "sqlite" { - err = Instance.Select(&res, "select sql as `Create Table` from sqlite_master where type='table' and tbl_name = 'email'") - } else { - err = Instance.Select(&res, "show create table `email`") - } - - if err != nil { - panic(err) - } - - if len(res) > 0 && !strings.Contains(res[0].CreateTable, "group_id") { - Instance.Exec("alter table email add group_id integer default 0 not null;") - } - -} diff --git a/server/go.mod b/server/go.mod index fc721ba..ffe9c9e 100644 --- a/server/go.mod +++ b/server/go.mod @@ -13,13 +13,13 @@ require ( github.com/emersion/go-smtp v0.21.0 github.com/go-acme/lego/v4 v4.16.1 github.com/go-sql-driver/mysql v1.8.1 - github.com/jmoiron/sqlx v1.3.5 github.com/mileusna/spf v0.9.5 github.com/sirupsen/logrus v1.9.3 github.com/spf13/cast v1.6.0 golang.org/x/crypto v0.22.0 golang.org/x/text v0.14.0 modernc.org/sqlite v1.29.6 + xorm.io/xorm v1.3.9 ) require ( @@ -27,12 +27,18 @@ require ( github.com/cenkalti/backoff/v4 v4.3.0 // indirect github.com/dustin/go-humanize v1.0.1 // indirect github.com/go-jose/go-jose/v4 v4.0.1 // indirect + github.com/goccy/go-json v0.10.2 // indirect + github.com/golang/snappy v0.0.4 // indirect github.com/google/uuid v1.6.0 // indirect github.com/hashicorp/golang-lru/v2 v2.0.7 // indirect + github.com/json-iterator/go v1.1.12 // indirect github.com/mattn/go-isatty v0.0.20 // indirect github.com/miekg/dns v1.1.58 // indirect + github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect + github.com/modern-go/reflect2 v1.0.2 // indirect github.com/ncruces/go-strftime v0.1.9 // indirect github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec // indirect + github.com/syndtr/goleveldb v1.0.0 // indirect golang.org/x/mod v0.17.0 // indirect golang.org/x/net v0.24.0 // indirect golang.org/x/sync v0.7.0 // indirect @@ -44,4 +50,5 @@ require ( modernc.org/memory v1.8.0 // indirect modernc.org/strutil v1.2.0 // indirect modernc.org/token v1.1.0 // indirect + xorm.io/builder v0.3.13 // indirect ) diff --git a/server/go.sum b/server/go.sum index 42fe558..28404f6 100644 --- a/server/go.sum +++ b/server/go.sum @@ -1,5 +1,7 @@ filippo.io/edwards25519 v1.1.0 h1:FNf4tywRC1HmFuKW5xopWpigGjJKiJSV0Cqo0cJWDaA= filippo.io/edwards25519 v1.1.0/go.mod h1:BxyFTGdWcka3PhytdK4V28tE5sGfRvvvRV7EaN4VDT4= +gitea.com/xorm/sqlfiddle v0.0.0-20180821085327-62ce714f951a h1:lSA0F4e9A2NcQSqGqTOXqu2aRi/XEQxDCBwM8yJtE6s= +gitea.com/xorm/sqlfiddle v0.0.0-20180821085327-62ce714f951a/go.mod h1:EXuID2Zs0pAQhH8yz+DNjUbjppKQzKFAn28TMYPB6IU= github.com/Jinnrry/gopop v0.0.0-20231113115125-fbdf52ae39ea h1:GISNlu8fPa2K+aySmHPSd9X0PG8GAAFEobq4XIqodMk= github.com/Jinnrry/gopop v0.0.0-20231113115125-fbdf52ae39ea/go.mod h1:xcI6e+jbXWN+T8EWOJtHbAku6pzNqyCHaFvzdeL1r2o= github.com/alexedwards/scs/mysqlstore v0.0.0-20240316134038-7e11d57e8885 h1:C7QAamNjR5yz6di4KJWAKcnxueKBgq4L/JGXhlnu35w= @@ -26,30 +28,37 @@ github.com/emersion/go-smtp v0.21.0 h1:ZDZmX9aFUuPlD1lpoT0nC/nozZuIkSCyQIyxdijjC github.com/emersion/go-smtp v0.21.0/go.mod h1:qm27SGYgoIPRot6ubfQ/GpiPy/g3PaZAVRxiO/sDUgQ= github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHkI4W8= github.com/frankban/quicktest v1.14.6/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0= +github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= github.com/go-acme/lego/v4 v4.16.1 h1:JxZ93s4KG0jL27rZ30UsIgxap6VGzKuREsSkkyzeoCQ= github.com/go-acme/lego/v4 v4.16.1/go.mod h1:AVvwdPned/IWpD/ihHhMsKnveF7HHYAz/CmtXi7OZoE= github.com/go-jose/go-jose/v4 v4.0.1 h1:QVEPDE3OluqXBQZDcnNvQrInro2h0e4eqNbnZSWqS6U= github.com/go-jose/go-jose/v4 v4.0.1/go.mod h1:WVf9LFMHh/QVrmqrOfqun0C45tMe3RoiKJMPvgWwLfY= -github.com/go-sql-driver/mysql v1.6.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg= github.com/go-sql-driver/mysql v1.7.1/go.mod h1:OXbVy3sEdcQ2Doequ6Z5BW6fXNQTmx+9S1MCJN5yJMI= github.com/go-sql-driver/mysql v1.8.1 h1:LedoTUt/eveggdHS9qUFC1EFSa8bU2+1pZjSRpvNJ1Y= github.com/go-sql-driver/mysql v1.8.1/go.mod h1:wEBSXgmK//2ZFJyE+qWnIsVGmvmEKlqwuVSjsCm7DZg= +github.com/goccy/go-json v0.10.2 h1:CrxCmQqYDkv1z7lO7Wbh2HN93uovUHgrECaO5ZrCXAU= +github.com/goccy/go-json v0.10.2/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I= +github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= +github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM= +github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/pprof v0.0.0-20221118152302-e6195bd50e26 h1:Xim43kblpZXfIBQsbuBVKCudVG457BR2GZFIz3uw3hQ= github.com/google/pprof v0.0.0-20221118152302-e6195bd50e26/go.mod h1:dDKJzRmX4S37WGHujM7tX//fmj1uioxKzKxz3lo4HJo= github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/hashicorp/golang-lru/v2 v2.0.7 h1:a+bsQ5rvGLjzHuww6tVxozPZFVghXaHOwFs4luLUK2k= github.com/hashicorp/golang-lru/v2 v2.0.7/go.mod h1:QeFd9opnmA6QUJc5vARoKUSoFhyfM2/ZepoAG6RGpeM= -github.com/jmoiron/sqlx v1.3.5 h1:vFFPA71p1o5gAeqtEAwLU4dnX2napprKtHr7PYIcN3g= -github.com/jmoiron/sqlx v1.3.5/go.mod h1:nRVWtLre0KfCLJvgxzCsLVMogSvQ1zNJtpYr2Ccp0mQ= +github.com/hpcloud/tail v1.0.0 h1:nfCOvKYfkgYP8hkirhJocXT2+zOD8yUNjXaWfTlyFKI= +github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= +github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= +github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= -github.com/lib/pq v1.2.0 h1:LXpIM/LZ5xGFhOpXAQUIMM1HdyqzVYM13zNdjCEEcA0= -github.com/lib/pq v1.2.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= github.com/mattn/go-sqlite3 v1.14.6/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU= @@ -60,8 +69,18 @@ github.com/miekg/dns v1.1.58 h1:ca2Hdkz+cDg/7eNF6V56jjzuZ4aCAE+DbVkILdQWG/4= github.com/miekg/dns v1.1.58/go.mod h1:Ypv+3b/KadlvW9vJfXOTf300O4UqaHFzFCuHz+rPkBY= github.com/mileusna/spf v0.9.5 h1:P6cmaIBwrhZaP9stXMzGOtxe+gIu65OVbZCmrAv9rgU= github.com/mileusna/spf v0.9.5/go.mod h1:o6IdTae6QptAbLgx/+ueXSTSpkG+f1cqLemQJSew8sI= +github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M= +github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= github.com/ncruces/go-strftime v0.1.9 h1:bY0MQC28UADQmHmaF5dgpLmImcShSi2kHU9XLdhx/f4= github.com/ncruces/go-strftime v0.1.9/go.mod h1:Fwc5htZGVVkseilnfgOVb9mKy6w1naJmn9CehxcKcls= +github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/ginkgo v1.7.0 h1:WSHQ+IS43OoUrWtD1/bbclrwK8TTH5hzp+umCiuxHgs= +github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/gomega v1.4.3 h1:RE1xgDvH7imwFD45h+u2SgIfERHlS2yNG4DObb5BSKU= +github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec h1:W09IVJc94icq4NjY3clb7Lk8O1qJ8BdBEF8z0ibU0rE= @@ -73,9 +92,12 @@ github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVs github.com/spf13/cast v1.6.0 h1:GEiTHELF+vaR5dhz3VqZfFSzZjYbgeKDpBxQVS4GYJ0= github.com/spf13/cast v1.6.0/go.mod h1:ancEpBxwJDODSW/UG4rDrAqiKolqNNh2DX3mk86cAdo= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= +github.com/syndtr/goleveldb v1.0.0 h1:fBdIW9lB4Iz0n9khmH8w27SJ3QEJ7+IgjPEwGSZiFdE= +github.com/syndtr/goleveldb v1.0.0/go.mod h1:ZVVdQEZoIme9iO1Ch2Jdy24qqXrMMOU6lpPAyBWyWuQ= github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= @@ -88,6 +110,7 @@ golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91 golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/mod v0.17.0 h1:zY54UmvipHiNd+pm+m0x9KhZ9hl1/7QNMyxXbc6ICqA= golang.org/x/mod v0.17.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= +golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= @@ -97,12 +120,14 @@ golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= golang.org/x/net v0.24.0 h1:1PcaxkF854Fu3+lvBIx5SYn9wRlBzzcnHZSiaFFAb0w= golang.org/x/net v0.24.0/go.mod h1:2Q7sJY5mzlzWjKtYUEXSlBWCdyaioyXzRB2RtU8KVE8= +golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.7.0 h1:YsImfSBoP9QPYL0xyKJPq0gcaJdG3rInoqxTWbfQu9M= golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= +golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -139,6 +164,13 @@ golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8T golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/fsnotify.v1 v1.4.7 h1:xOHLXZwVvI9hhs+cLKq5+I5onOuwQLhQwiu63xxlHs4= +gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= +gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ= +gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= +gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= +gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= @@ -168,3 +200,7 @@ modernc.org/strutil v1.2.0 h1:agBi9dp1I+eOnxXeiZawM8F4LawKv4NzGWSaLfyeNZA= modernc.org/strutil v1.2.0/go.mod h1:/mdcBmfOibveCTBxUl5B5l6W+TTH1FXPLHZE6bTosX0= modernc.org/token v1.1.0 h1:Xl7Ap9dKaEs5kLoOQeQmPWevfnk/DM5qcLcYlA8ys6Y= modernc.org/token v1.1.0/go.mod h1:UGzOrNV1mAFSEB63lOFHIpNRUVMvYTc6yu1SMY/XTDM= +xorm.io/builder v0.3.13 h1:a3jmiVVL19psGeXx8GIurTp7p0IIgqeDmwhcR6BAOAo= +xorm.io/builder v0.3.13/go.mod h1:aUW0S9eb9VCaPohFCH3j7czOx1PMW3i1HrSzbLYGBSE= +xorm.io/xorm v1.3.9 h1:TUovzS0ko+IQ1XnNLfs5dqK1cJl1H5uHpWbWqAQ04nU= +xorm.io/xorm v1.3.9/go.mod h1:LsCCffeeYp63ssk0pKumP6l96WZcHix7ChpurcLNuMw= diff --git a/server/i18n/i18n.go b/server/i18n/i18n.go index 90fe965..1fa4a1d 100644 --- a/server/i18n/i18n.go +++ b/server/i18n/i18n.go @@ -14,6 +14,7 @@ var ( "login_exp": "登录已失效", "ip_taps": "这是你服务器IP,确保这个IP正确", "invalid_email_address": "无效的邮箱地址!", + "deleted": "垃圾箱", } en = map[string]string{ "all_email": "All Email", @@ -28,6 +29,7 @@ var ( "login_exp": "Login has expired.", "ip_taps": "This is your server's IP, make sure it is correct.", "invalid_email_address": "Invalid e-mail address!", + "deleted": "Deleted", } ) diff --git a/server/models/User.go b/server/models/User.go index d15ad83..aa9e4b1 100644 --- a/server/models/User.go +++ b/server/models/User.go @@ -1,8 +1,12 @@ package models type User struct { - ID int `db:"id"` - Account string `db:"account"` - Name string `db:"name"` - Password string `db:"password"` + ID int `xorm:"id unsigned int not null pk autoincr"` + Account string `xorm:"varchar(20) notnull unique comment('账号登陆名')"` + Name string `xorm:"varchar(10) notnull comment('用户名')"` + Password string `xorm:"char(32) notnull comment('登陆密码,两次md5加盐,md5(md5(password+pmail) +pmail2023)')"` +} + +func (p User) TableName() string { + return "user" } diff --git a/server/models/auth.go b/server/models/auth.go index 237aef1..0ecb9c6 100644 --- a/server/models/auth.go +++ b/server/models/auth.go @@ -1,7 +1,11 @@ package models type UserAuth struct { - ID int `db:"id"` - UserID int `db:"user_id"` - EmailAccount string `db:"email_account"` + ID int `xorm:"id int unsigned not null pk autoincr"` + UserID int `xorm:"user_id int not null unique('uid_account') index comment('用户id')"` + EmailAccount string `xorm:"email_account not null unique('uid_account') index comment('收信人前缀')"` +} + +func (p UserAuth) TableName() string { + return "user_auth" } diff --git a/server/models/email.go b/server/models/email.go index ac3d620..b8ed539 100644 --- a/server/models/email.go +++ b/server/models/email.go @@ -8,30 +8,34 @@ import ( ) type Email struct { - Id int `db:"id" json:"id"` - Type int8 `db:"type" json:"type"` - GroupId int `db:"group_id" json:"group_id"` - Subject string `db:"subject" json:"subject"` - ReplyTo string `db:"reply_to" json:"reply_to"` - FromName string `db:"from_name" json:"from_name"` - FromAddress string `db:"from_address" json:"from_address"` - To string `db:"to" json:"to"` - Bcc string `db:"bcc" json:"bcc"` - Cc string `db:"cc" json:"cc"` - Text sql.NullString `db:"text" json:"text"` - Html sql.NullString `db:"html" json:"html"` - Sender string `db:"sender" json:"sender"` - Attachments string `db:"attachments" json:"attachments"` - SPFCheck int8 `db:"spf_check" json:"spf_check"` - DKIMCheck int8 `db:"dkim_check" json:"dkim_check"` - Status int8 `db:"status" json:"status"` // 0未发送,1已发送,2发送失败,3删除 - CronSendTime time.Time `db:"cron_send_time" json:"cron_send_time"` - UpdateTime time.Time `db:"update_time" json:"update_time"` - SendUserID int `db:"send_user_id" json:"send_user_id"` - IsRead int8 `db:"is_read" json:"is_read"` - Error sql.NullString `db:"error" json:"error"` - SendDate time.Time `db:"send_date" json:"send_date"` - CreateTime time.Time `db:"create_time" json:"create_time"` + Id int `xorm:"id pk unsigned int autoincr notnull" json:"id"` + Type int8 `xorm:"type tinyint(4) notnull default(0) comment('邮件类型,0:收到的邮件,1:发送的邮件')" json:"type"` + GroupId int `xorm:"group_id int notnull default(0) comment('分组id')'" json:"group_id"` + Subject string `xorm:"subject varchar(1000) notnull default('') comment('邮件标题')" json:"subject"` + ReplyTo string `xorm:"reply_to text comment('回复人')" json:"reply_to"` + FromName string `xorm:"from_name varchar(50) notnull default('') comment('发件人名称')" json:"from_name"` + FromAddress string `xorm:"from_address varchar(100) notnull default('') comment('发件人邮件地址')" json:"from_address"` + To string `xorm:"to text comment('收件人地址')" json:"to"` + Bcc string `xorm:"bcc text comment('密送')" json:"bcc"` + Cc string `xorm:"cc text comment('抄送')" json:"cc"` + Text sql.NullString `xorm:"text text comment('文本内容')" json:"text"` + Html sql.NullString `xorm:"html mediumtext comment('html内容')" json:"html"` + Sender string `xorm:"sender text comment('发送人')" json:"sender"` + Attachments string `xorm:"attachments longtext comment('附件')" json:"attachments"` + SPFCheck int8 `xorm:"spf_check tinyint(1) comment('spf校验是否通过')" json:"spf_check"` + DKIMCheck int8 `xorm:"dkim_check tinyint(1) comment('dkim校验是否通过')" json:"dkim_check"` + Status int8 `xorm:"status tinyint(4) notnull default(0) comment('0未发送,1已发送,2发送失败,3删除')" json:"status"` // 0未发送,1已发送,2发送失败,3删除 + CronSendTime time.Time `xorm:"cron_send_time comment('定时发送时间')" json:"cron_send_time"` + UpdateTime time.Time `xorm:"update_time updated comment('更新时间')" json:"update_time"` + SendUserID int `xorm:"send_user_id unsigned int notnull default(0) comment('发件人用户id')" json:"send_user_id"` + IsRead int8 `xorm:"is_read tinyint(1) comment('是否已读')" json:"is_read"` + Error sql.NullString `xorm:"error text comment('投递错误信息')" json:"error"` + SendDate time.Time `xorm:"send_date comment('投递时间')" json:"send_date"` + CreateTime time.Time `xorm:"create_time created" json:"create_time"` +} + +func (p Email) TableName() string { + return "email" } type attachments struct { diff --git a/server/models/group.go b/server/models/group.go index e67e14f..88de9ea 100644 --- a/server/models/group.go +++ b/server/models/group.go @@ -1,8 +1,12 @@ package models type Group struct { - ID int `db:"id" json:"id"` - Name string `db:"name" json:"name"` - ParentId int `db:"parent_id" json:"parent_id"` - UserId int `db:"user_id" json:"-"` + ID int `xorm:"id int unsigned not null pk autoincr" json:"id"` + Name string `xorm:"varchar(10) notnull default('') comment('分组名称')" json:"name"` + ParentId int `xorm:"parent_id int unsigned notnull default(0) comment('父分组名称')" json:"parent_id"` + UserId int `xorm:"user_id int unsigned notnull default(0) comment('用户id')" json:"-"` +} + +func (p *Group) TableName() string { + return "group" } diff --git a/server/models/rule.go b/server/models/rule.go index 40f07ef..d32f3c7 100644 --- a/server/models/rule.go +++ b/server/models/rule.go @@ -7,13 +7,17 @@ import ( ) type Rule struct { - Id int `db:"id" json:"id"` - UserId string `db:"user_id" json:"user_id"` - Name string `db:"name" json:"name"` - Value string `db:"value" json:"value"` - Action int `db:"action" json:"action"` - Params string `db:"params" json:"params"` - Sort int `db:"sort" json:"sort"` + Id int `xorm:"id int unsigned not null pk autoincr" json:"id"` + UserId int `xorm:"user_id notnull default(0) comment('用户id')" json:"user_id"` + Name string `xorm:"name notnull default('') comment('规则名称')" json:"name"` + Value string `xorm:"value text comment('规则内容')" json:"value"` + Action int `xorm:"action notnull default(0) comment('执行动作,1已读,2转发,3删除')" json:"action"` + Params string `xorm:"params notnull default('') comment('执行参数')" json:"params"` + Sort int `xorm:"sort notnull default(0) comment('排序,越大约优先')" json:"sort"` +} + +func (p *Rule) TableName() string { + return "rule" } func (p *Rule) Save(ctx *context.Context) error { diff --git a/server/pop3_server/action.go b/server/pop3_server/action.go index 03b77a9..3516d9a 100644 --- a/server/pop3_server/action.go +++ b/server/pop3_server/action.go @@ -100,7 +100,7 @@ func (a action) Pass(session *gopop.Session, pwd string) error { encodePwd := password.Encode(pwd) - err := db.Instance.Get(&user, db.WithContext(session.Ctx.(*context.Context), "select * from user where account =? and password =?"), session.User, encodePwd) + _, err := db.Instance.Where("account =? and password =?", session.User, encodePwd).Get(&user) if err != nil && !errors.Is(err, sql.ErrNoRows) { log.WithContext(session.Ctx.(*context.Context)).Errorf("%+v", err) } @@ -136,7 +136,7 @@ func (a action) Apop(session *gopop.Session, username, digest string) error { var user models.User - err := db.Instance.Get(&user, db.WithContext(session.Ctx.(*context.Context), "select * from user where account =? "), username) + _, err := db.Instance.Where("account =? ", username).Get(&user) if err != nil && !errors.Is(err, sql.ErrNoRows) { log.WithContext(session.Ctx.(*context.Context)).Errorf("%+v", err) } @@ -166,7 +166,7 @@ func (a action) Stat(session *gopop.Session) (msgNum, msgSize int64, err error) log.WithContext(session.Ctx).Debugf("POP3 CMD: STAT") var si statInfo - err = db.Instance.Get(&si, db.WithContext(session.Ctx.(*context.Context), "select count(1) as `num`, sum(length(text)+length(html)) as `size` from email where type = 0")) + _, err = db.Instance.Select("count(1) as `num`, sum(length(text)+length(html)) as `size`").Table("email").Where("type=0 and status=0").Get(&si) if err != nil && !errors.Is(err, sql.ErrNoRows) { log.WithContext(session.Ctx.(*context.Context)).Errorf("%+v", err) err = nil @@ -197,8 +197,7 @@ func (a action) Uidl(session *gopop.Session, msg string) ([]gopop.UidlItem, erro var err error var ssql string - ssql = db.WithContext(session.Ctx.(*context.Context), "SELECT id FROM email where type = 0") - err = db.Instance.Select(&res, ssql) + err = db.Instance.Where("type=0 and status=0").Select("id").Table("email").Find(&res) if err != nil && !errors.Is(err, sql.ErrNoRows) { log.WithContext(session.Ctx.(*context.Context)).Errorf("SQL:%s Error: %+v", ssql, err) @@ -235,11 +234,9 @@ func (a action) List(session *gopop.Session, msg string) ([]gopop.MailInfo, erro var ssql string if listId != 0 { - ssql = db.WithContext(session.Ctx.(*context.Context), "SELECT id, ifnull(LENGTH(TEXT) , 0) + ifnull(LENGTH(html) , 0) AS `size` FROM email where id =?") - err = db.Instance.Select(&res, ssql, listId) + err = db.Instance.Select("id, ifnull(LENGTH(TEXT) , 0) + ifnull(LENGTH(html) , 0) AS `size`").Table("email").Where("id=?", listId).Find(&res) } else { - ssql = db.WithContext(session.Ctx.(*context.Context), "SELECT id, ifnull(LENGTH(TEXT) , 0) + ifnull(LENGTH(html) , 0) AS `size` FROM email where type = 0") - err = db.Instance.Select(&res, ssql) + err = db.Instance.Select("id, ifnull(LENGTH(TEXT) , 0) + ifnull(LENGTH(html) , 0) AS `size`").Table("email").Where("type=0 and status=0").Find(&res) } if err != nil && !errors.Is(err, sql.ErrNoRows) { diff --git a/server/res_init/init.go b/server/res_init/init.go index f75c321..0d99b6e 100644 --- a/server/res_init/init.go +++ b/server/res_init/init.go @@ -9,6 +9,7 @@ import ( "pmail/dto/parsemail" "pmail/hooks" "pmail/http_server" + "pmail/models" "pmail/pop3_server" "pmail/services/setup/ssl" "pmail/session" @@ -37,6 +38,7 @@ func Init(serverVersion string) { if err != nil { panic(err) } + syncTables() session.Init() hooks.Init(serverVersion) // smtp server start @@ -84,3 +86,26 @@ func dirInit() { } } } + +func syncTables() { + err := db.Instance.Sync2(&models.User{}) + if err != nil { + panic(err) + } + err = db.Instance.Sync2(&models.Email{}) + if err != nil { + panic(err) + } + err = db.Instance.Sync2(&models.Group{}) + if err != nil { + panic(err) + } + err = db.Instance.Sync2(&models.Rule{}) + if err != nil { + panic(err) + } + err = db.Instance.Sync2(&models.UserAuth{}) + if err != nil { + panic(err) + } +} diff --git a/server/services/attachments/attachments.go b/server/services/attachments/attachments.go index 6b6d257..9d266f5 100644 --- a/server/services/attachments/attachments.go +++ b/server/services/attachments/attachments.go @@ -14,7 +14,7 @@ func GetAttachments(ctx *context.Context, emailId int, cid string) (string, []by // 获取邮件内容 var email models.Email - err := db.Instance.Get(&email, db.WithContext(ctx, "select * from email where id = ?"), emailId) + _, err := db.Instance.ID(emailId).Get(&email) if err != nil { log.WithContext(ctx).Errorf("SQL error:%+v", err) return "", nil @@ -39,7 +39,7 @@ func GetAttachmentsByIndex(ctx *context.Context, emailId int, index int) (string // 获取邮件内容 var email models.Email - err := db.Instance.Get(&email, db.WithContext(ctx, "select * from email where id = ?"), emailId) + _, err := db.Instance.ID(emailId).Get(&email) if err != nil { log.WithContext(ctx).Errorf("SQL error:%+v", err) return "", nil diff --git a/server/services/auth/auth.go b/server/services/auth/auth.go index dfb40a0..cf7a0c6 100644 --- a/server/services/auth/auth.go +++ b/server/services/auth/auth.go @@ -19,7 +19,7 @@ import ( func HasAuth(ctx *context.Context, email *models.Email) bool { // 获取当前用户的auth var auth []models.UserAuth - err := db.Instance.Select(&auth, db.WithContext(ctx, "select * from user_auth where user_id = ?"), ctx.UserID) + err := db.Instance.Where("user_id = ?", ctx.UserID).Find(&auth) if err != nil { log.WithContext(ctx).Errorf("SQL error:%+v", err) return false diff --git a/server/services/del_email/del_email.go b/server/services/del_email/del_email.go index 3fe63bf..410d9d0 100644 --- a/server/services/del_email/del_email.go +++ b/server/services/del_email/del_email.go @@ -13,8 +13,10 @@ import ( func DelEmail(ctx *context.Context, ids []int) error { var emails []*models.Email - db.Instance.Select(&emails, db.WithContext(ctx, fmt.Sprintf("select * from email where id in (%s)", array.Join(ids, ",")))) - + err := db.Instance.ID(ids).Find(&emails) + if err != nil { + return errors.Wrap(err) + } for _, email := range emails { // 检查是否有权限 hasAuth := auth.HasAuth(ctx, email) @@ -23,8 +25,7 @@ func DelEmail(ctx *context.Context, ids []int) error { } } - //_, err := db.Instance.Exec(db.WithContext(ctx, fmt.Sprintf("delete from email where id in (%s)", array.Join(ids, ",")))) - _, err := db.Instance.Exec(db.WithContext(ctx, fmt.Sprintf("update email set status = 3 where id in (%s)", array.Join(ids, ",")))) + _, err = db.Instance.Exec(db.WithContext(ctx, fmt.Sprintf("update email set status = 3 where id in (%s)", array.Join(ids, ",")))) if err != nil { return errors.Wrap(err) } diff --git a/server/services/detail/detail.go b/server/services/detail/detail.go index 8997c4c..99c6dba 100644 --- a/server/services/detail/detail.go +++ b/server/services/detail/detail.go @@ -15,7 +15,7 @@ import ( func GetEmailDetail(ctx *context.Context, id int, markRead bool) (*models.Email, error) { // 获取邮件内容 var email models.Email - err := db.Instance.Get(&email, db.WithContext(ctx, "select * from email where id = ?"), id) + _, err := db.Instance.ID(id).Get(&email) if err != nil { log.WithContext(ctx).Errorf("SQL error:%+v", err) return nil, err diff --git a/server/services/group/group.go b/server/services/group/group.go index 55d56e7..98e8db4 100644 --- a/server/services/group/group.go +++ b/server/services/group/group.go @@ -23,10 +23,7 @@ func DelGroup(ctx *context.Context, groupId int) (bool, error) { allGroupIds = append(allGroupIds, groupId) // 开启一个事务 - trans, err := db.Instance.Begin() - if err != nil { - return false, errors.Wrap(err) - } + trans := db.Instance.NewSession() res, err := trans.Exec(db.WithContext(ctx, fmt.Sprintf("delete from `group` where id in (%s) and user_id =?", array.Join(allGroupIds, ","))), ctx.UserID) if err != nil { @@ -57,7 +54,10 @@ type id struct { func getAllChildId(ctx *context.Context, rootId int) []int { var ids []id var ret []int - db.Instance.Select(&ids, db.WithContext(ctx, "select id from `group` where parent_id=? and user_id=?"), rootId, ctx.UserID) + err := db.Instance.Table("group").Where("parent_id=? and user_id=?", rootId, ctx.UserID).Find(&ids) + if err != nil { + log.WithContext(ctx).Errorf("getAllChildId err: %v", err) + } for _, item := range ids { ret = array.Merge(ret, getAllChildId(ctx, item.Id)) ret = append(ret, item.Id) @@ -89,7 +89,7 @@ func MoveMailToGroup(ctx *context.Context, mailId []int, groupId int) bool { func buildChildren(ctx *context.Context, parentId int) []*GroupItem { var ret []*GroupItem var rootGroup []*models.Group - err := db.Instance.Select(&rootGroup, db.WithContext(ctx, "select * from `group` where parent_id=? and user_id=?"), parentId, ctx.UserID) + err := db.Instance.Table("group").Where("parent_id=? and user_id=?", parentId, ctx.UserID).Find(&rootGroup) if err != nil { log.WithContext(ctx).Errorf("SQL Error:%v", err) @@ -110,6 +110,6 @@ func buildChildren(ctx *context.Context, parentId int) []*GroupItem { func GetGroupList(ctx *context.Context) []*models.Group { var ret []*models.Group - db.Instance.Select(&ret, db.WithContext(ctx, "select * from `group` where user_id=?"), ctx.UserID) + db.Instance.Table("group").Where("user_id=?", ctx.UserID).Find(&ret) return ret } diff --git a/server/services/list/list.go b/server/services/list/list.go index 485cca0..538d73e 100644 --- a/server/services/list/list.go +++ b/server/services/list/list.go @@ -9,17 +9,11 @@ import ( "pmail/utils/context" ) -func GetEmailList(ctx *context.Context, tag string, keyword string, offset, limit int) (emailList []*models.Email, total int) { +func GetEmailList(ctx *context.Context, tag string, keyword string, offset, limit int) (emailList []*models.Email, total int64) { - querySQL, queryParams := genSQL(ctx, false, tag, keyword, offset, limit) - counterSQL, counterParams := genSQL(ctx, true, tag, keyword, offset, limit) + querySQL, queryParams := genSQL(ctx, tag, keyword) - err := db.Instance.Select(&emailList, db.WithContext(ctx, querySQL), queryParams...) - if err != nil { - log.Errorf("SQL ERROR: %s ,Error:%s", querySQL, err) - } - - err = db.Instance.Get(&total, db.WithContext(ctx, counterSQL), counterParams...) + total, err := db.Instance.Table("email").Where(querySQL, queryParams...).Desc("id").Limit(limit, offset).FindAndCount(&emailList) if err != nil { log.Errorf("SQL ERROR: %s ,Error:%s", querySQL, err) } @@ -27,12 +21,9 @@ func GetEmailList(ctx *context.Context, tag string, keyword string, offset, limi return } -func genSQL(ctx *context.Context, counter bool, tag, keyword string, offset, limit int) (string, []any) { +func genSQL(ctx *context.Context, tag, keyword string) (string, []any) { - sql := "select * from email where 1=1 " - if counter { - sql = "select count(1) from email where 1=1 " - } + sql := "1=1 " sqlParams := []any{} @@ -61,8 +52,5 @@ func genSQL(ctx *context.Context, counter bool, tag, keyword string, offset, lim sqlParams = append(sqlParams, "%"+keyword+"%", "%"+keyword+"%") } - sql += " order by id desc limit ? offset ?" - sqlParams = append(sqlParams, limit, offset) - return sql, sqlParams } diff --git a/server/services/rule/rule.go b/server/services/rule/rule.go index eeb0db4..a8803dd 100644 --- a/server/services/rule/rule.go +++ b/server/services/rule/rule.go @@ -18,9 +18,9 @@ func GetAllRules(ctx *context.Context) []*dto.Rule { var res []*models.Rule var err error if ctx == nil || ctx.UserID == 0 { - err = db.Instance.Select(&res, "select * from rule order by sort desc") + err = db.Instance.Decr("sort").Find(&res) } else { - err = db.Instance.Select(&res, db.WithContext(ctx, "select * from rule where user_id=? order by sort desc"), ctx.UserID) + err = db.Instance.Where("user_id=?", ctx.UserID).Decr("sort").Find(&res) } if err != nil { diff --git a/server/services/setup/db.go b/server/services/setup/db.go index eda9568..d327bcc 100644 --- a/server/services/setup/db.go +++ b/server/services/setup/db.go @@ -29,7 +29,7 @@ func GetDatabaseSettings(ctx *context.Context) (string, string, error) { func GetAdminPassword(ctx *context.Context) (string, error) { users := []*models.User{} - err := db.Instance.Select(&users, "select * from user") + err := db.Instance.Find(&users) if err != nil { return "", errors.Wrap(err) } diff --git a/server/session/init.go b/server/session/init.go index e855f04..e6c5fdd 100644 --- a/server/session/init.go +++ b/server/session/init.go @@ -18,8 +18,8 @@ func Init() { // 使用db存储session数据,目前为了架构简单, // 暂不引入redis存储,如果日后性能存在瓶颈,可以将session迁移到redis if config.Instance.DbType == "mysql" { - Instance.Store = mysqlstore.New(db.Instance.DB) + Instance.Store = mysqlstore.New(db.Instance.DB().DB) } else { - Instance.Store = sqlite3store.New(db.Instance.DB) + Instance.Store = sqlite3store.New(db.Instance.DB().DB) } } diff --git a/server/smtp_server/read_content.go b/server/smtp_server/read_content.go index b5e1519..cfb3589 100644 --- a/server/smtp_server/read_content.go +++ b/server/smtp_server/read_content.go @@ -2,9 +2,11 @@ package smtp_server import ( "bytes" + "database/sql" "encoding/json" "github.com/mileusna/spf" log "github.com/sirupsen/logrus" + "github.com/spf13/cast" "io" "net" "net/netip" @@ -13,6 +15,7 @@ import ( "pmail/dto/parsemail" "pmail/hooks" "pmail/hooks/framework" + "pmail/models" "pmail/services/rule" "pmail/utils/async" "pmail/utils/context" @@ -83,12 +86,40 @@ func (s *Session) Data(r io.Reader) error { } // 转发 - err := saveEmail(ctx, email, 1, true, true) + err := saveEmail(ctx, email, s.Ctx.UserID, 1, true, true) if err != nil { log.WithContext(ctx).Errorf("Email Save Error %v", err) } - send.Send(ctx, email) + errMsg := "" + err, sendErr := send.Send(ctx, email) + + log.WithContext(ctx).Debugf("插件执行--SendAfter") + + as3 := async.New(ctx) + for _, hook := range hooks.HookList { + if hook == nil { + continue + } + as3.WaitProcess(func(hk any) { + hk.(framework.EmailHook).SendAfter(ctx, email, sendErr) + }, hook) + } + as3.Wait() + log.WithContext(ctx).Debugf("插件执行--SendAfter") + + if err != nil { + errMsg = err.Error() + _, err := db.Instance.Exec(db.WithContext(ctx, "update email set status =2 ,error=? where id = ? "), errMsg, email.MessageId) + if err != nil { + log.WithContext(ctx).Errorf("sql Error :%+v", err) + } + } else { + _, err := db.Instance.Exec(db.WithContext(ctx, "update email set status =1 where id = ? "), email.MessageId) + if err != nil { + log.WithContext(ctx).Errorf("sql Error :%+v", err) + } + } } else { // 收件 @@ -121,7 +152,18 @@ func (s *Session) Data(r io.Reader) error { return nil } - saveEmail(ctx, email, 0, SPFStatus, dkimStatus) + // 垃圾过滤 + if config.Instance.SpamFilterLevel == 1 && !SPFStatus && !dkimStatus { + log.WithContext(ctx).Infoln("垃圾邮件,拒信") + return nil + } + + if config.Instance.SpamFilterLevel == 2 && !SPFStatus { + log.WithContext(ctx).Infoln("垃圾邮件,拒信") + return nil + } + + saveEmail(ctx, email, 0, 0, SPFStatus, dkimStatus) if email.MessageId > 0 { log.WithContext(ctx).Debugf("开始执行邮件规则!") @@ -152,7 +194,7 @@ func (s *Session) Data(r io.Reader) error { return nil } -func saveEmail(ctx *context.Context, email *parsemail.Email, emailType int, SPFStatus, dkimStatus bool) error { +func saveEmail(ctx *context.Context, email *parsemail.Email, sendUserID int, emailType int, SPFStatus, dkimStatus bool) error { var dkimV, spfV int8 if dkimStatus { dkimV = 1 @@ -161,52 +203,42 @@ func saveEmail(ctx *context.Context, email *parsemail.Email, emailType int, SPFS spfV = 1 } - // 垃圾过滤 - if config.Instance.SpamFilterLevel == 1 && !SPFStatus && !dkimStatus { - log.WithContext(ctx).Infoln("垃圾邮件,拒信") - return nil - } - - if config.Instance.SpamFilterLevel == 2 && !SPFStatus { - log.WithContext(ctx).Infoln("垃圾邮件,拒信") - return nil - } - log.WithContext(ctx).Debugf("开始入库!") if email == nil { return nil } - sql := "INSERT INTO email (type, send_date, subject, reply_to, from_name, from_address, `to`, bcc, cc, text, html, sender, attachments,spf_check, dkim_check, create_time,is_read,status,group_id) VALUES (?,?,?,?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)" - res, err := db.Instance.Exec(sql, - emailType, - email.Date, - email.Subject, - json2string(email.ReplyTo), - email.From.Name, - email.From.EmailAddress, - json2string(email.To), - json2string(email.Bcc), - json2string(email.Cc), - email.Text, - email.HTML, - json2string(email.Sender), - json2string(email.Attachments), - spfV, - dkimV, - time.Now(), - email.IsRead, - email.Status, - email.GroupId, - ) + modelEmail := models.Email{ + Type: cast.ToInt8(emailType), + GroupId: email.GroupId, + Subject: email.Subject, + ReplyTo: json2string(email.ReplyTo), + FromName: email.From.Name, + FromAddress: email.From.EmailAddress, + To: json2string(email.To), + Bcc: json2string(email.Bcc), + Cc: json2string(email.Cc), + Text: sql.NullString{String: string(email.Text), Valid: true}, + Html: sql.NullString{String: string(email.HTML), Valid: true}, + Sender: json2string(email.Sender), + Attachments: json2string(email.Attachments), + SPFCheck: spfV, + DKIMCheck: dkimV, + SendUserID: sendUserID, + SendDate: time.Now(), + Status: cast.ToInt8(email.Status), + CreateTime: time.Now(), + } + + _, err := db.Instance.Insert(&modelEmail) if err != nil { log.WithContext(ctx).Errorf("db insert error:%+v", err.Error()) } - insertId, _ := res.LastInsertId() - if insertId > 0 { - email.MessageId = insertId + + if modelEmail.Id > 0 { + email.MessageId = cast.ToInt64(modelEmail.Id) } return nil diff --git a/server/smtp_server/smtp.go b/server/smtp_server/smtp.go index 7b6b432..9385a74 100644 --- a/server/smtp_server/smtp.go +++ b/server/smtp_server/smtp.go @@ -81,8 +81,7 @@ func (s *Session) AuthPlain(username, pwd string) error { username = infos[0] } - err := db.Instance.Get(&user, db.WithContext(s.Ctx, "select * from user where account =? and password =?"), - username, encodePwd) + _, err := db.Instance.Where("account =? and password =?", username, encodePwd).Get(&user) if err != nil && err != sql.ErrNoRows { log.Errorf("%+v", err) }