sojorn/go-backend/internal/handlers/follow_handler.go

236 lines
5.9 KiB
Go

package handlers
import (
"net/http"
"github.com/gin-gonic/gin"
)
type FollowHandler struct {
db interface {
Exec(query string, args ...interface{}) (interface{}, error)
Query(query string, args ...interface{}) (interface{}, error)
QueryRow(query string, args ...interface{}) interface{}
}
}
func NewFollowHandler(db interface {
Exec(query string, args ...interface{}) (interface{}, error)
Query(query string, args ...interface{}) (interface{}, error)
QueryRow(query string, args ...interface{}) interface{}
}) *FollowHandler {
return &FollowHandler{db: db}
}
// FollowUser creates a follow relationship
func (h *FollowHandler) FollowUser(c *gin.Context) {
userID := c.GetString("user_id")
if userID == "" {
c.JSON(http.StatusUnauthorized, gin.H{"error": "Unauthorized"})
return
}
targetUserID := c.Param("userId")
if targetUserID == "" {
c.JSON(http.StatusBadRequest, gin.H{"error": "Target user ID required"})
return
}
if userID == targetUserID {
c.JSON(http.StatusBadRequest, gin.H{"error": "Cannot follow yourself"})
return
}
query := `
INSERT INTO follows (follower_id, following_id)
VALUES ($1, $2)
ON CONFLICT (follower_id, following_id) DO NOTHING
RETURNING id
`
var followID string
err := h.db.QueryRow(query, userID, targetUserID)
if err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to follow user"})
return
}
c.JSON(http.StatusOK, gin.H{
"message": "Successfully followed user",
"follow_id": followID,
})
}
// UnfollowUser removes a follow relationship
func (h *FollowHandler) UnfollowUser(c *gin.Context) {
userID := c.GetString("user_id")
if userID == "" {
c.JSON(http.StatusUnauthorized, gin.H{"error": "Unauthorized"})
return
}
targetUserID := c.Param("userId")
if targetUserID == "" {
c.JSON(http.StatusBadRequest, gin.H{"error": "Target user ID required"})
return
}
query := `
DELETE FROM follows
WHERE follower_id = $1 AND following_id = $2
`
_, err := h.db.Exec(query, userID, targetUserID)
if err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to unfollow user"})
return
}
c.JSON(http.StatusOK, gin.H{"message": "Successfully unfollowed user"})
}
// IsFollowing checks if current user follows target user
func (h *FollowHandler) IsFollowing(c *gin.Context) {
userID := c.GetString("user_id")
if userID == "" {
c.JSON(http.StatusUnauthorized, gin.H{"error": "Unauthorized"})
return
}
targetUserID := c.Param("userId")
if targetUserID == "" {
c.JSON(http.StatusBadRequest, gin.H{"error": "Target user ID required"})
return
}
query := `
SELECT EXISTS(
SELECT 1 FROM follows
WHERE follower_id = $1 AND following_id = $2
)
`
var isFollowing bool
err := h.db.QueryRow(query, userID, targetUserID)
if err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to check follow status"})
return
}
c.JSON(http.StatusOK, gin.H{"is_following": isFollowing})
}
// GetMutualFollowers returns users that both current user and target user follow
func (h *FollowHandler) GetMutualFollowers(c *gin.Context) {
userID := c.GetString("user_id")
if userID == "" {
c.JSON(http.StatusUnauthorized, gin.H{"error": "Unauthorized"})
return
}
targetUserID := c.Param("userId")
if targetUserID == "" {
c.JSON(http.StatusBadRequest, gin.H{"error": "Target user ID required"})
return
}
query := `SELECT * FROM get_mutual_followers($1, $2)`
rows, err := h.db.Query(query, userID, targetUserID)
if err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to get mutual followers"})
return
}
var mutualFollowers []map[string]interface{}
// Parse rows into mutualFollowers slice
// Implementation depends on your DB driver
c.JSON(http.StatusOK, gin.H{"mutual_followers": mutualFollowers})
}
// GetSuggestedUsers returns suggested users to follow
func (h *FollowHandler) GetSuggestedUsers(c *gin.Context) {
userID := c.GetString("user_id")
if userID == "" {
c.JSON(http.StatusUnauthorized, gin.H{"error": "Unauthorized"})
return
}
limit := 10
if limitParam := c.Query("limit"); limitParam != "" {
// Parse limit from query param
}
query := `SELECT * FROM get_suggested_users($1, $2)`
rows, err := h.db.Query(query, userID, limit)
if err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to get suggestions"})
return
}
var suggestions []map[string]interface{}
// Parse rows into suggestions slice
c.JSON(http.StatusOK, gin.H{"suggestions": suggestions})
}
// GetFollowers returns list of users following the target user
func (h *FollowHandler) GetFollowers(c *gin.Context) {
targetUserID := c.Param("userId")
if targetUserID == "" {
c.JSON(http.StatusBadRequest, gin.H{"error": "User ID required"})
return
}
query := `
SELECT p.user_id, p.username, p.display_name, p.avatar_url, f.created_at
FROM follows f
JOIN profiles p ON f.follower_id = p.user_id
WHERE f.following_id = $1
ORDER BY f.created_at DESC
LIMIT 100
`
rows, err := h.db.Query(query, targetUserID)
if err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to get followers"})
return
}
var followers []map[string]interface{}
// Parse rows
c.JSON(http.StatusOK, gin.H{"followers": followers})
}
// GetFollowing returns list of users that target user follows
func (h *FollowHandler) GetFollowing(c *gin.Context) {
targetUserID := c.Param("userId")
if targetUserID == "" {
c.JSON(http.StatusBadRequest, gin.H{"error": "User ID required"})
return
}
query := `
SELECT p.user_id, p.username, p.display_name, p.avatar_url, f.created_at
FROM follows f
JOIN profiles p ON f.following_id = p.user_id
WHERE f.follower_id = $1
ORDER BY f.created_at DESC
LIMIT 100
`
rows, err := h.db.Query(query, targetUserID)
if err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to get following"})
return
}
var following []map[string]interface{}
// Parse rows
c.JSON(http.StatusOK, gin.H{"following": following})
}