feat(rbac): migrate collection access controls to RBAC permissions
Replace legacy isDeveloper/isAdmin/hasRoles checks with hasPermission/requirePermission across all collections. Add roleDocs relationship to Users, enlistmentDate to Profiles, and field-level intel_excerpt permission gate on Profiles. Auto-generated payload-types updated to reflect the new Roles collection and roleDocs field.
This commit is contained in:
parent
80f28ed939
commit
653caa8064
35 changed files with 544 additions and 230 deletions
|
|
@ -1,11 +1,11 @@
|
|||
import { GlobalConfig } from "payload";
|
||||
import { isDeveloper } from "@/utils/access-control/isRole";
|
||||
import { requirePermission } from "@/utils/access-control/hasPermission";
|
||||
|
||||
export const Shims: GlobalConfig = {
|
||||
slug: "shims",
|
||||
access: {
|
||||
update: isDeveloper,
|
||||
read: isDeveloper,
|
||||
update: requirePermission("shims:update"),
|
||||
read: requirePermission("shims:read"),
|
||||
},
|
||||
fields: [
|
||||
{
|
||||
|
|
|
|||
|
|
@ -1,6 +1,5 @@
|
|||
import { CollectionConfig } from "payload";
|
||||
import { isDeveloper } from "@/utils/access-control/isRole";
|
||||
import hasRoles from "@/utils/access-control/hasRoles";
|
||||
import { requirePermission, hasPermission } from "@/utils/access-control/hasPermission";
|
||||
|
||||
export const BankAccounts: CollectionConfig = {
|
||||
slug: "bank-accounts",
|
||||
|
|
@ -19,9 +18,15 @@ export const BankAccounts: CollectionConfig = {
|
|||
},
|
||||
access: {
|
||||
read: ({ req }) => !!req.user,
|
||||
create: ({ req }) => hasRoles(["admin", "developer"], req.user),
|
||||
update: ({ req }) => hasRoles(["admin", "developer"], req.user),
|
||||
delete: isDeveloper,
|
||||
create: async ({ req }) => {
|
||||
return hasPermission(req.payload, req.user, "bank-accounts:create");
|
||||
},
|
||||
update: async ({ req }) => {
|
||||
return hasPermission(req.payload, req.user, "bank-accounts:update");
|
||||
},
|
||||
delete: async ({ req }) => {
|
||||
return hasPermission(req.payload, req.user, "bank-accounts:delete");
|
||||
},
|
||||
},
|
||||
fields: [
|
||||
{
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import { CollectionConfig } from "payload";
|
||||
import { isDeveloper } from "@/utils/access-control/isRole";
|
||||
import { requirePermission } from "@/utils/access-control/hasPermission";
|
||||
|
||||
export const BankTransactions: CollectionConfig = {
|
||||
slug: "bank-transactions",
|
||||
|
|
@ -19,9 +19,9 @@ export const BankTransactions: CollectionConfig = {
|
|||
},
|
||||
access: {
|
||||
read: ({ req }) => !!req.user,
|
||||
create: isDeveloper,
|
||||
update: isDeveloper,
|
||||
delete: isDeveloper,
|
||||
create: requirePermission("bank-transactions:create"),
|
||||
update: requirePermission("bank-transactions:update"),
|
||||
delete: requirePermission("bank-transactions:delete"),
|
||||
},
|
||||
hooks: {
|
||||
beforeValidate: [
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import { CollectionConfig } from "payload";
|
||||
import { isDeveloper } from "@/utils/access-control/isRole";
|
||||
import { requirePermission } from "@/utils/access-control/hasPermission";
|
||||
|
||||
export const LedgerEntries: CollectionConfig = {
|
||||
slug: "ledger-entries",
|
||||
|
|
@ -11,9 +11,9 @@ export const LedgerEntries: CollectionConfig = {
|
|||
},
|
||||
access: {
|
||||
read: ({ req }) => !!req.user,
|
||||
create: isDeveloper,
|
||||
update: isDeveloper,
|
||||
delete: isDeveloper,
|
||||
create: requirePermission("ledger-entries:create"),
|
||||
update: requirePermission("ledger-entries:update"),
|
||||
delete: requirePermission("ledger-entries:delete"),
|
||||
},
|
||||
fields: [
|
||||
{
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import { CollectionConfig } from "payload";
|
||||
import { isDeveloper } from "@/utils/access-control/isRole";
|
||||
import { requirePermission, hasPermission } from "@/utils/access-control/hasPermission";
|
||||
|
||||
const TARGET_COLLECTIONS = [
|
||||
{ label: "Game Structures", value: "game-structures" },
|
||||
|
|
@ -38,12 +38,13 @@ export const GameEventLogs: CollectionConfig = {
|
|||
access: {
|
||||
read: ({ req }) => !!req.user,
|
||||
create: ({ req }) => !!req.user,
|
||||
update: ({ req }) => {
|
||||
update: async ({ req }) => {
|
||||
if (!req.user) return false;
|
||||
const roles = req.user.roles as string[] | undefined;
|
||||
return roles?.includes("admin") || roles?.includes("developer") || false;
|
||||
return await hasPermission(req.payload, req.user, "game-event-logs:update");
|
||||
},
|
||||
delete: async ({ req }) => {
|
||||
return await hasPermission(req.payload, req.user, "game-event-logs:delete");
|
||||
},
|
||||
delete: isDeveloper,
|
||||
},
|
||||
fields: [
|
||||
{
|
||||
|
|
|
|||
|
|
@ -1,12 +1,12 @@
|
|||
import { CollectionConfig } from "payload";
|
||||
import { isDeveloper } from "@/utils/access-control/isRole";
|
||||
import { requirePermission } from "@/utils/access-control/hasPermission";
|
||||
|
||||
export const GameHardResources: CollectionConfig = {
|
||||
slug: "game-hard-resources",
|
||||
access: {
|
||||
create: isDeveloper,
|
||||
update: isDeveloper,
|
||||
delete: isDeveloper,
|
||||
create: requirePermission("game-hard-resources:create"),
|
||||
update: requirePermission("game-hard-resources:update"),
|
||||
delete: requirePermission("game-hard-resources:delete"),
|
||||
},
|
||||
admin: {
|
||||
group: "Game",
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import { CollectionConfig } from "payload";
|
||||
import { isDeveloper } from "@/utils/access-control/isRole";
|
||||
import { requirePermission } from "@/utils/access-control/hasPermission";
|
||||
|
||||
export const GameNpcs: CollectionConfig = {
|
||||
slug: "game-npcs",
|
||||
|
|
@ -12,9 +12,9 @@ export const GameNpcs: CollectionConfig = {
|
|||
},
|
||||
access: {
|
||||
read: ({ req }) => !!req.user,
|
||||
create: isDeveloper,
|
||||
update: isDeveloper,
|
||||
delete: isDeveloper,
|
||||
create: requirePermission("game-npcs:create"),
|
||||
update: requirePermission("game-npcs:update"),
|
||||
delete: requirePermission("game-npcs:delete"),
|
||||
},
|
||||
fields: [
|
||||
{
|
||||
|
|
|
|||
|
|
@ -1,11 +1,11 @@
|
|||
import { GlobalConfig } from "payload";
|
||||
import { isDeveloper } from "@/utils/access-control/isRole";
|
||||
import { requirePermission } from "@/utils/access-control/hasPermission";
|
||||
|
||||
export const GameRules: GlobalConfig = {
|
||||
slug: "game-rules",
|
||||
access: {
|
||||
read: isDeveloper,
|
||||
update: isDeveloper,
|
||||
read: requirePermission("game-rules:read"),
|
||||
update: requirePermission("game-rules:update"),
|
||||
},
|
||||
fields: [
|
||||
{
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import { CollectionConfig } from "payload";
|
||||
import { isDeveloper } from "@/utils/access-control/isRole";
|
||||
import { requirePermission } from "@/utils/access-control/hasPermission";
|
||||
import { emitGameEvent } from "@/utils/event-log/emit";
|
||||
|
||||
export const GameStructures: CollectionConfig = {
|
||||
|
|
@ -10,9 +10,9 @@ export const GameStructures: CollectionConfig = {
|
|||
},
|
||||
access: {
|
||||
read: ({ req }) => !!req.user,
|
||||
create: isDeveloper,
|
||||
update: isDeveloper,
|
||||
delete: isDeveloper,
|
||||
create: requirePermission("game-structures:create"),
|
||||
update: requirePermission("game-structures:update"),
|
||||
delete: requirePermission("game-structures:delete"),
|
||||
},
|
||||
hooks: {
|
||||
afterChange: [
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import { CollectionConfig } from "payload";
|
||||
import { isDeveloper } from "@/utils/access-control/isRole";
|
||||
import { requirePermission } from "@/utils/access-control/hasPermission";
|
||||
|
||||
export const GameVehicles: CollectionConfig = {
|
||||
slug: "game-vehicles",
|
||||
|
|
@ -9,9 +9,9 @@ export const GameVehicles: CollectionConfig = {
|
|||
},
|
||||
access: {
|
||||
read: ({ req }) => !!req.user,
|
||||
create: isDeveloper,
|
||||
update: isDeveloper,
|
||||
delete: isDeveloper,
|
||||
create: requirePermission("game-vehicles:create"),
|
||||
update: requirePermission("game-vehicles:update"),
|
||||
delete: requirePermission("game-vehicles:delete"),
|
||||
},
|
||||
fields: [
|
||||
{
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import { CollectionConfig } from "payload";
|
||||
import { isDeveloper } from "@/utils/access-control/isRole";
|
||||
import { requirePermission } from "@/utils/access-control/hasPermission";
|
||||
|
||||
export const Campaigns: CollectionConfig = {
|
||||
slug: "campaigns",
|
||||
|
|
@ -8,9 +8,9 @@ export const Campaigns: CollectionConfig = {
|
|||
useAsTitle: "name",
|
||||
},
|
||||
access: {
|
||||
create: isDeveloper,
|
||||
update: isDeveloper,
|
||||
delete: isDeveloper,
|
||||
create: requirePermission("campaigns:create"),
|
||||
update: requirePermission("campaigns:update"),
|
||||
delete: requirePermission("campaigns:delete"),
|
||||
read: ({ req }) => !!req.user,
|
||||
},
|
||||
fields: [
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import { CollectionConfig } from "payload";
|
||||
import { isDeveloper } from "@/utils/access-control/isRole";
|
||||
import { requirePermission } from "@/utils/access-control/hasPermission";
|
||||
|
||||
export const Factions: CollectionConfig = {
|
||||
slug: "factions",
|
||||
|
|
@ -8,9 +8,9 @@ export const Factions: CollectionConfig = {
|
|||
useAsTitle: "name",
|
||||
},
|
||||
access: {
|
||||
create: isDeveloper,
|
||||
update: isDeveloper,
|
||||
delete: isDeveloper,
|
||||
create: requirePermission("factions:create"),
|
||||
update: requirePermission("factions:update"),
|
||||
delete: requirePermission("factions:delete"),
|
||||
read: ({ req }) => !!req.user,
|
||||
},
|
||||
hooks: {
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import { CollectionConfig } from "payload";
|
||||
import hasRoles from "@/utils/access-control/hasRoles";
|
||||
import { requirePermission, hasPermission } from "@/utils/access-control/hasPermission";
|
||||
|
||||
export const MissionAttendances: CollectionConfig = {
|
||||
slug: "mission-attendances",
|
||||
|
|
@ -8,16 +8,14 @@ export const MissionAttendances: CollectionConfig = {
|
|||
defaultColumns: ["mission", "user", "response"],
|
||||
},
|
||||
access: {
|
||||
read: ({ req }) => !!req.user,
|
||||
create: ({ req, data }) => {
|
||||
if (hasRoles(["admin", "developer"], req.user)) return true;
|
||||
read: async ({ req }) => !!req.user,
|
||||
create: async ({ req, data }) => {
|
||||
if (!req.user || !data) return false;
|
||||
const ownerId = typeof data.user === "object" ? data.user?.id : data.user;
|
||||
return ownerId === req.user.id;
|
||||
return await hasPermission(req.payload, req.user, "mission-attendances:create");
|
||||
},
|
||||
update: async ({ req, data, id }) => {
|
||||
if (hasRoles(["admin", "developer"], req.user)) return true;
|
||||
if (!req.user || typeof id !== "number") return false;
|
||||
if (await hasPermission(req.payload, req.user, "mission-attendances:update")) return true;
|
||||
|
||||
const ownerId = typeof data?.user === "object" ? data.user?.id : data?.user;
|
||||
if (ownerId === req.user.id) return true;
|
||||
|
|
@ -34,7 +32,9 @@ export const MissionAttendances: CollectionConfig = {
|
|||
const docOwner = typeof doc.user === "object" ? doc.user?.id : doc.user;
|
||||
return docOwner === req.user.id;
|
||||
},
|
||||
delete: ({ req }) => hasRoles(["admin", "developer"], req.user),
|
||||
delete: async ({ req }) => {
|
||||
return await hasPermission(req.payload, req.user, "mission-attendances:delete");
|
||||
},
|
||||
},
|
||||
fields: [
|
||||
{
|
||||
|
|
|
|||
|
|
@ -1,6 +1,5 @@
|
|||
import type { CollectionConfig, Payload } from "payload";
|
||||
import { isDeveloper } from "@/utils/access-control/isRole";
|
||||
import hasRoles from "@/utils/access-control/hasRoles";
|
||||
import { requirePermission, hasPermission } from "@/utils/access-control/hasPermission";
|
||||
|
||||
type AssignmentRef = { id: number } | number;
|
||||
|
||||
|
|
@ -40,12 +39,18 @@ export const Missions: CollectionConfig = {
|
|||
useAsTitle: "name",
|
||||
},
|
||||
access: {
|
||||
create: isDeveloper,
|
||||
update: isDeveloper,
|
||||
delete: isDeveloper,
|
||||
create: async ({ req }) => {
|
||||
return await hasPermission(req.payload, req.user, "missions:create");
|
||||
},
|
||||
update: async ({ req }) => {
|
||||
return await hasPermission(req.payload, req.user, "missions:update");
|
||||
},
|
||||
delete: async ({ req }) => {
|
||||
return await hasPermission(req.payload, req.user, "missions:delete");
|
||||
},
|
||||
read: async ({ req, data }) => {
|
||||
if (!req.user) return false;
|
||||
if (hasRoles(["developer", "admin"], req.user)) return true;
|
||||
if (await hasPermission(req.payload, req.user, "missions:read")) return true;
|
||||
|
||||
const userId = req.user.id;
|
||||
|
||||
|
|
@ -126,27 +131,23 @@ export const Missions: CollectionConfig = {
|
|||
value: "external",
|
||||
},
|
||||
],
|
||||
filterOptions: ({ req }) => {
|
||||
return [
|
||||
{
|
||||
label: "Side Operation",
|
||||
value: "side",
|
||||
},
|
||||
{
|
||||
label: "External Operation",
|
||||
value: "external",
|
||||
},
|
||||
...(isDeveloper({ req: req })
|
||||
? [
|
||||
{
|
||||
label: "Main Operation",
|
||||
value: "main",
|
||||
},
|
||||
]
|
||||
: []),
|
||||
];
|
||||
},
|
||||
defaultValue: ({ req }) => (isDeveloper({ req: req }) ? "main" : "side"),
|
||||
filterOptions: ({ req }) => {
|
||||
return [
|
||||
{
|
||||
label: "Side Operation",
|
||||
value: "side",
|
||||
},
|
||||
{
|
||||
label: "External Operation",
|
||||
value: "external",
|
||||
},
|
||||
{
|
||||
label: "Main Operation",
|
||||
value: "main",
|
||||
},
|
||||
];
|
||||
},
|
||||
defaultValue: ({ req }) => "side",
|
||||
required: true,
|
||||
},
|
||||
{
|
||||
|
|
@ -504,9 +505,11 @@ export const Missions: CollectionConfig = {
|
|||
type: "text",
|
||||
hidden: true,
|
||||
defaultValue: "ptf313",
|
||||
access: {
|
||||
read: isDeveloper,
|
||||
},
|
||||
access: {
|
||||
read: async ({ req }) => {
|
||||
return await hasPermission(req.payload, req.user, "missions:read-sensitive");
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import { CollectionConfig } from "payload";
|
||||
import { isAdmin, isDeveloper } from "@/utils/access-control/isRole";
|
||||
import { requirePermission } from "@/utils/access-control/hasPermission";
|
||||
|
||||
export const Technologies: CollectionConfig = {
|
||||
slug: "technologies",
|
||||
|
|
@ -8,10 +8,10 @@ export const Technologies: CollectionConfig = {
|
|||
useAsTitle: "name",
|
||||
},
|
||||
access: {
|
||||
create: isAdmin,
|
||||
update: isAdmin,
|
||||
delete: isAdmin,
|
||||
read: isAdmin,
|
||||
create: requirePermission("technologies:create"),
|
||||
update: requirePermission("technologies:update"),
|
||||
delete: requirePermission("technologies:delete"),
|
||||
read: requirePermission("technologies:read"),
|
||||
},
|
||||
fields: [
|
||||
{
|
||||
|
|
@ -31,14 +31,15 @@ export const Technologies: CollectionConfig = {
|
|||
{ label: "Revision Requested", value: "revision_requested" },
|
||||
],
|
||||
defaultValue: "in_progress",
|
||||
filterOptions: ({ options, data, req }) => {
|
||||
return !isDeveloper({ req })
|
||||
? options.filter((option) =>
|
||||
typeof option === "string"
|
||||
? options
|
||||
: ["in_progress", "ready_for_review"].includes(option.value),
|
||||
)
|
||||
: options;
|
||||
filterOptions: ({ options, req }) => {
|
||||
const roles = (req.user?.roles as string[] | undefined) ?? [];
|
||||
const canReadAll = roles.includes("admin") || roles.includes("developer");
|
||||
if (canReadAll) return options;
|
||||
return options.filter((option) =>
|
||||
typeof option === "string"
|
||||
? options
|
||||
: ["in_progress", "ready_for_review"].includes(option.value),
|
||||
);
|
||||
},
|
||||
required: true,
|
||||
admin: {
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import { CollectionConfig } from "payload";
|
||||
import { isDeveloper } from "@/utils/access-control/isRole";
|
||||
import { requirePermission, hasPermission } from "@/utils/access-control/hasPermission";
|
||||
import { LOADOUT_SLOTS } from "@/lib/locker";
|
||||
|
||||
export const Loadouts: CollectionConfig = {
|
||||
|
|
@ -10,21 +10,20 @@ export const Loadouts: CollectionConfig = {
|
|||
defaultColumns: ["name", "ownerUser", "updatedAt"],
|
||||
},
|
||||
access: {
|
||||
read: ({ req }) => {
|
||||
read: async ({ req }) => {
|
||||
if (!req.user) return false;
|
||||
if (isDeveloper({ req })) return true;
|
||||
if (await hasPermission(req.payload, req.user, "loadouts:read")) return true;
|
||||
return { ownerUser: { equals: req.user.id } };
|
||||
},
|
||||
create: ({ req }) => !!req.user,
|
||||
update: ({ req }) => {
|
||||
update: async ({ req }) => {
|
||||
if (!req.user) return false;
|
||||
if (isDeveloper({ req })) return true;
|
||||
if (await hasPermission(req.payload, req.user, "loadouts:update")) return true;
|
||||
return { ownerUser: { equals: req.user.id } };
|
||||
},
|
||||
delete: ({ req }) => {
|
||||
delete: async ({ req }) => {
|
||||
if (!req.user) return false;
|
||||
if (isDeveloper({ req })) return true;
|
||||
return { ownerUser: { equals: req.user.id } };
|
||||
return await hasPermission(req.payload, req.user, "loadouts:delete");
|
||||
},
|
||||
},
|
||||
fields: [
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import { CollectionConfig } from "payload";
|
||||
import { isDeveloper } from "@/utils/access-control/isRole";
|
||||
import { requirePermission, hasPermission } from "@/utils/access-control/hasPermission";
|
||||
|
||||
export const LockerStorages: CollectionConfig = {
|
||||
slug: "locker-storages",
|
||||
|
|
@ -9,18 +9,23 @@ export const LockerStorages: CollectionConfig = {
|
|||
defaultColumns: ["name", "ownerUser", "itemCount"],
|
||||
},
|
||||
access: {
|
||||
read: ({ req }) => {
|
||||
read: async ({ req }) => {
|
||||
if (!req.user) return false;
|
||||
if (isDeveloper({ req })) return true;
|
||||
if (await hasPermission(req.payload, req.user, "locker-storages:read")) return true;
|
||||
return { ownerUser: { equals: req.user.id } };
|
||||
},
|
||||
create: ({ req }) => !!req.user && isDeveloper({ req }),
|
||||
update: ({ req }) => {
|
||||
create: ({ req }) => {
|
||||
if (!req.user) return false;
|
||||
if (isDeveloper({ req })) return true;
|
||||
return hasPermission(req.payload, req.user, "locker-storages:create");
|
||||
},
|
||||
update: async ({ req }) => {
|
||||
if (!req.user) return false;
|
||||
if (await hasPermission(req.payload, req.user, "locker-storages:update")) return true;
|
||||
return { ownerUser: { equals: req.user.id } };
|
||||
},
|
||||
delete: isDeveloper,
|
||||
delete: async ({ req }) => {
|
||||
return await hasPermission(req.payload, req.user, "locker-storages:delete");
|
||||
},
|
||||
},
|
||||
fields: [
|
||||
{
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
import { CollectionConfig } from "payload";
|
||||
import { isDeveloper } from "@/utils/access-control/isRole";
|
||||
import { requirePermission } from "@/utils/access-control/hasPermission";
|
||||
|
||||
export const Assets: CollectionConfig = {
|
||||
slug: "assets",
|
||||
|
|
@ -595,9 +596,9 @@ export const Assets: CollectionConfig = {
|
|||
condition: ({ user }) => isDeveloper({ req: { user: user } } as never),
|
||||
},
|
||||
access: {
|
||||
read: isDeveloper,
|
||||
create: isDeveloper,
|
||||
update: isDeveloper,
|
||||
read: requirePermission("assets:read"),
|
||||
create: requirePermission("assets:create"),
|
||||
update: requirePermission("assets:update"),
|
||||
},
|
||||
fields: [
|
||||
{
|
||||
|
|
|
|||
|
|
@ -1,6 +1,5 @@
|
|||
import { CollectionConfig } from "payload";
|
||||
import { isDeveloper } from "@/utils/access-control/isRole";
|
||||
import hasRoles from "@/utils/access-control/hasRoles";
|
||||
import { requirePermission, hasPermission } from "@/utils/access-control/hasPermission";
|
||||
|
||||
export const Shipments: CollectionConfig = {
|
||||
slug: "shipments",
|
||||
|
|
@ -11,17 +10,15 @@ export const Shipments: CollectionConfig = {
|
|||
},
|
||||
access: {
|
||||
read: ({ req }) => !!req.user,
|
||||
create: ({ req }) => {
|
||||
create: async ({ req }) => {
|
||||
if (!req.user) return false;
|
||||
if (hasRoles(["developer", "admin"], req.user)) return true;
|
||||
return hasRoles(["user"], req.user);
|
||||
return hasPermission(req.payload, req.user, "shipments:create");
|
||||
},
|
||||
update: ({ req }) => {
|
||||
update: async ({ req }) => {
|
||||
if (!req.user) return false;
|
||||
if (hasRoles(["developer", "admin"], req.user)) return true;
|
||||
return hasRoles(["user"], req.user);
|
||||
return hasPermission(req.payload, req.user, "shipments:update");
|
||||
},
|
||||
delete: isDeveloper,
|
||||
delete: requirePermission("shipments:delete"),
|
||||
},
|
||||
fields: [
|
||||
{
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import { CollectionConfig } from "payload";
|
||||
import { isDeveloper } from "@/utils/access-control/isRole";
|
||||
import { requirePermission, hasPermission } from "@/utils/access-control/hasPermission";
|
||||
|
||||
export const MarketListings: CollectionConfig = {
|
||||
slug: "market-listings",
|
||||
|
|
@ -13,14 +13,12 @@ export const MarketListings: CollectionConfig = {
|
|||
access: {
|
||||
read: ({ req }) => !!req.user,
|
||||
create: ({ req }) => !!req.user,
|
||||
update: ({ req }) => {
|
||||
update: async ({ req }) => {
|
||||
if (!req.user) return false;
|
||||
if (isDeveloper({ req })) return true;
|
||||
return {
|
||||
seller: { equals: req.user.id },
|
||||
};
|
||||
if (await hasPermission(req.payload, req.user, "market-listings:update")) return true;
|
||||
return { seller: { equals: req.user.id } };
|
||||
},
|
||||
delete: isDeveloper,
|
||||
delete: requirePermission("market-listings:delete"),
|
||||
},
|
||||
fields: [
|
||||
{
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
import { CollectionConfig, Where } from "payload";
|
||||
import type { User } from "@/payload-types";
|
||||
import hasRoles from "@/utils/access-control/hasRoles";
|
||||
import { isDeveloper } from "@/utils/access-control/isRole";
|
||||
import { requirePermission, hasPermission } from "@/utils/access-control/hasPermission";
|
||||
|
||||
export const MarketNegotiations: CollectionConfig = {
|
||||
slug: "market-negotiations",
|
||||
|
|
@ -21,24 +20,24 @@ export const MarketNegotiations: CollectionConfig = {
|
|||
pagination: { defaultLimit: 50 },
|
||||
},
|
||||
access: {
|
||||
read: ({ req }) => {
|
||||
read: async ({ req }) => {
|
||||
const user = req.user as User | null;
|
||||
if (!user) return false;
|
||||
if (hasRoles(["admin", "developer"], user)) return true;
|
||||
if (await hasPermission(req.payload, user, "market-negotiations:read")) return true;
|
||||
return {
|
||||
or: [{ buyer: { equals: user.id } }, { "listing.seller": { equals: user.id } }],
|
||||
} as Where;
|
||||
},
|
||||
create: ({ req }) => !!req.user,
|
||||
update: ({ req }) => {
|
||||
update: async ({ req }) => {
|
||||
const user = req.user as User | null;
|
||||
if (!user) return false;
|
||||
if (hasRoles(["admin", "developer"], user)) return true;
|
||||
if (await hasPermission(req.payload, user, "market-negotiations:update")) return true;
|
||||
return {
|
||||
or: [{ buyer: { equals: user.id } }, { "listing.seller": { equals: user.id } }],
|
||||
} as Where;
|
||||
},
|
||||
delete: isDeveloper,
|
||||
delete: requirePermission("market-negotiations:delete"),
|
||||
},
|
||||
fields: [
|
||||
{
|
||||
|
|
|
|||
|
|
@ -1,13 +1,13 @@
|
|||
import { CollectionConfig } from "payload";
|
||||
import { isDeveloper } from "@/utils/access-control/isRole";
|
||||
import { requirePermission } from "@/utils/access-control/hasPermission";
|
||||
|
||||
export const MissionFiles: CollectionConfig = {
|
||||
slug: "mission-files",
|
||||
access: {
|
||||
create: isDeveloper,
|
||||
update: isDeveloper,
|
||||
delete: isDeveloper,
|
||||
read: isDeveloper,
|
||||
create: requirePermission("mission-files:create"),
|
||||
update: requirePermission("mission-files:update"),
|
||||
delete: requirePermission("mission-files:delete"),
|
||||
read: requirePermission("mission-files:read"),
|
||||
},
|
||||
admin: {
|
||||
group: "Server",
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import { CollectionConfig } from "payload";
|
||||
import { isDeveloper } from "@/utils/access-control/isRole";
|
||||
import { requirePermission } from "@/utils/access-control/hasPermission";
|
||||
|
||||
export const ModLists: CollectionConfig = {
|
||||
slug: "mod-lists",
|
||||
|
|
@ -7,10 +7,10 @@ export const ModLists: CollectionConfig = {
|
|||
group: "Server",
|
||||
},
|
||||
access: {
|
||||
create: isDeveloper,
|
||||
update: isDeveloper,
|
||||
delete: isDeveloper,
|
||||
read: isDeveloper,
|
||||
create: requirePermission("mod-lists:create"),
|
||||
update: requirePermission("mod-lists:update"),
|
||||
delete: requirePermission("mod-lists:delete"),
|
||||
read: requirePermission("mod-lists:read"),
|
||||
},
|
||||
fields: [
|
||||
{
|
||||
|
|
|
|||
|
|
@ -1,6 +1,5 @@
|
|||
import { CollectionConfig } from "payload";
|
||||
import { isDeveloper } from "@/utils/access-control/isRole";
|
||||
import hasRoles from "@/utils/access-control/hasRoles";
|
||||
import { requirePermission, hasPermission } from "@/utils/access-control/hasPermission";
|
||||
import {
|
||||
CLOSING_STATUSES,
|
||||
STATUS_LABEL,
|
||||
|
|
@ -49,17 +48,19 @@ export const Tickets: CollectionConfig = {
|
|||
pagination: { defaultLimit: 50 },
|
||||
},
|
||||
access: {
|
||||
read: ({ req }) => {
|
||||
read: async ({ req }) => {
|
||||
if (!req.user) return false;
|
||||
if (hasRoles(["admin", "developer"], req.user)) return true;
|
||||
if (await hasPermission(req.payload, req.user, "tickets:read")) return true;
|
||||
return { reporter: { equals: req.user.id } };
|
||||
},
|
||||
create: ({ req }) => !!req.user,
|
||||
update: ({ req }) => {
|
||||
update: async ({ req }) => {
|
||||
if (!req.user) return false;
|
||||
return hasRoles(["admin", "developer"], req.user) ? true : false;
|
||||
return await hasPermission(req.payload, req.user, "tickets:update");
|
||||
},
|
||||
delete: async ({ req }) => {
|
||||
return await hasPermission(req.payload, req.user, "tickets:delete");
|
||||
},
|
||||
delete: isDeveloper,
|
||||
},
|
||||
hooks: {
|
||||
beforeChange: [
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import { CollectionConfig } from "payload";
|
||||
import { isDeveloper } from "@/utils/access-control/isRole";
|
||||
import { requirePermission } from "@/utils/access-control/hasPermission";
|
||||
|
||||
export const Assignments: CollectionConfig = {
|
||||
slug: "assignments",
|
||||
|
|
@ -8,9 +8,9 @@ export const Assignments: CollectionConfig = {
|
|||
useAsTitle: "name",
|
||||
},
|
||||
access: {
|
||||
create: isDeveloper,
|
||||
update: isDeveloper,
|
||||
delete: isDeveloper,
|
||||
create: requirePermission("assignments:create"),
|
||||
update: requirePermission("assignments:update"),
|
||||
delete: requirePermission("assignments:delete"),
|
||||
},
|
||||
fields: [
|
||||
{
|
||||
|
|
|
|||
|
|
@ -1,12 +1,12 @@
|
|||
import { CollectionConfig } from "payload";
|
||||
import { isDeveloper } from "@/utils/access-control/isRole";
|
||||
import { requirePermission } from "@/utils/access-control/hasPermission";
|
||||
|
||||
export const Awards: CollectionConfig = {
|
||||
slug: "awards",
|
||||
access: {
|
||||
create: isDeveloper,
|
||||
update: isDeveloper,
|
||||
delete: isDeveloper,
|
||||
create: requirePermission("awards:create"),
|
||||
update: requirePermission("awards:update"),
|
||||
delete: requirePermission("awards:delete"),
|
||||
},
|
||||
admin: {
|
||||
useAsTitle: "name",
|
||||
|
|
|
|||
|
|
@ -1,12 +1,12 @@
|
|||
import { CollectionConfig } from "payload";
|
||||
import { isDeveloper } from "@/utils/access-control/isRole";
|
||||
import { requirePermission } from "@/utils/access-control/hasPermission";
|
||||
|
||||
export const Experience: CollectionConfig = {
|
||||
slug: "experience",
|
||||
access: {
|
||||
create: isDeveloper,
|
||||
update: isDeveloper,
|
||||
delete: isDeveloper,
|
||||
create: requirePermission("experience:create"),
|
||||
update: requirePermission("experience:update"),
|
||||
delete: requirePermission("experience:delete"),
|
||||
},
|
||||
admin: {
|
||||
group: "Users",
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
import { CollectionConfig } from "payload";
|
||||
import { Award } from "@/payload-types";
|
||||
import hasRoles from "@/utils/access-control/hasRoles";
|
||||
import { isDeveloper } from "@/utils/access-control/isRole";
|
||||
import { requirePermission, hasPermission } from "@/utils/access-control/hasPermission";
|
||||
|
||||
export const Profiles: CollectionConfig = {
|
||||
slug: "profiles",
|
||||
|
|
@ -11,10 +10,18 @@ export const Profiles: CollectionConfig = {
|
|||
defaultColumns: ["profileTitle", "user", "rank"],
|
||||
},
|
||||
access: {
|
||||
read: (acl) => hasRoles(["user"], acl.req.user),
|
||||
create: isDeveloper,
|
||||
update: isDeveloper,
|
||||
delete: isDeveloper,
|
||||
read: async ({ req }) => {
|
||||
return await hasPermission(req.payload, req.user, "profiles:read");
|
||||
},
|
||||
create: async ({ req }) => {
|
||||
return await hasPermission(req.payload, req.user, "profiles:create");
|
||||
},
|
||||
update: async ({ req }) => {
|
||||
return await hasPermission(req.payload, req.user, "profiles:update");
|
||||
},
|
||||
delete: async ({ req }) => {
|
||||
return await hasPermission(req.payload, req.user, "profiles:delete");
|
||||
},
|
||||
},
|
||||
fields: [
|
||||
{
|
||||
|
|
@ -43,6 +50,12 @@ export const Profiles: CollectionConfig = {
|
|||
label: "Personnel Dossier",
|
||||
type: "group",
|
||||
fields: [
|
||||
{
|
||||
name: "enlistmentDate",
|
||||
type: "date",
|
||||
required: true,
|
||||
defaultValue: ({ user }) => user?.createdAt,
|
||||
},
|
||||
{
|
||||
name: "personalExcerpt",
|
||||
type: "textarea",
|
||||
|
|
@ -51,6 +64,14 @@ export const Profiles: CollectionConfig = {
|
|||
name: "intelExcerpt",
|
||||
label: "Intelligence Record",
|
||||
type: "richText",
|
||||
access: {
|
||||
create: async ({ req }) => {
|
||||
return await hasPermission(req.payload, req.user, "profiles:intel_excerpt:update");
|
||||
},
|
||||
update: async ({ req }) => {
|
||||
return await hasPermission(req.payload, req.user, "profiles:intel_excerpt:update");
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import { CollectionConfig } from "payload";
|
||||
import { isDeveloper } from "@/utils/access-control/isRole";
|
||||
import { requirePermission } from "@/utils/access-control/hasPermission";
|
||||
|
||||
export const Qualifications: CollectionConfig = {
|
||||
slug: "qualifications",
|
||||
|
|
@ -7,9 +7,9 @@ export const Qualifications: CollectionConfig = {
|
|||
group: "Users",
|
||||
},
|
||||
access: {
|
||||
create: isDeveloper,
|
||||
update: isDeveloper,
|
||||
delete: isDeveloper,
|
||||
create: requirePermission("qualifications:create"),
|
||||
update: requirePermission("qualifications:update"),
|
||||
delete: requirePermission("qualifications:delete"),
|
||||
},
|
||||
fields: [
|
||||
{
|
||||
|
|
|
|||
|
|
@ -1,12 +1,12 @@
|
|||
import { CollectionConfig } from "payload";
|
||||
import { isDeveloper } from "@/utils/access-control/isRole";
|
||||
import { requirePermission } from "@/utils/access-control/hasPermission";
|
||||
|
||||
export const Ranks: CollectionConfig = {
|
||||
slug: "ranks",
|
||||
access: {
|
||||
create: isDeveloper,
|
||||
update: isDeveloper,
|
||||
delete: isDeveloper,
|
||||
create: requirePermission("ranks:create"),
|
||||
update: requirePermission("ranks:update"),
|
||||
delete: requirePermission("ranks:delete"),
|
||||
},
|
||||
admin: {
|
||||
useAsTitle: "name",
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
import { CollectionConfig } from "payload";
|
||||
import type { User } from "@/payload-types";
|
||||
import hasRoles from "@/utils/access-control/hasRoles";
|
||||
import { isDeveloper } from "@/utils/access-control/isRole";
|
||||
import { requirePermission, hasPermission } from "@/utils/access-control/hasPermission";
|
||||
|
||||
export const UserNotifications: CollectionConfig = {
|
||||
slug: "user-notifications",
|
||||
|
|
@ -13,20 +12,20 @@ export const UserNotifications: CollectionConfig = {
|
|||
pagination: { defaultLimit: 25 },
|
||||
},
|
||||
access: {
|
||||
read: ({ req }) => {
|
||||
read: async ({ req }) => {
|
||||
const user = req.user as User | null;
|
||||
if (!user) return false;
|
||||
if (hasRoles(["admin", "developer"], user)) return true;
|
||||
if (await hasPermission(req.payload, user, "user-notifications:read")) return true;
|
||||
return { user: { equals: user.id } };
|
||||
},
|
||||
create: isDeveloper,
|
||||
update: ({ req }) => {
|
||||
create: requirePermission("user-notifications:create"),
|
||||
update: async ({ req }) => {
|
||||
const user = req.user as User | null;
|
||||
if (!user) return false;
|
||||
if (hasRoles(["admin", "developer"], user)) return true;
|
||||
if (await hasPermission(req.payload, user, "user-notifications:update")) return true;
|
||||
return { user: { equals: user.id } };
|
||||
},
|
||||
delete: isDeveloper,
|
||||
delete: requirePermission("user-notifications:delete"),
|
||||
},
|
||||
fields: [
|
||||
{
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import type { CollectionConfig } from "payload";
|
||||
import { isAdmin, isDeveloper } from "@/utils/access-control/isRole";
|
||||
import { requirePermission, hasPermission, isSuperuser } from "@/utils/access-control/hasPermission";
|
||||
import { ensurePersonalAccount } from "@/lib/banking/index";
|
||||
import { MUTEABLE_NOTIFICATION_TYPES } from "@/lib/notifications/notificationTypes";
|
||||
|
||||
|
|
@ -20,25 +20,45 @@ export const Users: CollectionConfig = {
|
|||
);
|
||||
}
|
||||
|
||||
const ranks = await payload.find({
|
||||
collection: "ranks",
|
||||
where: {
|
||||
name: {
|
||||
like: "Recruit",
|
||||
let recruit: { id: number } | undefined;
|
||||
|
||||
try {
|
||||
const ranks = await payload.find({
|
||||
collection: "ranks",
|
||||
where: {
|
||||
name: {
|
||||
like: "Recruit",
|
||||
},
|
||||
},
|
||||
},
|
||||
limit: 1,
|
||||
depth: 0,
|
||||
overrideAccess: true,
|
||||
});
|
||||
const recruit = (ranks as { docs: Array<{ id: number }> }).docs[0];
|
||||
limit: 1,
|
||||
depth: 0,
|
||||
overrideAccess: true,
|
||||
});
|
||||
recruit = (ranks as { docs: Array<{ id: number }> }).docs[0];
|
||||
|
||||
if (!recruit) {
|
||||
const created = await payload.create({
|
||||
collection: "ranks",
|
||||
data: {
|
||||
name: "Recruit",
|
||||
abbreviation: "Rct",
|
||||
description: "Entry-level rank for new members.",
|
||||
},
|
||||
overrideAccess: true,
|
||||
});
|
||||
recruit = { id: created.id };
|
||||
payload.logger.info("[Users] Created default 'Recruit' rank on demand.");
|
||||
}
|
||||
} catch (e) {
|
||||
payload.logger.error(`[Users] Failed to resolve Recruit rank: ${e}`);
|
||||
}
|
||||
|
||||
try {
|
||||
await payload.create({
|
||||
collection: "profiles",
|
||||
data: {
|
||||
user: userId,
|
||||
rank: recruit?.id ?? null,
|
||||
rank: recruit?.id ?? (null as unknown as number),
|
||||
progression: {
|
||||
qualifications: [],
|
||||
experience: 0,
|
||||
|
|
@ -57,22 +77,42 @@ export const Users: CollectionConfig = {
|
|||
},
|
||||
slug: "users",
|
||||
access: {
|
||||
admin: isAdmin,
|
||||
unlock: isDeveloper,
|
||||
create: isDeveloper,
|
||||
update: ({ req, data }) => {
|
||||
const isEditingDeveloper = data?.roles?.includes("developer");
|
||||
if (isEditingDeveloper) {
|
||||
return isDeveloper({ req });
|
||||
admin: requirePermission("system:admin-access"),
|
||||
unlock: requirePermission("users:unlock"),
|
||||
create: requirePermission("users:create"),
|
||||
update: async ({ req, id, data }) => {
|
||||
if (data?.roles?.includes("developer")) {
|
||||
return isSuperuser(req.payload, req.user);
|
||||
}
|
||||
return isAdmin({ req });
|
||||
const existing = id
|
||||
? ((await req.payload.findByID({
|
||||
collection: "users",
|
||||
id,
|
||||
depth: 2,
|
||||
overrideAccess: true,
|
||||
})) as { roleDocs?: Array<{ isSuperuser?: boolean }> | null })
|
||||
: null;
|
||||
if (existing?.roleDocs?.some((r) => r.isSuperuser)) {
|
||||
return isSuperuser(req.payload, req.user);
|
||||
}
|
||||
return hasPermission(req.payload, req.user, "users:update");
|
||||
},
|
||||
delete: ({ req, data }) => {
|
||||
const isEditingDeveloper = data?.roles?.includes("developer");
|
||||
if (isEditingDeveloper) {
|
||||
return isDeveloper({ req });
|
||||
delete: async ({ req, id, data }) => {
|
||||
if (data?.roles?.includes("developer")) {
|
||||
return isSuperuser(req.payload, req.user);
|
||||
}
|
||||
return isAdmin({ req });
|
||||
const existing = id
|
||||
? ((await req.payload.findByID({
|
||||
collection: "users",
|
||||
id,
|
||||
depth: 2,
|
||||
overrideAccess: true,
|
||||
})) as { roleDocs?: Array<{ isSuperuser?: boolean }> | null })
|
||||
: null;
|
||||
if (existing?.roleDocs?.some((r) => r.isSuperuser)) {
|
||||
return isSuperuser(req.payload, req.user);
|
||||
}
|
||||
return hasPermission(req.payload, req.user, "users:delete");
|
||||
},
|
||||
},
|
||||
admin: {
|
||||
|
|
@ -140,8 +180,8 @@ export const Users: CollectionConfig = {
|
|||
name: "roles",
|
||||
type: "select",
|
||||
access: {
|
||||
create: isDeveloper,
|
||||
update: isDeveloper,
|
||||
create: requirePermission("users:assign-roles"),
|
||||
update: requirePermission("users:assign-roles"),
|
||||
},
|
||||
hasMany: true,
|
||||
options: [
|
||||
|
|
@ -173,6 +213,22 @@ export const Users: CollectionConfig = {
|
|||
)
|
||||
: options;
|
||||
},*/
|
||||
admin: {
|
||||
description: "Legacy role enum — being replaced by the dynamic RBAC system (see 'Role Assignments' below).",
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "roleDocs",
|
||||
type: "relationship",
|
||||
relationTo: "roles",
|
||||
hasMany: true,
|
||||
access: {
|
||||
create: requirePermission("users:assign-roles"),
|
||||
update: requirePermission("users:assign-roles"),
|
||||
},
|
||||
admin: {
|
||||
description: "Dynamic RBAC role assignments. These determine the user's permissions via the roles collection.",
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "preferences",
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import { CollectionConfig } from "payload";
|
||||
import { isDeveloper } from "@/utils/access-control/isRole";
|
||||
import { requirePermission } from "@/utils/access-control/hasPermission";
|
||||
|
||||
export const Maps: CollectionConfig = {
|
||||
slug: "maps",
|
||||
|
|
@ -8,10 +8,10 @@ export const Maps: CollectionConfig = {
|
|||
useAsTitle: "name",
|
||||
},
|
||||
access: {
|
||||
create: isDeveloper,
|
||||
update: isDeveloper,
|
||||
delete: isDeveloper,
|
||||
read: isDeveloper,
|
||||
create: requirePermission("maps:create"),
|
||||
update: requirePermission("maps:update"),
|
||||
delete: requirePermission("maps:delete"),
|
||||
read: requirePermission("maps:read"),
|
||||
},
|
||||
fields: [
|
||||
{
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import { CollectionConfig } from "payload";
|
||||
import { isDeveloper } from "@/utils/access-control/isRole";
|
||||
import { requirePermission } from "@/utils/access-control/hasPermission";
|
||||
|
||||
export const NarrativeEvents: CollectionConfig = {
|
||||
slug: "narrative-events",
|
||||
|
|
@ -8,10 +8,10 @@ export const NarrativeEvents: CollectionConfig = {
|
|||
useAsTitle: "name",
|
||||
},
|
||||
access: {
|
||||
create: isDeveloper,
|
||||
update: isDeveloper,
|
||||
delete: isDeveloper,
|
||||
read: isDeveloper,
|
||||
create: requirePermission("narrative-events:create"),
|
||||
update: requirePermission("narrative-events:update"),
|
||||
delete: requirePermission("narrative-events:delete"),
|
||||
read: requirePermission("narrative-events:read"),
|
||||
},
|
||||
fields: [
|
||||
{
|
||||
|
|
|
|||
|
|
@ -74,6 +74,7 @@ export interface Config {
|
|||
'game-npcs': GameNpc;
|
||||
'game-event-logs': GameEventLog;
|
||||
users: User;
|
||||
roles: Role;
|
||||
ranks: Rank;
|
||||
profiles: Profile;
|
||||
awards: Award;
|
||||
|
|
@ -125,6 +126,7 @@ export interface Config {
|
|||
'game-npcs': GameNpcsSelect<false> | GameNpcsSelect<true>;
|
||||
'game-event-logs': GameEventLogsSelect<false> | GameEventLogsSelect<true>;
|
||||
users: UsersSelect<false> | UsersSelect<true>;
|
||||
roles: RolesSelect<false> | RolesSelect<true>;
|
||||
ranks: RanksSelect<false> | RanksSelect<true>;
|
||||
profiles: ProfilesSelect<false> | ProfilesSelect<true>;
|
||||
awards: AwardsSelect<false> | AwardsSelect<true>;
|
||||
|
|
@ -1260,7 +1262,14 @@ export interface User {
|
|||
displayName: string;
|
||||
payloadDisplayName?: string | null;
|
||||
steamId: string;
|
||||
/**
|
||||
* Legacy role enum — being replaced by the dynamic RBAC system (see 'Role Assignments' below).
|
||||
*/
|
||||
roles?: ('guest' | 'user' | 'trusted' | 'admin' | 'developer')[] | null;
|
||||
/**
|
||||
* Dynamic RBAC role assignments. These determine the user's permissions via the roles collection.
|
||||
*/
|
||||
roleDocs?: (number | Role)[] | null;
|
||||
preferences?: {
|
||||
notifications?: {
|
||||
mutedAll?: boolean | null;
|
||||
|
|
@ -1335,6 +1344,203 @@ export interface User {
|
|||
password?: string | null;
|
||||
collection: 'users';
|
||||
}
|
||||
/**
|
||||
* Dynamic roles for the RBAC permission system. Assign permissions to roles, then assign roles to users.
|
||||
*
|
||||
* This interface was referenced by `Config`'s JSON-Schema
|
||||
* via the `definition` "roles".
|
||||
*/
|
||||
export interface Role {
|
||||
id: number;
|
||||
/**
|
||||
* Display name for this role, e.g. 'Logistics Officer'.
|
||||
*/
|
||||
name: string;
|
||||
/**
|
||||
* Machine-readable key. Built-in roles: 'guest', 'user', 'admin', 'developer'. Used by seed scripts and the Discord bot to look up roles by key.
|
||||
*/
|
||||
slug: string;
|
||||
/**
|
||||
* Optional notes about what this role is for.
|
||||
*/
|
||||
description?: string | null;
|
||||
/**
|
||||
* Permissions granted by this role. The full list is defined in src/permissions/index.ts.
|
||||
*/
|
||||
permissions?:
|
||||
| (
|
||||
| 'system:admin-access'
|
||||
| 'users:create'
|
||||
| 'users:read'
|
||||
| 'users:update'
|
||||
| 'users:delete'
|
||||
| 'users:unlock'
|
||||
| 'users:assign-roles'
|
||||
| 'ranks:create'
|
||||
| 'ranks:read'
|
||||
| 'ranks:update'
|
||||
| 'ranks:delete'
|
||||
| 'profiles:create'
|
||||
| 'profiles:read'
|
||||
| 'profiles:update'
|
||||
| 'profiles:delete'
|
||||
| 'awards:create'
|
||||
| 'awards:read'
|
||||
| 'awards:update'
|
||||
| 'awards:delete'
|
||||
| 'qualifications:create'
|
||||
| 'qualifications:read'
|
||||
| 'qualifications:update'
|
||||
| 'qualifications:delete'
|
||||
| 'assignments:create'
|
||||
| 'assignments:read'
|
||||
| 'assignments:update'
|
||||
| 'assignments:delete'
|
||||
| 'experience:create'
|
||||
| 'experience:read'
|
||||
| 'experience:update'
|
||||
| 'experience:delete'
|
||||
| 'user-notifications:create'
|
||||
| 'user-notifications:read'
|
||||
| 'user-notifications:update'
|
||||
| 'user-notifications:delete'
|
||||
| 'missions:create'
|
||||
| 'missions:read'
|
||||
| 'missions:update'
|
||||
| 'missions:delete'
|
||||
| 'missions:read-sensitive'
|
||||
| 'mission-attendances:create'
|
||||
| 'mission-attendances:read'
|
||||
| 'mission-attendances:update'
|
||||
| 'mission-attendances:delete'
|
||||
| 'campaigns:create'
|
||||
| 'campaigns:read'
|
||||
| 'campaigns:update'
|
||||
| 'campaigns:delete'
|
||||
| 'factions:create'
|
||||
| 'factions:read'
|
||||
| 'factions:update'
|
||||
| 'factions:delete'
|
||||
| 'technologies:create'
|
||||
| 'technologies:read'
|
||||
| 'technologies:update'
|
||||
| 'technologies:delete'
|
||||
| 'assets:create'
|
||||
| 'assets:read'
|
||||
| 'assets:update'
|
||||
| 'assets:delete'
|
||||
| 'resources:create'
|
||||
| 'resources:read'
|
||||
| 'resources:update'
|
||||
| 'resources:delete'
|
||||
| 'vehicles:create'
|
||||
| 'vehicles:read'
|
||||
| 'vehicles:update'
|
||||
| 'vehicles:delete'
|
||||
| 'structures:create'
|
||||
| 'structures:read'
|
||||
| 'structures:update'
|
||||
| 'structures:delete'
|
||||
| 'shipments:create'
|
||||
| 'shipments:read'
|
||||
| 'shipments:update'
|
||||
| 'shipments:delete'
|
||||
| 'bank-accounts:create'
|
||||
| 'bank-accounts:read'
|
||||
| 'bank-accounts:update'
|
||||
| 'bank-accounts:delete'
|
||||
| 'bank-transactions:create'
|
||||
| 'bank-transactions:read'
|
||||
| 'bank-transactions:update'
|
||||
| 'bank-transactions:delete'
|
||||
| 'ledger-entries:create'
|
||||
| 'ledger-entries:read'
|
||||
| 'ledger-entries:update'
|
||||
| 'ledger-entries:delete'
|
||||
| 'locker-storages:create'
|
||||
| 'locker-storages:read'
|
||||
| 'locker-storages:update'
|
||||
| 'locker-storages:delete'
|
||||
| 'loadouts:create'
|
||||
| 'loadouts:read'
|
||||
| 'loadouts:update'
|
||||
| 'loadouts:delete'
|
||||
| 'market-listings:create'
|
||||
| 'market-listings:read'
|
||||
| 'market-listings:update'
|
||||
| 'market-listings:delete'
|
||||
| 'market-negotiations:create'
|
||||
| 'market-negotiations:read'
|
||||
| 'market-negotiations:update'
|
||||
| 'market-negotiations:delete'
|
||||
| 'tickets:create'
|
||||
| 'tickets:read'
|
||||
| 'tickets:update'
|
||||
| 'tickets:delete'
|
||||
| 'game-structures:create'
|
||||
| 'game-structures:read'
|
||||
| 'game-structures:update'
|
||||
| 'game-structures:delete'
|
||||
| 'game-vehicles:create'
|
||||
| 'game-vehicles:read'
|
||||
| 'game-vehicles:update'
|
||||
| 'game-vehicles:delete'
|
||||
| 'game-npcs:create'
|
||||
| 'game-npcs:read'
|
||||
| 'game-npcs:update'
|
||||
| 'game-npcs:delete'
|
||||
| 'game-hard-resources:create'
|
||||
| 'game-hard-resources:read'
|
||||
| 'game-hard-resources:update'
|
||||
| 'game-hard-resources:delete'
|
||||
| 'game-event-logs:create'
|
||||
| 'game-event-logs:read'
|
||||
| 'game-event-logs:update'
|
||||
| 'game-event-logs:delete'
|
||||
| 'maps:create'
|
||||
| 'maps:read'
|
||||
| 'maps:update'
|
||||
| 'maps:delete'
|
||||
| 'narrative-events:create'
|
||||
| 'narrative-events:read'
|
||||
| 'narrative-events:update'
|
||||
| 'narrative-events:delete'
|
||||
| 'mission-files:create'
|
||||
| 'mission-files:read'
|
||||
| 'mission-files:update'
|
||||
| 'mission-files:delete'
|
||||
| 'mod-lists:create'
|
||||
| 'mod-lists:read'
|
||||
| 'mod-lists:update'
|
||||
| 'mod-lists:delete'
|
||||
| 'game-rules:read'
|
||||
| 'game-rules:update'
|
||||
| 'shims:read'
|
||||
| 'shims:update'
|
||||
| 'logistics:manage'
|
||||
| 'intelligence:manage'
|
||||
| 'profiles:intel_excerpt:update'
|
||||
| 'banking:manage'
|
||||
| 'tickets:staff'
|
||||
| 'discord:staff'
|
||||
| 'discord:announce'
|
||||
)[]
|
||||
| null;
|
||||
/**
|
||||
* Parent roles to inherit permissions and settings from. Inheriting from a superuser role makes this role a superuser. Restricted to developers.
|
||||
*/
|
||||
parentRoles?: (number | Role)[] | null;
|
||||
/**
|
||||
* System roles are built-in and cannot be deleted. They can still be edited (e.g. to change their permissions).
|
||||
*/
|
||||
isSystem?: boolean | null;
|
||||
/**
|
||||
* Superuser roles bypass ALL permission checks. Use with extreme caution — this grants unrestricted access.
|
||||
*/
|
||||
isSuperuser?: boolean | null;
|
||||
updatedAt: string;
|
||||
createdAt: string;
|
||||
}
|
||||
/**
|
||||
* This interface was referenced by `Config`'s JSON-Schema
|
||||
* via the `definition` "ranks".
|
||||
|
|
@ -1358,7 +1564,8 @@ export interface Profile {
|
|||
user: number | User;
|
||||
rank: number | Rank;
|
||||
profileTitle?: string | null;
|
||||
dossier?: {
|
||||
dossier: {
|
||||
enlistmentDate: string;
|
||||
personalExcerpt?: string | null;
|
||||
intelExcerpt?: {
|
||||
root: {
|
||||
|
|
@ -2438,6 +2645,10 @@ export interface PayloadLockedDocument {
|
|||
relationTo: 'users';
|
||||
value: number | User;
|
||||
} | null)
|
||||
| ({
|
||||
relationTo: 'roles';
|
||||
value: number | Role;
|
||||
} | null)
|
||||
| ({
|
||||
relationTo: 'ranks';
|
||||
value: number | Rank;
|
||||
|
|
@ -2746,6 +2957,7 @@ export interface UsersSelect<T extends boolean = true> {
|
|||
payloadDisplayName?: T;
|
||||
steamId?: T;
|
||||
roles?: T;
|
||||
roleDocs?: T;
|
||||
preferences?:
|
||||
| T
|
||||
| {
|
||||
|
|
@ -2786,6 +2998,21 @@ export interface UsersSelect<T extends boolean = true> {
|
|||
expiresAt?: T;
|
||||
};
|
||||
}
|
||||
/**
|
||||
* This interface was referenced by `Config`'s JSON-Schema
|
||||
* via the `definition` "roles_select".
|
||||
*/
|
||||
export interface RolesSelect<T extends boolean = true> {
|
||||
name?: T;
|
||||
slug?: T;
|
||||
description?: T;
|
||||
permissions?: T;
|
||||
parentRoles?: T;
|
||||
isSystem?: T;
|
||||
isSuperuser?: T;
|
||||
updatedAt?: T;
|
||||
createdAt?: T;
|
||||
}
|
||||
/**
|
||||
* This interface was referenced by `Config`'s JSON-Schema
|
||||
* via the `definition` "ranks_select".
|
||||
|
|
@ -2810,6 +3037,7 @@ export interface ProfilesSelect<T extends boolean = true> {
|
|||
dossier?:
|
||||
| T
|
||||
| {
|
||||
enlistmentDate?: T;
|
||||
personalExcerpt?: T;
|
||||
intelExcerpt?: T;
|
||||
};
|
||||
|
|
|
|||
Loading…
Reference in a new issue