mirror of
https://github.com/knadh/listmonk.git
synced 2025-10-05 12:57:37 +08:00
This patch significantly cleans up clunky, repetitive, and pervasive validation logic across HTTP handlers. - Rather than dozens of handlers checking and using strconv to validate ID, the handlers with `:id` are now wrapped in a `hasID()` middleware that does the validation and sets an int `id` in the handler context that the wrapped handlers can now access with `getID()`. - Handlers that handled both single + multi resource requests (eg: GET `/api/lists`) with single/multiple id checking conditions are all now split into separate handlers, eg: `getList()`, `getLists()`.
195 lines
4.4 KiB
Go
195 lines
4.4 KiB
Go
package main
|
|
|
|
import (
|
|
"fmt"
|
|
"net/http"
|
|
"strings"
|
|
|
|
"github.com/knadh/listmonk/internal/auth"
|
|
"github.com/labstack/echo/v4"
|
|
)
|
|
|
|
// GetUserRoles retrieves roles.
|
|
func (a *App) GetUserRoles(c echo.Context) error {
|
|
// Get all roles.
|
|
out, err := a.core.GetRoles()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
return c.JSON(http.StatusOK, okResp{out})
|
|
}
|
|
|
|
// GeListRoles retrieves roles.
|
|
func (a *App) GeListRoles(c echo.Context) error {
|
|
// Get all roles.
|
|
out, err := a.core.GetListRoles()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
return c.JSON(http.StatusOK, okResp{out})
|
|
}
|
|
|
|
// CreateUserRole handles role creation.
|
|
func (a *App) CreateUserRole(c echo.Context) error {
|
|
var r auth.Role
|
|
if err := c.Bind(&r); err != nil {
|
|
return err
|
|
}
|
|
if err := a.validateUserRole(r); err != nil {
|
|
return err
|
|
}
|
|
|
|
// Create the role in the DB.
|
|
out, err := a.core.CreateRole(r)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
return c.JSON(http.StatusOK, okResp{out})
|
|
}
|
|
|
|
// CreateListRole handles role creation.
|
|
func (a *App) CreateListRole(c echo.Context) error {
|
|
var r auth.ListRole
|
|
if err := c.Bind(&r); err != nil {
|
|
return err
|
|
}
|
|
if err := a.validateListRole(r); err != nil {
|
|
return err
|
|
}
|
|
|
|
// Create the role in the DB.
|
|
out, err := a.core.CreateListRole(r)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
return c.JSON(http.StatusOK, okResp{out})
|
|
}
|
|
|
|
// UpdateUserRole handles role modification.
|
|
func (a *App) UpdateUserRole(c echo.Context) error {
|
|
id := getID(c)
|
|
|
|
// ID 1 is reserved for the Super Admin user role.
|
|
if id == auth.SuperAdminRoleID {
|
|
return echo.NewHTTPError(http.StatusBadRequest, a.i18n.T("globals.messages.invalidID"))
|
|
}
|
|
|
|
// Incoming params.
|
|
var r auth.Role
|
|
if err := c.Bind(&r); err != nil {
|
|
return err
|
|
}
|
|
if err := a.validateUserRole(r); err != nil {
|
|
return err
|
|
}
|
|
|
|
// Validate.
|
|
r.Name.String = strings.TrimSpace(r.Name.String)
|
|
|
|
// Update the role in the DB.
|
|
out, err := a.core.UpdateUserRole(id, r)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
// Cache API tokens for in-memory, off-DB /api/* request auth.
|
|
if _, err := cacheUsers(a.core, a.auth); err != nil {
|
|
return err
|
|
}
|
|
|
|
return c.JSON(http.StatusOK, okResp{out})
|
|
}
|
|
|
|
// UpdateListRole handles role modification.
|
|
func (a *App) UpdateListRole(c echo.Context) error {
|
|
// Get the role ID.
|
|
id := getID(c)
|
|
|
|
// ID 1 is reserved for the Super Admin user role.
|
|
if id == auth.SuperAdminRoleID {
|
|
return echo.NewHTTPError(http.StatusBadRequest, a.i18n.T("globals.messages.invalidID"))
|
|
}
|
|
|
|
// Incoming params.
|
|
var r auth.ListRole
|
|
if err := c.Bind(&r); err != nil {
|
|
return err
|
|
}
|
|
|
|
if err := a.validateListRole(r); err != nil {
|
|
return err
|
|
}
|
|
|
|
// Validate.
|
|
r.Name.String = strings.TrimSpace(r.Name.String)
|
|
|
|
// Update the role in the DB.
|
|
out, err := a.core.UpdateListRole(id, r)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
// Cache API tokens for in-memory, off-DB /api/* request auth.
|
|
if _, err := cacheUsers(a.core, a.auth); err != nil {
|
|
return err
|
|
}
|
|
|
|
return c.JSON(http.StatusOK, okResp{out})
|
|
}
|
|
|
|
// DeleteRole handles (user|list) role deletion.
|
|
func (a *App) DeleteRole(c echo.Context) error {
|
|
// Get the role ID.
|
|
id := getID(c)
|
|
|
|
// ID 1 is reserved for the Super Admin user role.
|
|
if id == auth.SuperAdminRoleID {
|
|
return echo.NewHTTPError(http.StatusBadRequest, a.i18n.T("globals.messages.invalidID"))
|
|
}
|
|
|
|
// Delete the role from the DB.
|
|
if err := a.core.DeleteRole(int(id)); err != nil {
|
|
return err
|
|
}
|
|
|
|
// Cache API tokens for in-memory, off-DB /api/* request auth.
|
|
if _, err := cacheUsers(a.core, a.auth); err != nil {
|
|
return err
|
|
}
|
|
|
|
return c.JSON(http.StatusOK, okResp{true})
|
|
}
|
|
|
|
func (a *App) validateUserRole(r auth.Role) error {
|
|
if !strHasLen(r.Name.String, 1, stdInputMaxLen) {
|
|
return echo.NewHTTPError(http.StatusBadRequest, a.i18n.Ts("globals.messages.invalidFields", "name", "name"))
|
|
}
|
|
|
|
for _, p := range r.Permissions {
|
|
if _, ok := a.cfg.Permissions[p]; !ok {
|
|
return echo.NewHTTPError(http.StatusBadRequest, a.i18n.Ts("globals.messages.invalidFields", "name", fmt.Sprintf("permission: %s", p)))
|
|
}
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func (a *App) validateListRole(r auth.ListRole) error {
|
|
if !strHasLen(r.Name.String, 1, stdInputMaxLen) {
|
|
return echo.NewHTTPError(http.StatusBadRequest, a.i18n.Ts("globals.messages.invalidFields", "name", "name"))
|
|
}
|
|
|
|
for _, l := range r.Lists {
|
|
for _, p := range l.Permissions {
|
|
if p != auth.PermListGet && p != auth.PermListManage {
|
|
return echo.NewHTTPError(http.StatusBadRequest, a.i18n.Ts("globals.messages.invalidFields", "name", fmt.Sprintf("list permission: %s", p)))
|
|
}
|
|
}
|
|
}
|
|
|
|
return nil
|
|
}
|