0.2.71
This commit is contained in:
@@ -57,6 +57,7 @@ func (s *Server) adminRoutes() http.Handler {
|
||||
mux.Handle("POST /admin/api/sync", s.adminAuth(s.handleAdminSync))
|
||||
mux.Handle("POST /admin/api/for-you", s.adminAuth(s.handleAdminForYou))
|
||||
mux.Handle("POST /admin/api/maintenance", s.adminAuth(s.handleAdminMaintenance))
|
||||
mux.Handle("POST /admin/api/quiet-time", s.adminAuth(s.handleAdminQuietTime))
|
||||
mux.Handle("POST /admin/api/deployment-alert", s.adminAuth(s.handleAdminDeploymentAlert))
|
||||
mux.Handle("POST /admin/api/update-policy", s.adminAuth(s.handleAdminUpdatePolicy))
|
||||
mux.Handle("GET /admin/api/release-builder", s.adminAuth(s.handleAdminReleaseBuilderStatus))
|
||||
@@ -233,6 +234,7 @@ type adminStatus struct {
|
||||
ServerVersion string `json:"serverVersion"`
|
||||
CurrentUser string `json:"currentUser,omitempty"`
|
||||
Maintenance store.Maintenance `json:"maintenance"`
|
||||
QuietTime quietTimeStatus `json:"quietTime"`
|
||||
UpdatePolicy appupdate.Policy `json:"updatePolicy"`
|
||||
Library store.LibraryStats `json:"library"`
|
||||
SyncRunning bool `json:"syncRunning"`
|
||||
@@ -301,6 +303,7 @@ func (s *Server) handleAdminStatus(w http.ResponseWriter, r *http.Request) {
|
||||
return username
|
||||
}(),
|
||||
Maintenance: s.maintenance.get(),
|
||||
QuietTime: s.quietTimeStatus(time.Now()),
|
||||
UpdatePolicy: s.updatePolicy.get(),
|
||||
Library: stats,
|
||||
SyncRunning: s.syncer.Running(),
|
||||
@@ -605,6 +608,9 @@ type syncRequest struct {
|
||||
// handleAdminSync starts an import in the background and returns immediately. A full
|
||||
// import of a large library takes minutes; the page polls /admin/api/status for progress.
|
||||
func (s *Server) handleAdminSync(w http.ResponseWriter, r *http.Request) {
|
||||
if s.rejectWorkDuringQuietTime(w) {
|
||||
return
|
||||
}
|
||||
var req syncRequest
|
||||
if err := json.NewDecoder(http.MaxBytesReader(w, r.Body, 4<<10)).Decode(&req); err != nil {
|
||||
writeError(w, http.StatusBadRequest, "malformed request body")
|
||||
@@ -640,6 +646,9 @@ type forYouAdminRequest struct {
|
||||
// handleAdminForYou provides the recovery controls needed for an idempotent backfill:
|
||||
// import all Tracearr sessions again, or rebuild every active user's derived pool.
|
||||
func (s *Server) handleAdminForYou(w http.ResponseWriter, r *http.Request) {
|
||||
if s.rejectWorkDuringQuietTime(w) {
|
||||
return
|
||||
}
|
||||
if s.forYou == nil {
|
||||
writeError(w, http.StatusServiceUnavailable, "Tracearr is not configured")
|
||||
return
|
||||
@@ -731,6 +740,47 @@ func (s *Server) handleAdminMaintenance(w http.ResponseWriter, r *http.Request)
|
||||
writeJSON(w, http.StatusOK, s.maintenance.get())
|
||||
}
|
||||
|
||||
type quietTimeRequest struct {
|
||||
Enabled bool `json:"enabled"`
|
||||
StartTime string `json:"startTime"`
|
||||
EndTime string `json:"endTime"`
|
||||
Message string `json:"message"`
|
||||
}
|
||||
|
||||
func (s *Server) handleAdminQuietTime(w http.ResponseWriter, r *http.Request) {
|
||||
var req quietTimeRequest
|
||||
if err := json.NewDecoder(http.MaxBytesReader(w, r.Body, 8<<10)).Decode(&req); err != nil {
|
||||
writeError(w, http.StatusBadRequest, "malformed request body")
|
||||
return
|
||||
}
|
||||
start, startErr := time.Parse("15:04", strings.TrimSpace(req.StartTime))
|
||||
end, endErr := time.Parse("15:04", strings.TrimSpace(req.EndTime))
|
||||
if startErr != nil || endErr != nil {
|
||||
writeError(w, http.StatusBadRequest, "quiet time must use valid 24-hour start and end times")
|
||||
return
|
||||
}
|
||||
if start.Equal(end) {
|
||||
writeError(w, http.StatusBadRequest, "quiet time start and end must be different")
|
||||
return
|
||||
}
|
||||
policy := store.QuietTime{
|
||||
Enabled: req.Enabled, StartTime: start.Format("15:04"), EndTime: end.Format("15:04"),
|
||||
Message: strings.TrimSpace(req.Message),
|
||||
}
|
||||
if err := s.store.SetQuietTime(r.Context(), policy); err != nil {
|
||||
s.loggerFor(r.Context()).Error("quiet-time write failed", "error", err)
|
||||
writeError(w, http.StatusInternalServerError, "could not update quiet time")
|
||||
return
|
||||
}
|
||||
if err := s.LoadQuietTime(r.Context()); err != nil {
|
||||
s.loggerFor(r.Context()).Warn("quiet-time reload failed", "error", err)
|
||||
}
|
||||
status := s.quietTimeStatus(time.Now())
|
||||
s.loggerFor(r.Context()).Info("quiet time changed", "enabled", status.Enabled,
|
||||
"active", status.Active, "start", status.StartTime, "end", status.EndTime)
|
||||
writeJSON(w, http.StatusOK, status)
|
||||
}
|
||||
|
||||
func (s *Server) handleAdminAnalytics(w http.ResponseWriter, r *http.Request) {
|
||||
days := queryInt(r, "days", 7, 90)
|
||||
since := time.Now().UTC().AddDate(0, 0, -days)
|
||||
|
||||
Reference in New Issue
Block a user