mirror of
https://github.com/knadh/listmonk.git
synced 2025-09-12 01:14:50 +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()`.
173 lines
4 KiB
Go
173 lines
4 KiB
Go
package main
|
|
|
|
import (
|
|
"net/http"
|
|
"strconv"
|
|
"strings"
|
|
|
|
"github.com/knadh/listmonk/internal/auth"
|
|
"github.com/knadh/listmonk/models"
|
|
"github.com/labstack/echo/v4"
|
|
)
|
|
|
|
// GetLists retrieves lists with additional metadata like subscriber counts.
|
|
func (a *App) GetLists(c echo.Context) error {
|
|
// Get the authenticated user.
|
|
user := auth.GetUser(c)
|
|
|
|
// Get the list IDs (or blanket permission) the user has access to.
|
|
hasAllPerm, permittedIDs := user.GetPermittedLists(auth.PermTypeGet)
|
|
|
|
// Minimal query simply returns the list of all lists without JOIN subscriber counts. This is fast.
|
|
minimal, _ := strconv.ParseBool(c.FormValue("minimal"))
|
|
if minimal {
|
|
res, err := a.core.GetLists("", hasAllPerm, permittedIDs)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
if len(res) == 0 {
|
|
return c.JSON(http.StatusOK, okResp{[]struct{}{}})
|
|
}
|
|
|
|
// Meta.
|
|
total := len(res)
|
|
out := models.PageResults{
|
|
Results: res,
|
|
Total: total,
|
|
Page: 1,
|
|
PerPage: total,
|
|
}
|
|
|
|
return c.JSON(http.StatusOK, okResp{out})
|
|
}
|
|
|
|
// Full list query.
|
|
var (
|
|
query = strings.TrimSpace(c.FormValue("query"))
|
|
tags = c.QueryParams()["tag"]
|
|
orderBy = c.FormValue("order_by")
|
|
typ = c.FormValue("type")
|
|
optin = c.FormValue("optin")
|
|
order = c.FormValue("order")
|
|
|
|
pg = a.pg.NewFromURL(c.Request().URL.Query())
|
|
)
|
|
res, total, err := a.core.QueryLists(query, typ, optin, tags, orderBy, order, hasAllPerm, permittedIDs, pg.Offset, pg.Limit)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
out := models.PageResults{
|
|
Query: query,
|
|
Results: res,
|
|
Total: total,
|
|
Page: pg.Page,
|
|
PerPage: pg.PerPage,
|
|
}
|
|
|
|
return c.JSON(http.StatusOK, okResp{out})
|
|
}
|
|
|
|
// GetList retrieves a single list by id.
|
|
// It's permission checked by the listPerm middleware.
|
|
func (a *App) GetList(c echo.Context) error {
|
|
// Get the authenticated user.
|
|
user := auth.GetUser(c)
|
|
|
|
// Check if the user has access to the list.
|
|
id := getID(c)
|
|
if err := user.HasListPerm(auth.PermTypeGet, id); err != nil {
|
|
return err
|
|
}
|
|
|
|
// Get the list from the DB.
|
|
out, err := a.core.GetList(id, "")
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
return c.JSON(http.StatusOK, okResp{out})
|
|
}
|
|
|
|
// CreateList handles list creation.
|
|
func (a *App) CreateList(c echo.Context) error {
|
|
l := models.List{}
|
|
if err := c.Bind(&l); err != nil {
|
|
return err
|
|
}
|
|
|
|
// Validate.
|
|
if !strHasLen(l.Name, 1, stdInputMaxLen) {
|
|
return echo.NewHTTPError(http.StatusBadRequest, a.i18n.T("lists.invalidName"))
|
|
}
|
|
|
|
out, err := a.core.CreateList(l)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
return c.JSON(http.StatusOK, okResp{out})
|
|
}
|
|
|
|
// UpdateList handles list modification.
|
|
// It's permission checked by the listPerm middleware.
|
|
func (a *App) UpdateList(c echo.Context) error {
|
|
// Get the authenticated user.
|
|
user := auth.GetUser(c)
|
|
|
|
// Check if the user has access to the list.
|
|
id := getID(c)
|
|
if err := user.HasListPerm(auth.PermTypeManage, id); err != nil {
|
|
return err
|
|
}
|
|
|
|
// Incoming params.
|
|
var l models.List
|
|
if err := c.Bind(&l); err != nil {
|
|
return err
|
|
}
|
|
|
|
// Validate.
|
|
if !strHasLen(l.Name, 1, stdInputMaxLen) {
|
|
return echo.NewHTTPError(http.StatusBadRequest, a.i18n.T("lists.invalidName"))
|
|
}
|
|
|
|
// Update the list in the DB.
|
|
out, err := a.core.UpdateList(id, l)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
return c.JSON(http.StatusOK, okResp{out})
|
|
}
|
|
|
|
// DeleteLists handles list deletion, either a single one (ID in the URI), or a list.
|
|
// It's permission checked by the listPerm middleware.
|
|
func (a *App) DeleteLists(c echo.Context) error {
|
|
// Get the authenticated user.
|
|
user := auth.GetUser(c)
|
|
|
|
var (
|
|
id, _ = strconv.ParseInt(c.Param("id"), 10, 64)
|
|
ids []int
|
|
)
|
|
if id < 1 && len(ids) == 0 {
|
|
return echo.NewHTTPError(http.StatusBadRequest, a.i18n.T("globals.messages.invalidID"))
|
|
}
|
|
|
|
if id > 0 {
|
|
ids = append(ids, int(id))
|
|
}
|
|
|
|
// Check if the user has access to the list.
|
|
if err := user.HasListPerm(auth.PermTypeManage, ids...); err != nil {
|
|
return err
|
|
}
|
|
|
|
// Delete the lists from the DB.
|
|
if err := a.core.DeleteLists(ids); err != nil {
|
|
return err
|
|
}
|
|
|
|
return c.JSON(http.StatusOK, okResp{true})
|
|
}
|