You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
94 lines
2.7 KiB
Go
94 lines
2.7 KiB
Go
package handler
|
|
|
|
import (
|
|
"log/slog"
|
|
"net/http"
|
|
|
|
"github.com/denisovdennis/autohero/internal/model"
|
|
"github.com/denisovdennis/autohero/internal/storage"
|
|
)
|
|
|
|
// AchievementHandler serves achievement API endpoints.
|
|
type AchievementHandler struct {
|
|
achievementStore *storage.AchievementStore
|
|
heroStore *storage.HeroStore
|
|
logger *slog.Logger
|
|
}
|
|
|
|
// NewAchievementHandler creates a new AchievementHandler.
|
|
func NewAchievementHandler(achievementStore *storage.AchievementStore, heroStore *storage.HeroStore, logger *slog.Logger) *AchievementHandler {
|
|
return &AchievementHandler{
|
|
achievementStore: achievementStore,
|
|
heroStore: heroStore,
|
|
logger: logger,
|
|
}
|
|
}
|
|
|
|
// GetHeroAchievements returns all achievements with unlocked status for the hero.
|
|
// GET /api/v1/hero/achievements
|
|
func (h *AchievementHandler) GetHeroAchievements(w http.ResponseWriter, r *http.Request) {
|
|
telegramID, ok := resolveTelegramID(r)
|
|
if !ok {
|
|
writeJSON(w, http.StatusBadRequest, map[string]string{
|
|
"error": "missing telegramId",
|
|
})
|
|
return
|
|
}
|
|
|
|
hero, err := h.heroStore.GetByTelegramID(r.Context(), telegramID)
|
|
if err != nil {
|
|
h.logger.Error("failed to get hero for achievements", "error", err)
|
|
writeJSON(w, http.StatusInternalServerError, map[string]string{
|
|
"error": "failed to load hero",
|
|
})
|
|
return
|
|
}
|
|
if hero == nil {
|
|
writeJSON(w, http.StatusNotFound, map[string]string{
|
|
"error": "hero not found",
|
|
})
|
|
return
|
|
}
|
|
|
|
// Load all achievement definitions.
|
|
allAchievements, err := h.achievementStore.ListAchievements(r.Context())
|
|
if err != nil {
|
|
h.logger.Error("failed to list achievements", "error", err)
|
|
writeJSON(w, http.StatusInternalServerError, map[string]string{
|
|
"error": "failed to load achievements",
|
|
})
|
|
return
|
|
}
|
|
|
|
// Load hero's unlocked achievements.
|
|
heroAchievements, err := h.achievementStore.GetHeroAchievements(r.Context(), hero.ID)
|
|
if err != nil {
|
|
h.logger.Error("failed to get hero achievements", "hero_id", hero.ID, "error", err)
|
|
writeJSON(w, http.StatusInternalServerError, map[string]string{
|
|
"error": "failed to load hero achievements",
|
|
})
|
|
return
|
|
}
|
|
|
|
// Build lookup of unlocked achievement IDs.
|
|
unlockedMap := make(map[string]*model.HeroAchievement, len(heroAchievements))
|
|
for i := range heroAchievements {
|
|
unlockedMap[heroAchievements[i].AchievementID] = &heroAchievements[i]
|
|
}
|
|
|
|
// Build response combining definitions with unlock status.
|
|
views := make([]model.AchievementView, 0, len(allAchievements))
|
|
for _, a := range allAchievements {
|
|
view := model.AchievementView{
|
|
Achievement: a,
|
|
}
|
|
if ha, ok := unlockedMap[a.ID]; ok {
|
|
view.Unlocked = true
|
|
view.UnlockedAt = &ha.UnlockedAt
|
|
}
|
|
views = append(views, view)
|
|
}
|
|
|
|
writeJSON(w, http.StatusOK, views)
|
|
}
|