dbots/internal/bot/router.go

147 lines
3.6 KiB
Go

package bot
import (
"errors"
"net/http"
"codeberg.org/nextgo/dbots/internal/db"
"codeberg.org/nextgo/dbots/internal/errorutil"
"codeberg.org/nextgo/dbots/internal/middleware"
"codeberg.org/nextgo/dbots/internal/paginate"
"github.com/go-chi/chi/v5"
"github.com/go-chi/render"
)
type Router struct {
bots *Service
router chi.Router
}
func NewRouter(q *db.Queries) *Router {
return &Router{
bots: NewService(q),
router: chi.NewRouter(),
}
}
func (r *Router) Routes() http.Handler {
r.router.Get("/", r.listBots) // todo: deprecate this
r.router.With(middleware.AuthGuardMiddleware).Post("/", r.submitBot)
r.router.Route("/{botID}", func(router chi.Router) {
router.Use(middleware.BotContext(r.bots.q))
router.With(r.BotCache).Get("/", r.getBot)
router.Route("/co-owners", func(c chi.Router) {
c.Use(middleware.AuthGuardMiddleware)
c.Get("/", r.listCoOwners)
c.Post("/{userID}", r.addCoOwner)
c.Delete("/{userID}", r.removeCoOwner)
})
})
return r.router
}
func (r *Router) submitBot(w http.ResponseWriter, req *http.Request) {
var data CreateBotRequest
if err := render.Bind(req, &data); err != nil {
render.Render(w, req, errorutil.ErrInvalidRequest(err))
return
}
ctx := req.Context()
bot, err := r.bots.Submit(ctx, data)
if err != nil {
if errors.Is(err, errorutil.ErrBotAlreadyExists) {
render.Render(w, req, errorutil.ErrInvalidRequest(err))
} else {
render.Render(w, req, errorutil.ErrInternal(err))
}
return
}
render.Status(req, http.StatusCreated)
render.JSON(w, req, bot)
}
func (r *Router) getBot(w http.ResponseWriter, req *http.Request) {
ctx := req.Context()
bot := middleware.GetBot(ctx)
render.JSON(w, req, bot)
}
func (r *Router) listBots(w http.ResponseWriter, req *http.Request) {
ctx := req.Context()
query := req.URL.Query().Get("q")
p := paginate.ParseParams(req)
page, err := r.bots.List(ctx, query, p)
if err != nil {
render.Render(w, req, errorutil.ErrInvalidRequest(err))
return
}
render.JSON(w, req, page)
}
func (r *Router) listCoOwners(w http.ResponseWriter, req *http.Request) {
ctx := req.Context()
bot := middleware.GetBot(ctx)
owners, err := r.bots.ListCoOwners(ctx, bot.ID)
if err != nil {
render.Render(w, req, errorutil.ErrInternal(err))
return
}
render.JSON(w, req, owners)
}
func (r *Router) addCoOwner(w http.ResponseWriter, req *http.Request) {
ctx := req.Context()
bot := middleware.GetBot(ctx)
userID := chi.URLParam(req, "userID")
if err := r.bots.AddCoOwner(ctx, bot.ID, userID); err != nil {
switch {
case errors.Is(err, errorutil.ErrNotFound.Err):
render.Render(w, req, errorutil.ErrNotFound)
case errors.Is(err, errorutil.ErrForbidden.Err):
render.Render(w, req, errorutil.ErrForbidden)
default:
render.Render(w, req, errorutil.ErrInvalidRequest(err))
}
return
}
render.NoContent(w, req)
}
func (r *Router) removeCoOwner(w http.ResponseWriter, req *http.Request) {
ctx := req.Context()
bot := middleware.GetBot(ctx)
userID := chi.URLParam(req, "userID")
if err := r.bots.RemoveCoOwner(ctx, bot.ID, userID); err != nil {
switch {
case errors.Is(err, errorutil.ErrNotFound.Err):
render.Render(w, req, errorutil.ErrNotFound)
case errors.Is(err, errorutil.ErrForbidden.Err):
render.Render(w, req, errorutil.ErrForbidden)
default:
render.Render(w, req, errorutil.ErrInternal(err))
}
return
}
render.NoContent(w, req)
}
func (r *Router) BotCache(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
w.Header().Add("Cache-Control", "max-age=3600")
next.ServeHTTP(w, req)
})
}