From e2ff065218e945b4094be9d90eda583e7c021e85 Mon Sep 17 00:00:00 2001 From: Zhang Minghan Date: Sun, 11 Feb 2024 13:12:30 +0800 Subject: [PATCH] feat: support ban user and set admin permission action --- admin/controller.go | 62 +++++++++++++++++++++ admin/router.go | 2 + admin/user.go | 16 ++++++ app/src/admin/api/chart.ts | 30 +++++++++++ app/src/components/PopupDialog.tsx | 5 +- app/src/components/admin/UserTable.tsx | 74 ++++++++++++++++++++++++++ app/src/resources/i18n/cn.json | 8 +++ app/src/resources/i18n/en.json | 10 +++- app/src/resources/i18n/ja.json | 10 +++- app/src/resources/i18n/ru.json | 10 +++- 10 files changed, 223 insertions(+), 4 deletions(-) diff --git a/admin/controller.go b/admin/controller.go index 94c6661..5f9e8c7 100644 --- a/admin/controller.go +++ b/admin/controller.go @@ -29,6 +29,16 @@ type EmailMigrationForm struct { Email string `json:"email"` } +type SetAdminForm struct { + Id int64 `json:"id"` + Admin bool `json:"admin"` +} + +type BanForm struct { + Id int64 `json:"id"` + Ban bool `json:"ban"` +} + type QuotaOperationForm struct { Id int64 `json:"id" binding:"required"` Quota float32 `json:"quota" binding:"required"` @@ -220,6 +230,58 @@ func UpdateEmailAPI(c *gin.Context) { }) } +func SetAdminAPI(c *gin.Context) { + db := utils.GetDBFromContext(c) + + var form SetAdminForm + if err := c.ShouldBindJSON(&form); err != nil { + c.JSON(http.StatusOK, gin.H{ + "status": false, + "message": err.Error(), + }) + return + } + + err := setAdmin(db, form.Id, form.Admin) + if err != nil { + c.JSON(http.StatusOK, gin.H{ + "status": false, + "message": err.Error(), + }) + return + } + + c.JSON(http.StatusOK, gin.H{ + "status": true, + }) +} + +func BanAPI(c *gin.Context) { + db := utils.GetDBFromContext(c) + + var form BanForm + if err := c.ShouldBindJSON(&form); err != nil { + c.JSON(http.StatusOK, gin.H{ + "status": false, + "message": err.Error(), + }) + return + } + + err := banUser(db, form.Id, form.Ban) + if err != nil { + c.JSON(http.StatusOK, gin.H{ + "status": false, + "message": err.Error(), + }) + return + } + + c.JSON(http.StatusOK, gin.H{ + "status": true, + }) +} + func UserQuotaAPI(c *gin.Context) { db := utils.GetDBFromContext(c) diff --git a/admin/router.go b/admin/router.go index 6c97964..010d91c 100644 --- a/admin/router.go +++ b/admin/router.go @@ -28,6 +28,8 @@ func Register(app *gin.RouterGroup) { app.POST("/admin/user/release", ReleaseUsageAPI) app.POST("/admin/user/password", UpdatePasswordAPI) app.POST("/admin/user/email", UpdateEmailAPI) + app.POST("/admin/user/ban", BanAPI) + app.POST("/admin/user/admin", SetAdminAPI) app.POST("/admin/user/root", UpdateRootPasswordAPI) app.POST("/admin/market/update", UpdateMarketAPI) diff --git a/admin/user.go b/admin/user.go index 01880a7..9462015 100644 --- a/admin/user.go +++ b/admin/user.go @@ -133,6 +133,22 @@ func emailMigration(db *sql.DB, id int64, email string) error { return err } +func setAdmin(db *sql.DB, id int64, isAdmin bool) error { + _, err := db.Exec(` + UPDATE auth SET is_admin = ? WHERE id = ? + `, isAdmin, id) + + return err +} + +func banUser(db *sql.DB, id int64, isBanned bool) error { + _, err := db.Exec(` + UPDATE auth SET is_banned = ? WHERE id = ? + `, isBanned, id) + + return err +} + func quotaMigration(db *sql.DB, id int64, quota float32, override bool) error { // if quota is negative, then decrease quota // if quota is positive, then increase quota diff --git a/app/src/admin/api/chart.ts b/app/src/admin/api/chart.ts index 4e820aa..561f1e5 100644 --- a/app/src/admin/api/chart.ts +++ b/app/src/admin/api/chart.ts @@ -225,6 +225,36 @@ export async function subscriptionOperation( } } +export async function banUserOperation( + id: number, + ban: boolean, +): Promise { + try { + const response = await axios.post("/admin/user/ban", { + id, + ban, + }); + return response.data as CommonResponse; + } catch (e) { + return { status: false, message: getErrorMessage(e) }; + } +} + +export async function setAdminOperation( + id: number, + admin: boolean, +): Promise { + try { + const response = await axios.post("/admin/user/admin", { + id, + admin, + }); + return response.data as CommonResponse; + } catch (e) { + return { status: false, message: getErrorMessage(e) }; + } +} + export async function subscriptionLevelOperation( id: number, level: number, diff --git a/app/src/components/PopupDialog.tsx b/app/src/components/PopupDialog.tsx index d2261d6..0b6e471 100644 --- a/app/src/components/PopupDialog.tsx +++ b/app/src/components/PopupDialog.tsx @@ -23,12 +23,13 @@ export enum popupTypes { export type PopupDialogProps = { title: string; description?: string; - name: string; + name?: string; placeholder?: string; defaultValue?: string; onValueChange?: (value: string) => string; onSubmit?: (value: string) => Promise; destructive?: boolean; + disabled?: boolean; type?: popupTypes; @@ -112,6 +113,7 @@ function PopupDialog(props: PopupDialogProps) { cancelLabel, confirmLabel, destructive, + disabled, } = props; const { t } = useTranslation(); @@ -137,6 +139,7 @@ function PopupDialog(props: PopupDialogProps) { {cancelLabel || t("cancel")}