diff --git a/admin/src/app/users/[id]/page.tsx b/admin/src/app/users/[id]/page.tsx index 4f1d00d..264241d 100644 --- a/admin/src/app/users/[id]/page.tsx +++ b/admin/src/app/users/[id]/page.tsx @@ -512,7 +512,7 @@ function FollowManager({ userId }: { userId: string }) { {/* Add */}
- setAddHandle(e.target.value)} onKeyDown={(e) => e.key === 'Enter' && handleAdd()} className="flex-1 px-2 py-1.5 border border-warm-300 rounded text-sm" /> diff --git a/go-backend/internal/handlers/admin_handler.go b/go-backend/internal/handlers/admin_handler.go index ca53fc6..ff7198f 100644 --- a/go-backend/internal/handlers/admin_handler.go +++ b/go-backend/internal/handlers/admin_handler.go @@ -689,6 +689,22 @@ func (h *AdminHandler) AdminUpdateProfile(c *gin.Context) { c.JSON(http.StatusOK, gin.H{"message": "Profile updated"}) } +// resolveUserID accepts either a UUID or a handle and returns the user's UUID. +func (h *AdminHandler) resolveUserID(ctx context.Context, input string) (string, error) { + // If it parses as a UUID, return as-is + if _, err := uuid.Parse(input); err == nil { + return input, nil + } + // Otherwise, treat as a handle and look it up + handle := strings.TrimPrefix(input, "@") + var id uuid.UUID + err := h.pool.QueryRow(ctx, `SELECT id FROM profiles WHERE handle = $1`, handle).Scan(&id) + if err != nil { + return "", fmt.Errorf("user not found: %s", input) + } + return id.String(), nil +} + // AdminManageFollow adds or removes follow relationships for official accounts. func (h *AdminHandler) AdminManageFollow(c *gin.Context) { ctx := c.Request.Context() @@ -696,7 +712,7 @@ func (h *AdminHandler) AdminManageFollow(c *gin.Context) { var req struct { Action string `json:"action"` // "add" or "remove" - UserID string `json:"user_id"` // the other user in the relationship + UserID string `json:"user_id"` // UUID or handle of the other user Relation string `json:"relation"` // "follower" (user follows target) or "following" (target follows user) } if err := c.ShouldBindJSON(&req); err != nil { @@ -713,16 +729,21 @@ func (h *AdminHandler) AdminManageFollow(c *gin.Context) { return } + // Resolve handle or UUID to a UUID + resolvedID, err := h.resolveUserID(ctx, req.UserID) + if err != nil { + c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()}) + return + } + // Determine follower_id and following_id var followerID, followingID string if req.Relation == "follower" { - // "user follows target" — user is follower, target is following - followerID = req.UserID + followerID = resolvedID followingID = targetUserID } else { - // "target follows user" — target is follower, user is following followerID = targetUserID - followingID = req.UserID + followingID = resolvedID } if req.Action == "add" {