This repository has been archived on 2024-04-07. You can view files and clone it, but cannot push or open issues or pull requests.
summer-utils/api/crud/generic.go
2023-04-16 11:56:17 +01:00

172 lines
5.1 KiB
Go

package crud
import (
"code.mrmelon54.com/melon/summer/pkg/api"
"code.mrmelon54.com/melon/summer/pkg/claims/auth"
"code.mrmelon54.com/melon/summer/pkg/utils"
"encoding/json"
"github.com/gorilla/mux"
"github.com/mrmelon54/mjwt"
"net/http"
)
type crudHandler[T any] struct {
provider Provider[T]
verify mjwt.Provider
}
type secureHandlerFunc func(rw http.ResponseWriter, req *http.Request, claims *auth.AccessTokenClaims)
func NewCrudHandler[T any](router *mux.Router, verify mjwt.Provider, provider Provider[T], findPath, itemPath string) {
z := &crudHandler[T]{provider: provider, verify: verify}
router.HandleFunc(findPath, z.claimExtractor(z.handleFind)).Methods(http.MethodGet)
router.HandleFunc(findPath, z.claimExtractor(z.handleAdd)).Methods(http.MethodPost)
router.HandleFunc(itemPath, z.claimExtractor(z.handleGet)).Methods(http.MethodGet)
router.HandleFunc(itemPath, z.claimExtractor(z.handlePut)).Methods(http.MethodPut)
router.HandleFunc(itemPath, z.claimExtractor(z.handlePatch)).Methods(http.MethodPatch)
router.HandleFunc(itemPath, z.claimExtractor(z.handleDelete)).Methods(http.MethodDelete)
}
func (c *crudHandler[T]) claimExtractor(f secureHandlerFunc) func(rw http.ResponseWriter, req *http.Request) {
return func(rw http.ResponseWriter, req *http.Request) {
token := utils.GetBearerToken(req)
if token == "" {
f(rw, req, nil)
return
}
// Verify as mfa flow token
_, b, err := mjwt.ExtractClaims[auth.AccessTokenClaims](c.verify, token)
if err != nil {
f(rw, req, nil)
return
}
f(rw, req, &b.Claims)
}
}
func (c *crudHandler[T]) handleFind(rw http.ResponseWriter, _ *http.Request, claims *auth.AccessTokenClaims) {
a, err := c.provider.Find(claims)
if HttpCatchError(rw, err) {
return
}
if api.GenericErrorMsg[T](rw, err, http.StatusInternalServerError, "Find error") {
return
}
rw.Header().Set("Content-Type", "application/json")
rw.WriteHeader(http.StatusOK)
err = json.NewEncoder(rw).Encode(a)
if api.GenericErrorMsg[T](rw, err, http.StatusInternalServerError, "Encode error") {
return
}
}
func (c *crudHandler[T]) handleAdd(rw http.ResponseWriter, req *http.Request, claims *auth.AccessTokenClaims) {
var t T
err := json.NewDecoder(req.Body).Decode(&t)
if api.GenericErrorMsg[T](rw, err, http.StatusBadRequest, "Decode error") {
return
}
t, err = c.provider.Add(claims, t)
if HttpCatchError(rw, err) {
return
}
if api.GenericErrorMsg[T](rw, err, http.StatusInternalServerError, "Add error") {
return
}
rw.Header().Set("Content-Type", "application/json")
rw.WriteHeader(http.StatusCreated)
err = json.NewEncoder(rw).Encode(&t)
if api.GenericErrorMsg[T](rw, err, http.StatusInternalServerError, "Encode error") {
return
}
}
func (c *crudHandler[T]) handleGet(rw http.ResponseWriter, req *http.Request, claims *auth.AccessTokenClaims) {
vars := mux.Vars(req)
s, ok := vars["id"]
if !ok {
api.GenericErrorMsg[T](rw, api.ErrParamMissing, http.StatusBadRequest, "Parameter error")
return
}
t, found, err := c.provider.Get(claims, s)
if HttpCatchError(rw, err) {
return
}
if api.GenericErrorMsg[T](rw, err, http.StatusInternalServerError, "Get error") {
return
}
if !found {
api.GenericErrorMsg[T](rw, err, http.StatusNotFound, "Not Found")
return
}
rw.Header().Set("Content-Type", "application/json")
rw.WriteHeader(http.StatusOK)
err = json.NewEncoder(rw).Encode(&t)
if api.GenericErrorMsg[T](rw, err, http.StatusInternalServerError, "Encode error") {
return
}
}
func (c *crudHandler[T]) handlePut(rw http.ResponseWriter, req *http.Request, claims *auth.AccessTokenClaims) {
vars := mux.Vars(req)
s, ok := vars["id"]
if !ok {
api.GenericErrorMsg[T](rw, api.ErrParamMissing, http.StatusBadRequest, "Parameter error")
return
}
var t T
err := json.NewDecoder(req.Body).Decode(&t)
if api.GenericErrorMsg[T](rw, err, http.StatusBadRequest, "Decode error") {
return
}
err = c.provider.Put(claims, s, t)
if HttpCatchError(rw, err) {
return
}
if api.GenericErrorMsg[T](rw, err, http.StatusInternalServerError, "Put error") {
return
}
rw.WriteHeader(http.StatusNoContent)
}
func (c *crudHandler[T]) handlePatch(rw http.ResponseWriter, req *http.Request, claims *auth.AccessTokenClaims) {
vars := mux.Vars(req)
s, ok := vars["id"]
if !ok {
api.GenericErrorMsg[T](rw, api.ErrParamMissing, http.StatusBadRequest, "Parameter error")
return
}
var t T
err := json.NewDecoder(req.Body).Decode(&t)
if api.GenericErrorMsg[T](rw, err, http.StatusBadRequest, "Decode error") {
return
}
err = c.provider.Patch(claims, s, t)
if HttpCatchError(rw, err) {
return
}
if api.GenericErrorMsg[T](rw, err, http.StatusInternalServerError, "Patch error") {
return
}
rw.WriteHeader(http.StatusNoContent)
}
func (c *crudHandler[T]) handleDelete(rw http.ResponseWriter, req *http.Request, claims *auth.AccessTokenClaims) {
vars := mux.Vars(req)
s, ok := vars["id"]
if !ok {
api.GenericErrorMsg[T](rw, api.ErrParamMissing, http.StatusBadRequest, "Parameter error")
return
}
err := c.provider.Delete(claims, s)
if HttpCatchError(rw, err) {
return
}
if api.GenericErrorMsg[T](rw, err, http.StatusInternalServerError, "Delete error") {
return
}
rw.WriteHeader(http.StatusNoContent)
}