feat: disciple link
This commit is contained in:
@@ -8,6 +8,7 @@ import (
|
||||
"strings"
|
||||
|
||||
"github.com/go-chi/chi/v5"
|
||||
"github.com/prabhupadasays/spsays-bff/internal/repository"
|
||||
"github.com/prabhupadasays/spsays-bff/internal/service"
|
||||
"github.com/prabhupadasays/spsays-bff/pkg/response"
|
||||
)
|
||||
@@ -331,6 +332,68 @@ func (h *AdminHandler) setUserBanned(w http.ResponseWriter, r *http.Request, ban
|
||||
// { "bookmark_limit": 10|null, "public_collection_limit": …, "private_collection_limit": … }.
|
||||
// Each field is optional: a null (or omitted) value resets that limit to the
|
||||
// plan default; a number caps that resource for this user regardless of plan.
|
||||
// ListDisciples — GET /admin/disciples?q=&limit= — options for the
|
||||
// direct-disciple picker. Read-only; an empty q returns the first page
|
||||
// alphabetically so the picker opens with content.
|
||||
func (h *AdminHandler) ListDisciples(w http.ResponseWriter, r *http.Request) {
|
||||
limit, _ := strconv.Atoi(r.URL.Query().Get("limit"))
|
||||
items, err := h.svc.SearchDisciples(r.Context(), r.URL.Query().Get("q"), limit)
|
||||
if err != nil {
|
||||
if errors.Is(err, service.ErrDisciplesUnavailable) {
|
||||
response.Error(w, http.StatusServiceUnavailable, "disciple directory unavailable")
|
||||
return
|
||||
}
|
||||
response.Error(w, http.StatusInternalServerError, "could not search disciples")
|
||||
return
|
||||
}
|
||||
response.JSON(w, http.StatusOK, items)
|
||||
}
|
||||
|
||||
// LinkDisciple — POST /admin/users/{id}/disciple {"disciple_id":"…"} — marks the
|
||||
// account as one of Śrīla Prabhupāda's direct disciples. Re-posting with a
|
||||
// different id moves the link.
|
||||
func (h *AdminHandler) LinkDisciple(w http.ResponseWriter, r *http.Request) {
|
||||
id := chi.URLParam(r, "id")
|
||||
var in struct {
|
||||
DiscipleID string `json:"disciple_id"`
|
||||
}
|
||||
if err := json.NewDecoder(r.Body).Decode(&in); err != nil {
|
||||
response.Error(w, http.StatusBadRequest, "invalid request body")
|
||||
return
|
||||
}
|
||||
if strings.TrimSpace(in.DiscipleID) == "" {
|
||||
response.Error(w, http.StatusBadRequest, "disciple_id is required")
|
||||
return
|
||||
}
|
||||
switch err := h.svc.LinkDisciple(r.Context(), id, in.DiscipleID); {
|
||||
case err == nil:
|
||||
response.JSON(w, http.StatusOK, map[string]any{"linked": true})
|
||||
case errors.Is(err, service.ErrAdminUserNotFound):
|
||||
response.Error(w, http.StatusNotFound, "user not found")
|
||||
case errors.Is(err, service.ErrDiscipleNotFound):
|
||||
response.Error(w, http.StatusNotFound, "disciple not found")
|
||||
case errors.Is(err, repository.ErrDiscipleClaimed):
|
||||
response.Error(w, http.StatusConflict, "that disciple is already linked to another user")
|
||||
case errors.Is(err, service.ErrDisciplesUnavailable):
|
||||
response.Error(w, http.StatusServiceUnavailable, "disciple directory unavailable")
|
||||
default:
|
||||
response.Error(w, http.StatusInternalServerError, "could not link disciple")
|
||||
}
|
||||
}
|
||||
|
||||
// UnlinkDisciple — DELETE /admin/users/{id}/disciple — removes the link.
|
||||
func (h *AdminHandler) UnlinkDisciple(w http.ResponseWriter, r *http.Request) {
|
||||
id := chi.URLParam(r, "id")
|
||||
switch err := h.svc.UnlinkDisciple(r.Context(), id); {
|
||||
case err == nil:
|
||||
response.JSON(w, http.StatusOK, map[string]any{"linked": false})
|
||||
case errors.Is(err, service.ErrAdminUserNotFound):
|
||||
response.Error(w, http.StatusNotFound, "user not found")
|
||||
default:
|
||||
response.Error(w, http.StatusInternalServerError, "could not unlink disciple")
|
||||
}
|
||||
}
|
||||
|
||||
func (h *AdminHandler) SetUserLimits(w http.ResponseWriter, r *http.Request) {
|
||||
id := chi.URLParam(r, "id")
|
||||
var in struct {
|
||||
|
||||
Reference in New Issue
Block a user