feat:增加超管机制,超管可以查看所有人的帖子

This commit is contained in:
amos
2025-12-18 17:14:48 +08:00
parent 2f8c1c4931
commit fd43681979
7 changed files with 61 additions and 21 deletions

View File

@@ -38,6 +38,7 @@ func migrate(db *sql.DB) error {
avatar_url TEXT DEFAULT '',
bio TEXT DEFAULT '',
is_admin INTEGER DEFAULT 0,
is_superadmin INTEGER DEFAULT 0,
created_at DATETIME DEFAULT CURRENT_TIMESTAMP
);
@@ -120,5 +121,11 @@ func migrate(db *sql.DB) error {
// SQLite 不支持 IF NOT EXISTS 用于 ALTER TABLE所以忽略错误
db.Exec("ALTER TABLE posts ADD COLUMN updated_at DATETIME DEFAULT NULL")
// 迁移:添加 is_superadmin 字段
db.Exec("ALTER TABLE users ADD COLUMN is_superadmin INTEGER DEFAULT 0")
// 设置 amos 为超管
db.Exec("UPDATE users SET is_superadmin = 1 WHERE username = 'amos'")
return nil
}

View File

@@ -75,8 +75,8 @@ func (h *AuthHandler) Register(c *gin.Context) {
userID, _ := result.LastInsertId()
// 生成 token
token, err := h.generateToken(userID, isAdmin)
// 生成 token(新注册用户不是超管)
token, err := h.generateToken(userID, isAdmin, false)
if err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": "failed to generate token"})
return
@@ -102,9 +102,9 @@ func (h *AuthHandler) Login(c *gin.Context) {
var user model.User
err := h.db.QueryRow(
"SELECT id, username, password_hash, nickname, avatar_url, bio, is_admin, created_at FROM users WHERE username = ?",
"SELECT id, username, password_hash, nickname, avatar_url, bio, is_admin, COALESCE(is_superadmin, 0), created_at FROM users WHERE username = ?",
req.Username,
).Scan(&user.ID, &user.Username, &user.PasswordHash, &user.Nickname, &user.AvatarURL, &user.Bio, &user.IsAdmin, &user.CreatedAt)
).Scan(&user.ID, &user.Username, &user.PasswordHash, &user.Nickname, &user.AvatarURL, &user.Bio, &user.IsAdmin, &user.IsSuperAdmin, &user.CreatedAt)
if err == sql.ErrNoRows {
c.JSON(http.StatusUnauthorized, gin.H{"error": "invalid credentials"})
@@ -120,7 +120,7 @@ func (h *AuthHandler) Login(c *gin.Context) {
return
}
token, err := h.generateToken(user.ID, user.IsAdmin)
token, err := h.generateToken(user.ID, user.IsAdmin, user.IsSuperAdmin)
if err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": "failed to generate token"})
return
@@ -132,10 +132,11 @@ func (h *AuthHandler) Login(c *gin.Context) {
})
}
func (h *AuthHandler) generateToken(userID int64, isAdmin bool) (string, error) {
func (h *AuthHandler) generateToken(userID int64, isAdmin bool, isSuperAdmin bool) (string, error) {
claims := &middleware.Claims{
UserID: userID,
IsAdmin: isAdmin,
UserID: userID,
IsAdmin: isAdmin,
IsSuperAdmin: isSuperAdmin,
RegisteredClaims: jwt.RegisteredClaims{
ExpiresAt: jwt.NewNumericDate(time.Now().Add(7 * 24 * time.Hour)),
IssuedAt: jwt.NewNumericDate(time.Now()),

View File

@@ -67,21 +67,44 @@ func (h *PostHandler) Create(c *gin.Context) {
func (h *PostHandler) List(c *gin.Context) {
userID := middleware.GetUserID(c)
isSuperAdmin, _ := c.Get("is_superadmin")
page, _ := strconv.Atoi(c.DefaultQuery("page", "1"))
pageSize, _ := strconv.Atoi(c.DefaultQuery("page_size", "20"))
offset := (page - 1) * pageSize
rows, err := h.db.Query(`
SELECT p.id, p.user_id, p.content, p.created_at, p.updated_at,
u.id, u.username, u.nickname, u.avatar_url,
(SELECT COUNT(*) FROM likes WHERE post_id = p.id) as like_count,
(SELECT COUNT(*) FROM likes WHERE post_id = p.id AND user_id = ?) as liked,
(SELECT COUNT(*) FROM comments WHERE post_id = p.id) as comment_count
FROM posts p
JOIN users u ON p.user_id = u.id
ORDER BY p.created_at DESC
LIMIT ? OFFSET ?
`, userID, pageSize, offset)
// 超管可以看到所有帖子,普通用户看不到超管的帖子
var rows *sql.Rows
var err error
if isSuperAdmin != nil && isSuperAdmin.(bool) {
// 超管:看到所有帖子
rows, err = h.db.Query(`
SELECT p.id, p.user_id, p.content, p.created_at, p.updated_at,
u.id, u.username, u.nickname, u.avatar_url,
(SELECT COUNT(*) FROM likes WHERE post_id = p.id) as like_count,
(SELECT COUNT(*) FROM likes WHERE post_id = p.id AND user_id = ?) as liked,
(SELECT COUNT(*) FROM comments WHERE post_id = p.id) as comment_count
FROM posts p
JOIN users u ON p.user_id = u.id
ORDER BY p.created_at DESC
LIMIT ? OFFSET ?
`, userID, pageSize, offset)
} else {
// 普通用户:只能看到非超管的帖子
rows, err = h.db.Query(`
SELECT p.id, p.user_id, p.content, p.created_at, p.updated_at,
u.id, u.username, u.nickname, u.avatar_url,
(SELECT COUNT(*) FROM likes WHERE post_id = p.id) as like_count,
(SELECT COUNT(*) FROM likes WHERE post_id = p.id AND user_id = ?) as liked,
(SELECT COUNT(*) FROM comments WHERE post_id = p.id) as comment_count
FROM posts p
JOIN users u ON p.user_id = u.id
WHERE COALESCE(u.is_superadmin, 0) = 0
ORDER BY p.created_at DESC
LIMIT ? OFFSET ?
`, userID, pageSize, offset)
}
if err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": "database error"})
return

View File

@@ -22,6 +22,7 @@ func NewSearchHandler(db *sql.DB, cfg *config.Config) *SearchHandler {
func (h *SearchHandler) Search(c *gin.Context) {
userID := middleware.GetUserID(c)
isSuperAdmin, _ := c.Get("is_superadmin")
var req model.SearchRequest
if err := c.ShouldBindQuery(&req); err != nil {
@@ -50,6 +51,11 @@ func (h *SearchHandler) Search(c *gin.Context) {
`
args := []interface{}{userID}
// 普通用户看不到超管的帖子
if isSuperAdmin == nil || !isSuperAdmin.(bool) {
query += " AND COALESCE(u.is_superadmin, 0) = 0"
}
if req.Query != "" {
query += " AND p.content LIKE ?"
args = append(args, "%"+req.Query+"%")

View File

@@ -9,8 +9,9 @@ import (
)
type Claims struct {
UserID int64 `json:"user_id"`
IsAdmin bool `json:"is_admin"`
UserID int64 `json:"user_id"`
IsAdmin bool `json:"is_admin"`
IsSuperAdmin bool `json:"is_superadmin"`
jwt.RegisteredClaims
}
@@ -49,6 +50,7 @@ func AuthMiddleware(jwtSecret string) gin.HandlerFunc {
c.Set("user_id", claims.UserID)
c.Set("is_admin", claims.IsAdmin)
c.Set("is_superadmin", claims.IsSuperAdmin)
c.Next()
}
}

View File

@@ -10,6 +10,7 @@ type User struct {
AvatarURL string `json:"avatar_url"`
Bio string `json:"bio"`
IsAdmin bool `json:"is_admin"`
IsSuperAdmin bool `json:"is_superadmin"`
CreatedAt time.Time `json:"created_at"`
}

Binary file not shown.