package handlers import ( "fmt" "log/slog" "net/http" "strconv" "github.com/go-chi/chi/v5" "qbank/internal/auth" "qbank/internal/db" ) type QuestionHandler struct { auth *auth.Manager repo *db.Repo render *Renderer } func NewQuestionHandler(a *auth.Manager, repo *db.Repo, r *Renderer) *QuestionHandler { return &QuestionHandler{auth: a, repo: repo, render: r} } func (h *QuestionHandler) Show(w http.ResponseWriter, r *http.Request) { id := chi.URLParam(r, "id") user := auth.UserFromCtx(r.Context()) q, answers, err := h.repo.GetQuestion(id) if err != nil { HTTPError(w, http.StatusNotFound) return } stats, _ := h.repo.GetStatsForUser(user.ID, []string{id}) data := BaseData(h.auth, r) data["Question"] = q data["Answers"] = answers data["Stat"] = stats[id] h.render.Render(w, http.StatusOK, "question", data) } func (h *QuestionHandler) Edit(w http.ResponseWriter, r *http.Request) { id := chi.URLParam(r, "id") if !h.auth.CheckCSRF(r) { HTTPError(w, http.StatusForbidden) return } r.Body = http.MaxBytesReader(w, r.Body, 1<<20) if err := r.ParseForm(); err != nil { HTTPError(w, http.StatusBadRequest) return } _, answers, err := h.repo.GetQuestion(id) if err != nil { HTTPError(w, http.StatusNotFound) return } text := r.FormValue("q_text") source := r.FormValue("source") correctIdx, _ := strconv.Atoi(r.FormValue("correct")) if err := h.repo.UpdateQuestion(id, text, source); err != nil { slog.Error("update question", "err", err) HTTPError(w, http.StatusInternalServerError) return } updates := make([]db.AnswerUpdate, len(answers)) for i, a := range answers { updates[i] = db.AnswerUpdate{ ID: a.ID, Text: r.FormValue(fmt.Sprintf("a_text_%d", i)), IsCorrect: i == correctIdx, } } if err := h.repo.UpdateAnswers(updates); err != nil { slog.Error("update answers", "err", err) HTTPError(w, http.StatusInternalServerError) return } h.auth.SetFlash(r, "Question saved.") http.Redirect(w, r, "/questions/"+id, http.StatusSeeOther) } func (h *QuestionHandler) Delete(w http.ResponseWriter, r *http.Request) { id := chi.URLParam(r, "id") if !h.auth.CheckCSRF(r) { HTTPError(w, http.StatusForbidden) return } r.Body = http.MaxBytesReader(w, r.Body, 4096) r.ParseForm() if err := h.repo.DeleteQuestion(id); err != nil { slog.Error("delete question", "err", err) HTTPError(w, http.StatusInternalServerError) return } h.auth.SetFlash(r, "Question deleted.") http.Redirect(w, r, "/", http.StatusSeeOther) }