feat: add user search
This commit is contained in:
@@ -4,6 +4,7 @@ import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"net/http"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/prabhupadasays/spsays-bff/internal/middleware"
|
||||
@@ -53,6 +54,57 @@ func (h *UserHandler) UpdateProfile(w http.ResponseWriter, r *http.Request) {
|
||||
response.JSON(w, http.StatusOK, u)
|
||||
}
|
||||
|
||||
// userSearchItem is the public-safe slice of model.User returned by the
|
||||
// search endpoint. Sensitive fields (email, password hash, role, plan,
|
||||
// token_version, timestamps) are intentionally omitted.
|
||||
type userSearchItem struct {
|
||||
Handle string `json:"handle"`
|
||||
Name string `json:"name"`
|
||||
AvatarURL *string `json:"avatar_url,omitempty"`
|
||||
}
|
||||
|
||||
// Search handles GET /api/v1/users/search?q=...&limit=...
|
||||
//
|
||||
// Public endpoint — anonymous and signed-in viewers alike can search
|
||||
// for users by handle or display name. Returns a sanitized payload
|
||||
// without auth-sensitive fields. Used by the global /search page when
|
||||
// the query carries an "@" prefix.
|
||||
func (h *UserHandler) Search(w http.ResponseWriter, r *http.Request) {
|
||||
q := strings.TrimSpace(r.URL.Query().Get("q"))
|
||||
if q == "" {
|
||||
response.JSON(w, http.StatusOK, map[string]any{
|
||||
"query": "",
|
||||
"results": []userSearchItem{},
|
||||
})
|
||||
return
|
||||
}
|
||||
limit := 20
|
||||
if v := r.URL.Query().Get("limit"); v != "" {
|
||||
if n, err := strconv.Atoi(v); err == nil && n > 0 && n <= 50 {
|
||||
limit = n
|
||||
}
|
||||
}
|
||||
|
||||
users, err := h.svc.Search(r.Context(), q, limit)
|
||||
if err != nil {
|
||||
response.Error(w, http.StatusInternalServerError, "search failed")
|
||||
return
|
||||
}
|
||||
|
||||
items := make([]userSearchItem, 0, len(users))
|
||||
for _, u := range users {
|
||||
items = append(items, userSearchItem{
|
||||
Handle: u.Handle,
|
||||
Name: u.Name,
|
||||
AvatarURL: u.AvatarURL,
|
||||
})
|
||||
}
|
||||
response.JSON(w, http.StatusOK, map[string]any{
|
||||
"query": q,
|
||||
"results": items,
|
||||
})
|
||||
}
|
||||
|
||||
// GetReadingPrefs returns the caller's saved reading prefs blob (always
|
||||
// well-formed JSON; an empty object when the user has never written).
|
||||
// The frontend treats the response as the source of truth on first
|
||||
|
||||
Reference in New Issue
Block a user