diff --git a/app/src-tauri/tauri.conf.json b/app/src-tauri/tauri.conf.json index 925922b..3185925 100644 --- a/app/src-tauri/tauri.conf.json +++ b/app/src-tauri/tauri.conf.json @@ -8,7 +8,7 @@ }, "package": { "productName": "chatnio", - "version": "3.9.1" + "version": "3.9.2" }, "tauri": { "allowlist": { diff --git a/app/src/conf/index.ts b/app/src/conf/index.ts index aa909af..15f04b0 100644 --- a/app/src/conf/index.ts +++ b/app/src/conf/index.ts @@ -9,7 +9,7 @@ import { syncSiteInfo } from "@/admin/api/info.ts"; import { getOfflineModels, loadPreferenceModels } from "@/conf/storage.ts"; import { setAxiosConfig } from "@/conf/api.ts"; -export const version = "3.9.1"; // version of the current build +export const version = "3.9.2"; // version of the current build export const dev: boolean = getDev(); // is in development mode (for debugging, in localhost origin) export const deploy: boolean = true; // is production environment (for api endpoint) export const tokenField = getTokenField(deploy); // token field name for storing token diff --git a/auth/auth.go b/auth/auth.go index c2d2568..e4e9b73 100644 --- a/auth/auth.go +++ b/auth/auth.go @@ -290,6 +290,10 @@ func (u *User) Validate(c *gin.Context) bool { return false } + if u.IsBanned(db) { + return false + } + cache.Set(c, fmt.Sprintf("nio:user:%s", u.Username), u.Password, 30*time.Minute) return true } diff --git a/auth/struct.go b/auth/struct.go index 97be222..074e8d9 100644 --- a/auth/struct.go +++ b/auth/struct.go @@ -16,6 +16,7 @@ type User struct { Admin bool `json:"is_admin"` Level int `json:"level"` Subscription *time.Time `json:"subscription"` + Banned bool `json:"is_banned"` } func GetUserById(db *sql.DB, id int64) *User { @@ -49,6 +50,20 @@ func GetId(db *sql.DB, user *User) int64 { return user.GetID(db) } +func (u *User) IsBanned(db *sql.DB) bool { + if u.Banned { + return true + } + + var banned sql.NullBool + if err := db.QueryRow("SELECT is_banned FROM auth WHERE username = ?", u.Username).Scan(&banned); err != nil { + return false + } + u.Banned = banned.Valid && banned.Bool + + return u.Banned +} + func (u *User) IsAdmin(db *sql.DB) bool { if u.Admin { return true diff --git a/connection/database.go b/connection/database.go index 9ea1156..fd30521 100644 --- a/connection/database.go +++ b/connection/database.go @@ -59,6 +59,10 @@ func ConnectMySQL() *sql.DB { CreateRedeemTable(db) CreateBroadcastTable(db) + if err := doMigration(db); err != nil { + fmt.Println(fmt.Sprintf("migration error: %s", err)) + } + DB = db return db @@ -128,8 +132,8 @@ func CreateQuotaTable(db *sql.DB) { CREATE TABLE IF NOT EXISTS quota ( id INT PRIMARY KEY AUTO_INCREMENT, user_id INT UNIQUE, - quota DECIMAL(16, 4), - used DECIMAL(16, 4), + quota DECIMAL(24, 6), + used DECIMAL(24, 6), created_at DATETIME DEFAULT CURRENT_TIMESTAMP, updated_at DATETIME DEFAULT CURRENT_TIMESTAMP, FOREIGN KEY (user_id) REFERENCES auth(id) @@ -215,7 +219,7 @@ func CreateInvitationTable(db *sql.DB) { CREATE TABLE IF NOT EXISTS invitation ( id INT PRIMARY KEY AUTO_INCREMENT, code VARCHAR(255) UNIQUE, - quota DECIMAL(12, 4), + quota DECIMAL(16, 4), type VARCHAR(255), used BOOLEAN DEFAULT FALSE, used_id INT, @@ -235,7 +239,7 @@ func CreateRedeemTable(db *sql.DB) { CREATE TABLE IF NOT EXISTS redeem ( id INT PRIMARY KEY AUTO_INCREMENT, code VARCHAR(255) UNIQUE, - quota DECIMAL(12, 4), + quota DECIMAL(16, 4), used BOOLEAN DEFAULT FALSE, created_at DATETIME DEFAULT CURRENT_TIMESTAMP, updated_at DATETIME DEFAULT CURRENT_TIMESTAMP diff --git a/connection/db_migration.go b/connection/db_migration.go new file mode 100644 index 0000000..0c4367a --- /dev/null +++ b/connection/db_migration.go @@ -0,0 +1,56 @@ +package connection + +import ( + "database/sql" + "strings" +) + +func validSqlError(err error) bool { + if err == nil { + return false + } + + content := err.Error() + + // Error 1060: Duplicate column name + // Error 1050: Table already exists + + return !(strings.Contains(content, "Error 1060") && strings.Contains(content, "Error 1050")) +} + +func checkSqlError(_ sql.Result, err error) error { + if validSqlError(err) { + return err + } + + return nil +} + +func execSql(db *sql.DB, sql string, args ...interface{}) error { + return checkSqlError(db.Exec(sql, args...)) +} + +func doMigration(db *sql.DB) error { + // v3.10 migration + + // update `quota`, `used` field in `quota` table + // migrate `DECIMAL(16, 4)` to `DECIMAL(24, 6)` + + if err := execSql(db, ` + ALTER TABLE quota + MODIFY COLUMN quota DECIMAL(24, 6), + MODIFY COLUMN used DECIMAL(24, 6); + `); err != nil { + return err + } + + // add new field `is_banned` in `auth` table + if err := execSql(db, ` + ALTER TABLE auth + ADD COLUMN is_banned BOOLEAN DEFAULT FALSE; + `); err != nil { + return err + } + + return nil +}