Content jailing: hide all posts/comments on ban/suspend, restore on activate
This commit is contained in:
parent
d32da021fb
commit
d1b01aa5b2
|
|
@ -470,6 +470,9 @@ func (h *AdminHandler) UpdateUserStatus(c *gin.Context) {
|
||||||
}
|
}
|
||||||
// Revoke ALL refresh tokens immediately
|
// Revoke ALL refresh tokens immediately
|
||||||
h.pool.Exec(ctx, `UPDATE refresh_tokens SET revoked = true WHERE user_id = $1::uuid`, targetUserID)
|
h.pool.Exec(ctx, `UPDATE refresh_tokens SET revoked = true WHERE user_id = $1::uuid`, targetUserID)
|
||||||
|
// Jail all their content (hidden from feeds until restored)
|
||||||
|
h.pool.Exec(ctx, `UPDATE posts SET status = 'jailed' WHERE author_id = $1::uuid AND status = 'active' AND deleted_at IS NULL`, targetUserID)
|
||||||
|
h.pool.Exec(ctx, `UPDATE comments SET status = 'jailed' WHERE author_id = $1::uuid AND status = 'active' AND deleted_at IS NULL`, targetUserID)
|
||||||
} else if req.Status == "suspended" {
|
} else if req.Status == "suspended" {
|
||||||
suspendUntil := time.Now().Add(7 * 24 * time.Hour) // Default 7 day suspension from admin
|
suspendUntil := time.Now().Add(7 * 24 * time.Hour) // Default 7 day suspension from admin
|
||||||
_, err := h.pool.Exec(ctx, `UPDATE users SET status = 'suspended', suspended_until = $2 WHERE id = $1::uuid`, targetUserID, suspendUntil)
|
_, err := h.pool.Exec(ctx, `UPDATE users SET status = 'suspended', suspended_until = $2 WHERE id = $1::uuid`, targetUserID, suspendUntil)
|
||||||
|
|
@ -477,12 +480,20 @@ func (h *AdminHandler) UpdateUserStatus(c *gin.Context) {
|
||||||
c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to update user status"})
|
c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to update user status"})
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
// Jail all their content during suspension
|
||||||
|
h.pool.Exec(ctx, `UPDATE posts SET status = 'jailed' WHERE author_id = $1::uuid AND status = 'active' AND deleted_at IS NULL`, targetUserID)
|
||||||
|
h.pool.Exec(ctx, `UPDATE comments SET status = 'jailed' WHERE author_id = $1::uuid AND status = 'active' AND deleted_at IS NULL`, targetUserID)
|
||||||
} else {
|
} else {
|
||||||
_, err := h.pool.Exec(ctx, `UPDATE users SET status = $1, suspended_until = NULL WHERE id = $2::uuid`, req.Status, targetUserID)
|
_, err := h.pool.Exec(ctx, `UPDATE users SET status = $1, suspended_until = NULL WHERE id = $2::uuid`, req.Status, targetUserID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to update user status"})
|
c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to update user status"})
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
// If reactivating, restore any jailed content
|
||||||
|
if req.Status == "active" {
|
||||||
|
h.pool.Exec(ctx, `UPDATE posts SET status = 'active' WHERE author_id = $1::uuid AND status = 'jailed'`, targetUserID)
|
||||||
|
h.pool.Exec(ctx, `UPDATE comments SET status = 'active' WHERE author_id = $1::uuid AND status = 'jailed'`, targetUserID)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Log status change
|
// Log status change
|
||||||
|
|
|
||||||
|
|
@ -86,9 +86,13 @@ func AuthMiddleware(jwtSecret string, pool ...*pgxpool.Pool) gin.HandlerFunc {
|
||||||
}
|
}
|
||||||
if status == "suspended" {
|
if status == "suspended" {
|
||||||
if suspendedUntil != nil && time.Now().After(*suspendedUntil) {
|
if suspendedUntil != nil && time.Now().After(*suspendedUntil) {
|
||||||
// Suspension expired — reactivate
|
// Suspension expired — reactivate and restore jailed content
|
||||||
dbPool.Exec(context.Background(),
|
dbPool.Exec(context.Background(),
|
||||||
`UPDATE users SET status = 'active', suspended_until = NULL WHERE id = $1::uuid`, userID)
|
`UPDATE users SET status = 'active', suspended_until = NULL WHERE id = $1::uuid`, userID)
|
||||||
|
dbPool.Exec(context.Background(),
|
||||||
|
`UPDATE posts SET status = 'active' WHERE author_id = $1::uuid AND status = 'jailed'`, userID)
|
||||||
|
dbPool.Exec(context.Background(),
|
||||||
|
`UPDATE comments SET status = 'active' WHERE author_id = $1::uuid AND status = 'jailed'`, userID)
|
||||||
} else {
|
} else {
|
||||||
c.JSON(http.StatusForbidden, gin.H{"error": "Your account is temporarily suspended.", "code": "suspended"})
|
c.JSON(http.StatusForbidden, gin.H{"error": "Your account is temporarily suspended.", "code": "suspended"})
|
||||||
c.Abort()
|
c.Abort()
|
||||||
|
|
|
||||||
|
|
@ -165,6 +165,9 @@ func (cf *ContentFilter) RecordStrikeWithIP(ctx context.Context, userID uuid.UUI
|
||||||
cf.pool.Exec(ctx, `UPDATE users SET status = 'banned' WHERE id = $1`, userID)
|
cf.pool.Exec(ctx, `UPDATE users SET status = 'banned' WHERE id = $1`, userID)
|
||||||
// Revoke ALL refresh tokens immediately so the user is logged out
|
// Revoke ALL refresh tokens immediately so the user is logged out
|
||||||
cf.pool.Exec(ctx, `UPDATE refresh_tokens SET revoked = true WHERE user_id = $1`, userID)
|
cf.pool.Exec(ctx, `UPDATE refresh_tokens SET revoked = true WHERE user_id = $1`, userID)
|
||||||
|
// Jail all their content
|
||||||
|
cf.pool.Exec(ctx, `UPDATE posts SET status = 'jailed' WHERE author_id = $1 AND status = 'active' AND deleted_at IS NULL`, userID)
|
||||||
|
cf.pool.Exec(ctx, `UPDATE comments SET status = 'jailed' WHERE author_id = $1 AND status = 'active' AND deleted_at IS NULL`, userID)
|
||||||
// Log IP for ban evasion prevention
|
// Log IP for ban evasion prevention
|
||||||
if clientIP != "" {
|
if clientIP != "" {
|
||||||
cf.pool.Exec(ctx, `
|
cf.pool.Exec(ctx, `
|
||||||
|
|
@ -177,11 +180,15 @@ func (cf *ContentFilter) RecordStrikeWithIP(ctx context.Context, userID uuid.UUI
|
||||||
consequence = "suspend_7d"
|
consequence = "suspend_7d"
|
||||||
suspendUntil := time.Now().Add(7 * 24 * time.Hour)
|
suspendUntil := time.Now().Add(7 * 24 * time.Hour)
|
||||||
cf.pool.Exec(ctx, `UPDATE users SET status = 'suspended', suspended_until = $2 WHERE id = $1`, userID, suspendUntil)
|
cf.pool.Exec(ctx, `UPDATE users SET status = 'suspended', suspended_until = $2 WHERE id = $1`, userID, suspendUntil)
|
||||||
|
cf.pool.Exec(ctx, `UPDATE posts SET status = 'jailed' WHERE author_id = $1 AND status = 'active' AND deleted_at IS NULL`, userID)
|
||||||
|
cf.pool.Exec(ctx, `UPDATE comments SET status = 'jailed' WHERE author_id = $1 AND status = 'active' AND deleted_at IS NULL`, userID)
|
||||||
fmt.Printf("Content filter: user %s suspended 7 days (%d strikes)\n", userID, count)
|
fmt.Printf("Content filter: user %s suspended 7 days (%d strikes)\n", userID, count)
|
||||||
case count >= 3:
|
case count >= 3:
|
||||||
consequence = "suspend_24h"
|
consequence = "suspend_24h"
|
||||||
suspendUntil := time.Now().Add(24 * time.Hour)
|
suspendUntil := time.Now().Add(24 * time.Hour)
|
||||||
cf.pool.Exec(ctx, `UPDATE users SET status = 'suspended', suspended_until = $2 WHERE id = $1`, userID, suspendUntil)
|
cf.pool.Exec(ctx, `UPDATE users SET status = 'suspended', suspended_until = $2 WHERE id = $1`, userID, suspendUntil)
|
||||||
|
cf.pool.Exec(ctx, `UPDATE posts SET status = 'jailed' WHERE author_id = $1 AND status = 'active' AND deleted_at IS NULL`, userID)
|
||||||
|
cf.pool.Exec(ctx, `UPDATE comments SET status = 'jailed' WHERE author_id = $1 AND status = 'active' AND deleted_at IS NULL`, userID)
|
||||||
fmt.Printf("Content filter: user %s suspended 24h (%d strikes)\n", userID, count)
|
fmt.Printf("Content filter: user %s suspended 24h (%d strikes)\n", userID, count)
|
||||||
default:
|
default:
|
||||||
fmt.Printf("Content filter: user %s warning (%d strikes)\n", userID, count)
|
fmt.Printf("Content filter: user %s warning (%d strikes)\n", userID, count)
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue