feat: implement 8 features across full stack
- Leaderboard: rank-based percentile tiers (champion/gold/silver/bronze),
deterministic tie-breaking (xp DESC, user_id ASC)
- Mentor chat: md: breakpoints, safe-area-inset-bottom padding
- Learning progress: server-side progressPct, curriculum expansion safety
- Physical orders: hard-disabled with 410 Gone
- Certificate approval: pending/issued flow, admin issue/revoke endpoints,
certificate_requires_approval setting (migration 0031)
- Draft/publish: is_published on lessons and chapters, admin publish UI
(migration 0030)
- Video panel: static thumbnails (no preload), client-side pagination
- Rich editor: TipTap + tiptap-markdown for lesson descriptions,
marked + DOMPurify for SafeMarkdown rendering
This commit is contained in:
@@ -575,6 +575,38 @@ func (s *Server) handleAdminDeleteLesson(w http.ResponseWriter, r *http.Request)
|
||||
writeJSON(w, http.StatusOK, map[string]any{"ok": true})
|
||||
}
|
||||
|
||||
func (s *Server) handleAdminPublishLesson(w http.ResponseWriter, r *http.Request) {
|
||||
id := routeID(r, "id")
|
||||
var body struct {
|
||||
Publish bool `json:"publish"`
|
||||
}
|
||||
if err := bodyJSON(r, &body); err != nil {
|
||||
writeErr(w, http.StatusBadRequest, "دادهٔ ارسالی نامعتبر است")
|
||||
return
|
||||
}
|
||||
if err := s.store.PublishLesson(r.Context(), id, body.Publish); err != nil {
|
||||
writeErr(w, http.StatusInternalServerError, "بهروزرسانی وضعیت درس ممکن نشد")
|
||||
return
|
||||
}
|
||||
writeJSON(w, http.StatusOK, map[string]any{"ok": true})
|
||||
}
|
||||
|
||||
func (s *Server) handleAdminPublishChapter(w http.ResponseWriter, r *http.Request) {
|
||||
id := routeID(r, "id")
|
||||
var body struct {
|
||||
Publish bool `json:"publish"`
|
||||
}
|
||||
if err := bodyJSON(r, &body); err != nil {
|
||||
writeErr(w, http.StatusBadRequest, "دادهٔ ارسالی نامعتبر است")
|
||||
return
|
||||
}
|
||||
if err := s.store.PublishChapter(r.Context(), id, body.Publish); err != nil {
|
||||
writeErr(w, http.StatusInternalServerError, "بهروزرسانی وضعیت فصل ممکن نشد")
|
||||
return
|
||||
}
|
||||
writeJSON(w, http.StatusOK, map[string]any{"ok": true})
|
||||
}
|
||||
|
||||
// ---- questions ----
|
||||
|
||||
func (s *Server) handleAdminListQuestions(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
Reference in New Issue
Block a user