core/internal/port/handler_http_api_village.go

245 lines
6.5 KiB
Go

package port
import (
"context"
"net/http"
"slices"
"strconv"
"gitea.dwysokinski.me/twhelp/core/internal/domain"
"gitea.dwysokinski.me/twhelp/core/internal/port/internal/apimodel"
"github.com/go-chi/chi/v5"
)
func (h *apiHTTPHandler) ListVillages(
w http.ResponseWriter,
r *http.Request,
_ apimodel.VersionCodePathParam,
serverKey apimodel.ServerKeyPathParam,
params apimodel.ListVillagesParams,
) {
domainParams := domain.NewListVillagesParams()
if err := domainParams.SetSort([]domain.VillageSort{domain.VillageSortIDASC}); err != nil {
h.errorRenderer.withErrorPathFormatter(formatListVillagesErrorPath).render(w, r, err)
return
}
if err := domainParams.SetServerKeys([]string{serverKey}); err != nil {
h.errorRenderer.withErrorPathFormatter(formatListVillagesErrorPath).render(w, r, err)
return
}
if params.Coords != nil {
if err := domainParams.SetCoordsString(*params.Coords); err != nil {
h.errorRenderer.withErrorPathFormatter(formatListVillagesErrorPath).render(w, r, err)
return
}
}
if params.Limit != nil {
if err := domainParams.SetLimit(*params.Limit); err != nil {
h.errorRenderer.withErrorPathFormatter(formatListVillagesErrorPath).render(w, r, err)
return
}
}
if params.Cursor != nil {
if err := domainParams.SetEncodedCursor(*params.Cursor); err != nil {
h.errorRenderer.withErrorPathFormatter(formatListVillagesErrorPath).render(w, r, err)
return
}
}
res, err := h.villageSvc.ListWithRelations(r.Context(), domainParams)
if err != nil {
h.errorRenderer.render(w, r, err)
return
}
renderJSON(w, r, http.StatusOK, apimodel.NewListVillagesResponse(res))
}
func (h *apiHTTPHandler) ListPlayerVillages(
w http.ResponseWriter,
r *http.Request,
_ apimodel.VersionCodePathParam,
serverKey apimodel.ServerKeyPathParam,
playerID apimodel.PlayerIdPathParam,
params apimodel.ListPlayerVillagesParams,
) {
domainParams := domain.NewListVillagesParams()
if err := domainParams.SetSort([]domain.VillageSort{domain.VillageSortIDASC}); err != nil {
h.errorRenderer.withErrorPathFormatter(formatListVillagesErrorPath).render(w, r, err)
return
}
if err := domainParams.SetServerKeys([]string{serverKey}); err != nil {
h.errorRenderer.withErrorPathFormatter(formatListVillagesErrorPath).render(w, r, err)
return
}
if err := domainParams.SetPlayerIDs([]int{playerID}); err != nil {
h.errorRenderer.withErrorPathFormatter(formatListVillagesErrorPath).render(w, r, err)
return
}
if params.Limit != nil {
if err := domainParams.SetLimit(*params.Limit); err != nil {
h.errorRenderer.withErrorPathFormatter(formatListVillagesErrorPath).render(w, r, err)
return
}
}
if params.Cursor != nil {
if err := domainParams.SetEncodedCursor(*params.Cursor); err != nil {
h.errorRenderer.withErrorPathFormatter(formatListVillagesErrorPath).render(w, r, err)
return
}
}
res, err := h.villageSvc.ListWithRelations(r.Context(), domainParams)
if err != nil {
h.errorRenderer.render(w, r, err)
return
}
renderJSON(w, r, http.StatusOK, apimodel.NewListVillagesResponse(res))
}
func (h *apiHTTPHandler) ListTribeVillages(
w http.ResponseWriter,
r *http.Request,
_ apimodel.VersionCodePathParam,
serverKey apimodel.ServerKeyPathParam,
tribeID apimodel.TribeIdPathParam,
params apimodel.ListTribeVillagesParams,
) {
domainParams := domain.NewListVillagesParams()
if err := domainParams.SetSort([]domain.VillageSort{domain.VillageSortIDASC}); err != nil {
h.errorRenderer.withErrorPathFormatter(formatListVillagesErrorPath).render(w, r, err)
return
}
if err := domainParams.SetServerKeys([]string{serverKey}); err != nil {
h.errorRenderer.withErrorPathFormatter(formatListVillagesErrorPath).render(w, r, err)
return
}
if err := domainParams.SetTribeIDs([]int{tribeID}); err != nil {
h.errorRenderer.withErrorPathFormatter(formatListVillagesErrorPath).render(w, r, err)
return
}
if params.Limit != nil {
if err := domainParams.SetLimit(*params.Limit); err != nil {
h.errorRenderer.withErrorPathFormatter(formatListVillagesErrorPath).render(w, r, err)
return
}
}
if params.Cursor != nil {
if err := domainParams.SetEncodedCursor(*params.Cursor); err != nil {
h.errorRenderer.withErrorPathFormatter(formatListVillagesErrorPath).render(w, r, err)
return
}
}
res, err := h.villageSvc.ListWithRelations(r.Context(), domainParams)
if err != nil {
h.errorRenderer.render(w, r, err)
return
}
renderJSON(w, r, http.StatusOK, apimodel.NewListVillagesResponse(res))
}
func (h *apiHTTPHandler) GetVillage(
w http.ResponseWriter,
r *http.Request,
_ apimodel.VersionCodePathParam,
_ apimodel.ServerKeyPathParam,
_ apimodel.VillageIdPathParam,
) {
village, _ := villageFromContext(r.Context())
renderJSON(w, r, http.StatusOK, apimodel.NewGetVillageResponse(village))
}
func (h *apiHTTPHandler) villageMiddleware(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
ctx := r.Context()
routeCtx := chi.RouteContext(ctx)
server, serverOK := serverFromContext(ctx)
villageIDIdx := slices.Index(routeCtx.URLParams.Keys, "villageId")
if !serverOK || villageIDIdx < 0 {
next.ServeHTTP(w, r)
return
}
villageID, err := strconv.Atoi(routeCtx.URLParams.Values[villageIDIdx])
if err != nil {
return
}
village, err := h.villageSvc.GetWithRelations(
ctx,
villageID,
server.Key(),
)
if err != nil {
h.errorRenderer.withErrorPathFormatter(formatGetVillageErrorPath).render(w, r, err)
return
}
next.ServeHTTP(w, r.WithContext(villageToContext(ctx, village)))
})
}
type villageCtxKey struct{}
func villageToContext(ctx context.Context, v domain.VillageWithRelations) context.Context {
return context.WithValue(ctx, villageCtxKey{}, v)
}
func villageFromContext(ctx context.Context) (domain.VillageWithRelations, bool) {
v, ok := ctx.Value(villageCtxKey{}).(domain.VillageWithRelations)
return v, ok
}
func formatListVillagesErrorPath(segments []domain.ErrorPathSegment) []string {
if segments[0].Model != "ListVillagesParams" {
return nil
}
switch segments[0].Field {
case "cursor":
return []string{"$query", "cursor"}
case "limit":
return []string{"$query", "limit"}
case "coords":
path := []string{"$query", "coords"}
if segments[0].Index >= 0 {
path = append(path, strconv.Itoa(segments[0].Index))
}
return path
default:
return nil
}
}
func formatGetVillageErrorPath(segments []domain.ErrorPathSegment) []string {
if segments[0].Model != "ListVillagesParams" {
return nil
}
switch segments[0].Field {
case "ids":
return []string{"$path", "villageId"}
default:
return nil
}
}