2024-06-15 17:44:55 +08:00
|
|
|
package core
|
|
|
|
|
|
|
|
import (
|
2024-06-24 01:20:24 +08:00
|
|
|
"encoding/json"
|
2024-06-15 17:44:55 +08:00
|
|
|
"net/http"
|
|
|
|
|
|
|
|
"github.com/knadh/listmonk/models"
|
|
|
|
"github.com/labstack/echo/v4"
|
|
|
|
"github.com/lib/pq"
|
|
|
|
)
|
|
|
|
|
|
|
|
// GetRoles retrieves all roles.
|
|
|
|
func (c *Core) GetRoles() ([]models.Role, error) {
|
|
|
|
out := []models.Role{}
|
|
|
|
if err := c.q.GetRoles.Select(&out); err != nil {
|
|
|
|
return nil, echo.NewHTTPError(http.StatusInternalServerError,
|
|
|
|
c.i18n.Ts("globals.messages.errorFetching", "name", "{users.roles}", "error", pqErrMsg(err)))
|
|
|
|
}
|
|
|
|
|
2024-06-24 01:20:24 +08:00
|
|
|
// Unmarshall the nested list permissions, if any.
|
|
|
|
for n, r := range out {
|
|
|
|
if r.ListsRaw == nil {
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
|
|
|
|
if err := json.Unmarshal(r.ListsRaw, &out[n].Lists); err != nil {
|
|
|
|
c.log.Printf("error unmarshalling list permissions for role %d: %v", r.ID, err)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-06-15 17:44:55 +08:00
|
|
|
return out, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// CreateRole creates a new role.
|
|
|
|
func (c *Core) CreateRole(r models.Role) (models.Role, error) {
|
|
|
|
var out models.Role
|
|
|
|
|
|
|
|
if err := c.q.CreateRole.Get(&out, r.Name, pq.Array(r.Permissions)); err != nil {
|
|
|
|
return models.Role{}, echo.NewHTTPError(http.StatusInternalServerError,
|
|
|
|
c.i18n.Ts("globals.messages.errorCreating", "name", "{users.role}", "error", pqErrMsg(err)))
|
|
|
|
}
|
|
|
|
|
2024-06-24 01:20:24 +08:00
|
|
|
if err := c.UpsertListPermissions(out.ID, r.Lists); err != nil {
|
|
|
|
return models.Role{}, echo.NewHTTPError(http.StatusInternalServerError,
|
|
|
|
c.i18n.Ts("globals.messages.errorCreating", "name", "{users.role}", "error", pqErrMsg(err)))
|
|
|
|
}
|
|
|
|
|
2024-06-15 17:44:55 +08:00
|
|
|
return out, nil
|
|
|
|
}
|
|
|
|
|
2024-06-24 01:20:24 +08:00
|
|
|
// UpsertListPermissions upserts permission for a role.
|
|
|
|
func (c *Core) UpsertListPermissions(roleID int, lp []models.ListPermission) error {
|
|
|
|
var (
|
|
|
|
listIDs = make([]int, 0, len(lp))
|
|
|
|
listPerms = make([][]string, 0, len(lp))
|
|
|
|
)
|
|
|
|
for _, p := range lp {
|
|
|
|
if len(p.Permissions) == 0 {
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
|
|
|
|
listIDs = append(listIDs, p.ID)
|
|
|
|
|
|
|
|
// For the Postgres array unnesting query to work, all permissions arrays should
|
|
|
|
// have equal number of entries. Add "" in case there's only one of either list:get or list:manage
|
|
|
|
perms := make([]string, 2)
|
|
|
|
copy(perms[:], p.Permissions[:])
|
|
|
|
listPerms = append(listPerms, perms)
|
|
|
|
}
|
|
|
|
|
|
|
|
if _, err := c.q.UpsertListPermissions.Exec(roleID, pq.Array(listIDs), pq.Array(listPerms)); err != nil {
|
|
|
|
return echo.NewHTTPError(http.StatusInternalServerError,
|
|
|
|
c.i18n.Ts("globals.messages.errorCreating", "name", "{users.role}", "error", pqErrMsg(err)))
|
|
|
|
}
|
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// DeleteListPermission deletes a list permission entry from a role.
|
|
|
|
func (c *Core) DeleteListPermission(roleID, listID int) error {
|
|
|
|
if _, err := c.q.DeleteListPermission.Exec(roleID, listID); err != nil {
|
|
|
|
if pqErr, ok := err.(*pq.Error); ok && pqErr.Constraint == "users_role_id_fkey" {
|
|
|
|
return echo.NewHTTPError(http.StatusBadRequest, c.i18n.T("users.cantDeleteRole"))
|
|
|
|
}
|
|
|
|
return echo.NewHTTPError(http.StatusInternalServerError,
|
|
|
|
c.i18n.Ts("globals.messages.errorDeleting", "name", "{users.role}", "error", pqErrMsg(err)))
|
|
|
|
}
|
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2024-06-15 17:44:55 +08:00
|
|
|
// UpdateRole updates a given role.
|
|
|
|
func (c *Core) UpdateRole(id int, r models.Role) (models.Role, error) {
|
|
|
|
var out models.Role
|
|
|
|
|
|
|
|
if err := c.q.UpdateRole.Get(&out, id, r.Name, pq.Array(r.Permissions)); err != nil {
|
|
|
|
return models.Role{}, echo.NewHTTPError(http.StatusInternalServerError,
|
|
|
|
c.i18n.Ts("globals.messages.errorUpdating", "name", "{users.role}", "error", pqErrMsg(err)))
|
|
|
|
}
|
|
|
|
|
|
|
|
if out.ID == 0 {
|
|
|
|
return models.Role{}, echo.NewHTTPError(http.StatusBadRequest, c.i18n.Ts("globals.messages.notFound", "name", "{users.role}"))
|
|
|
|
}
|
|
|
|
|
2024-06-24 01:20:24 +08:00
|
|
|
if err := c.UpsertListPermissions(out.ID, r.Lists); err != nil {
|
|
|
|
return models.Role{}, echo.NewHTTPError(http.StatusInternalServerError,
|
|
|
|
c.i18n.Ts("globals.messages.errorCreating", "name", "{users.role}", "error", pqErrMsg(err)))
|
|
|
|
}
|
|
|
|
|
2024-06-15 17:44:55 +08:00
|
|
|
return out, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// DeleteRole deletes a given role.
|
|
|
|
func (c *Core) DeleteRole(id int) error {
|
|
|
|
if _, err := c.q.DeleteRole.Exec(id); err != nil {
|
2024-06-16 16:20:04 +08:00
|
|
|
if pqErr, ok := err.(*pq.Error); ok && pqErr.Constraint == "users_role_id_fkey" {
|
|
|
|
return echo.NewHTTPError(http.StatusBadRequest, c.i18n.T("users.cantDeleteRole"))
|
|
|
|
}
|
2024-06-15 17:44:55 +08:00
|
|
|
return echo.NewHTTPError(http.StatusInternalServerError,
|
|
|
|
c.i18n.Ts("globals.messages.errorDeleting", "name", "{users.role}", "error", pqErrMsg(err)))
|
|
|
|
}
|
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|