From 799d27b58c13b97d089e03c0c6a94a48886018f5 Mon Sep 17 00:00:00 2001 From: Sam Date: Tue, 21 Mar 2023 14:27:39 +0100 Subject: [PATCH] feat: add list reports endpoints --- backend/db/report.go | 49 ++++++++++++++++++-- backend/routes/mod/get_reports.go | 77 +++++++++++++++++++++++++++++-- backend/routes/mod/routes.go | 4 +- 3 files changed, 122 insertions(+), 8 deletions(-) diff --git a/backend/db/report.go b/backend/db/report.go index 9162638..8137c82 100644 --- a/backend/db/report.go +++ b/backend/db/report.go @@ -22,10 +22,13 @@ type Report struct { AdminComment *string } -const reportPageSize = 100 +const ReportPageSize = 100 -func (db *DB) Reports(ctx context.Context, closed bool, page int) (rs []Report, err error) { - builder := sq.Select("*").From("reports").Offset(uint64(reportPageSize * page)).Limit(reportPageSize).OrderBy("id ASC") +func (db *DB) Reports(ctx context.Context, closed bool, before int) (rs []Report, err error) { + builder := sq.Select("*").From("reports").Limit(ReportPageSize).OrderBy("id DESC") + if before != 0 { + builder = builder.Where("id < ?", before) + } if closed { builder = builder.Where("resolved_at IS NOT NULL") } else { @@ -45,3 +48,43 @@ func (db *DB) Reports(ctx context.Context, closed bool, page int) (rs []Report, } return rs, nil } + +func (db *DB) ReportsByUser(ctx context.Context, userID xid.ID, before int) (rs []Report, err error) { + builder := sq.Select("*").From("reports").Where("user_id = ?", userID).Limit(ReportPageSize).OrderBy("id DESC") + if before != 0 { + builder = builder.Where("id < ?", before) + } + sql, args, err := builder.ToSql() + if err != nil { + return nil, errors.Wrap(err, "building sql") + } + + err = pgxscan.Select(ctx, db, &rs, sql, args...) + if err != nil { + return nil, errors.Wrap(err, "executing query") + } + if len(rs) == 0 { + return []Report{}, nil + } + return rs, nil +} + +func (db *DB) ReportsByReporter(ctx context.Context, reporterID xid.ID, before int) (rs []Report, err error) { + builder := sq.Select("*").From("reports").Where("reporter_id = ?", reporterID).Limit(ReportPageSize).OrderBy("id DESC") + if before != 0 { + builder = builder.Where("id < ?", before) + } + sql, args, err := builder.ToSql() + if err != nil { + return nil, errors.Wrap(err, "building sql") + } + + err = pgxscan.Select(ctx, db, &rs, sql, args...) + if err != nil { + return nil, errors.Wrap(err, "executing query") + } + if len(rs) == 0 { + return []Report{}, nil + } + return rs, nil +} diff --git a/backend/routes/mod/get_reports.go b/backend/routes/mod/get_reports.go index 62707d1..1aad2e8 100644 --- a/backend/routes/mod/get_reports.go +++ b/backend/routes/mod/get_reports.go @@ -1,13 +1,84 @@ package mod import ( - "fmt" "net/http" + "strconv" + + "codeberg.org/u1f320/pronouns.cc/backend/log" + "codeberg.org/u1f320/pronouns.cc/backend/server" + "emperror.dev/errors" + "github.com/go-chi/chi/v5" + "github.com/go-chi/render" + "github.com/rs/xid" ) -func (s *Server) getReports(w http.ResponseWriter, r *http.Request) error { +func (s *Server) getReports(w http.ResponseWriter, r *http.Request) (err error) { + ctx := r.Context() showClosed := r.FormValue("closed") == "true" + var before int + if s := r.FormValue("before"); s != "" { + before, err = strconv.Atoi(s) + if err != nil { + return server.APIError{Code: server.ErrBadRequest, Details: "\"before\": invalid ID"} + } + } - fmt.Println("closed =", showClosed) + reports, err := s.DB.Reports(ctx, showClosed, before) + if err != nil { + log.Errorf("getting reports: %v", err) + return errors.Wrap(err, "getting reports from database") + } + + render.JSON(w, r, reports) + return nil +} + +func (s *Server) getReportsByUser(w http.ResponseWriter, r *http.Request) (err error) { + ctx := r.Context() + var before int + if s := r.FormValue("before"); s != "" { + before, err = strconv.Atoi(s) + if err != nil { + return server.APIError{Code: server.ErrBadRequest, Details: "\"before\": invalid ID"} + } + } + + userID, err := xid.FromString(chi.URLParam(r, "id")) + if err != nil { + return server.APIError{Code: server.ErrBadRequest, Details: "Invalid user ID"} + } + + reports, err := s.DB.ReportsByUser(ctx, userID, before) + if err != nil { + log.Errorf("getting reports: %v", err) + return errors.Wrap(err, "getting reports from database") + } + + render.JSON(w, r, reports) + return nil +} + +func (s *Server) getReportsByReporter(w http.ResponseWriter, r *http.Request) (err error) { + ctx := r.Context() + var before int + if s := r.FormValue("before"); s != "" { + before, err = strconv.Atoi(s) + if err != nil { + return server.APIError{Code: server.ErrBadRequest, Details: "\"before\": invalid ID"} + } + } + + userID, err := xid.FromString(chi.URLParam(r, "id")) + if err != nil { + return server.APIError{Code: server.ErrBadRequest, Details: "Invalid user ID"} + } + + reports, err := s.DB.ReportsByReporter(ctx, userID, before) + if err != nil { + log.Errorf("getting reports: %v", err) + return errors.Wrap(err, "getting reports from database") + } + + render.JSON(w, r, reports) return nil } diff --git a/backend/routes/mod/routes.go b/backend/routes/mod/routes.go index 6d76ee0..88b9657 100644 --- a/backend/routes/mod/routes.go +++ b/backend/routes/mod/routes.go @@ -17,8 +17,8 @@ func Mount(srv *server.Server, r chi.Router) { r.With(MustAdmin).Route("/admin", func(r chi.Router) { r.Get("/reports", server.WrapHandler(s.getReports)) - r.Get("/reports/by-user/{id}", nil) - r.Get("/reports/by-reporter/{id}", nil) + r.Get("/reports/by-user/{id}", server.WrapHandler(s.getReportsByUser)) + r.Get("/reports/by-reporter/{id}", server.WrapHandler(s.getReportsByReporter)) r.Patch("/reports/{id}", nil) })