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.
167 lines
4.3 KiB
TypeScript
167 lines
4.3 KiB
TypeScript
import { CollectionConfig } from "payload";
|
|
import { requirePermission } from "@/utils/access-control/hasPermission";
|
|
|
|
export const Factions: CollectionConfig = {
|
|
slug: "factions",
|
|
admin: {
|
|
group: "Intelligence",
|
|
useAsTitle: "name",
|
|
},
|
|
access: {
|
|
create: requirePermission("factions:create"),
|
|
update: requirePermission("factions:update"),
|
|
delete: requirePermission("factions:delete"),
|
|
read: ({ req }) => !!req.user,
|
|
},
|
|
hooks: {
|
|
beforeValidate: [
|
|
async ({ data, operation, originalDoc, req }) => {
|
|
if (data?.type !== "playerFaction") return data;
|
|
|
|
const payload = req.payload;
|
|
const existing = await payload.find({
|
|
collection: "factions",
|
|
where: { type: { equals: "playerFaction" } },
|
|
limit: 1,
|
|
depth: 0,
|
|
overrideAccess: true,
|
|
});
|
|
|
|
const conflict = existing.docs.find((doc) => doc.id !== originalDoc?.id);
|
|
if (conflict) {
|
|
throw new Error(
|
|
`Only one faction can be the Player Faction at a time. "${conflict.name}" is already the Player Faction.`,
|
|
);
|
|
}
|
|
return data;
|
|
},
|
|
],
|
|
},
|
|
fields: [
|
|
{
|
|
name: "name",
|
|
type: "text",
|
|
required: true,
|
|
unique: true,
|
|
},
|
|
{
|
|
name: "type",
|
|
type: "select",
|
|
options: [
|
|
{
|
|
label: "Player Faction",
|
|
value: "playerFaction",
|
|
},
|
|
{
|
|
label: "Major Faction",
|
|
value: "majorFaction",
|
|
},
|
|
{
|
|
label: "Minor Faction",
|
|
value: "minorFaction",
|
|
},
|
|
{
|
|
label: "Corporation",
|
|
value: "corporation",
|
|
},
|
|
{
|
|
label: "Special",
|
|
value: "special",
|
|
},
|
|
],
|
|
required: true,
|
|
defaultValue: "minorFaction",
|
|
admin: {
|
|
description:
|
|
"Player Faction = the faction our unit is currently playing as. Only one faction can carry this type at a time.",
|
|
},
|
|
},
|
|
{
|
|
name: "description",
|
|
type: "richText",
|
|
},
|
|
{
|
|
name: "reputation",
|
|
type: "number",
|
|
admin: {
|
|
description:
|
|
"This faction's standing in the world, from -100 (reviled) to 100 (revered). 0 is neutral. Adjusted manually by admins/GMs as campaign events unfold.",
|
|
},
|
|
defaultValue: 0,
|
|
min: -100,
|
|
max: 100,
|
|
},
|
|
{
|
|
name: "relationships",
|
|
type: "array",
|
|
labels: {
|
|
singular: "Relationship",
|
|
plural: "Relationships",
|
|
},
|
|
admin: {
|
|
description:
|
|
"Pairwise standing between this faction and another faction, from -100 (hostile) to 100 (allied). 0 is neutral. One entry per counterpart faction.",
|
|
},
|
|
fields: [
|
|
{
|
|
name: "targetFaction",
|
|
type: "relationship",
|
|
relationTo: "factions",
|
|
required: true,
|
|
admin: {
|
|
description: "The other faction in this pairwise relationship.",
|
|
},
|
|
},
|
|
{
|
|
name: "value",
|
|
type: "number",
|
|
required: true,
|
|
defaultValue: 0,
|
|
min: -100,
|
|
max: 100,
|
|
admin: {
|
|
description: "Standing from -100 (hostile) to 100 (allied). 0 is neutral.",
|
|
},
|
|
},
|
|
{
|
|
name: "notes",
|
|
type: "textarea",
|
|
admin: {
|
|
description: "Optional context for why this relationship stands where it does.",
|
|
},
|
|
},
|
|
],
|
|
},
|
|
{
|
|
name: "playableFaction",
|
|
type: "checkbox",
|
|
admin: {
|
|
description:
|
|
"Whether or not this faction is playable. Some factions may be specifically intended to be unplayable based on narrative requirements.",
|
|
},
|
|
},
|
|
{
|
|
name: "startingFaction",
|
|
type: "checkbox",
|
|
admin: {
|
|
description:
|
|
"Whether or not this faction is/was available as a starting faction at the beginning of the campaign.",
|
|
},
|
|
},
|
|
{
|
|
name: "associatedCampaigns",
|
|
type: "relationship",
|
|
relationTo: "campaigns",
|
|
hasMany: true,
|
|
},
|
|
{
|
|
name: "coverImage",
|
|
type: "upload",
|
|
relationTo: "media",
|
|
admin: {
|
|
description:
|
|
"Background image for the faction detail page hero. Renders translucent with a top-to-bottom fade to black. Recommended aspect ratio: 16:9 or wider.",
|
|
},
|
|
},
|
|
],
|
|
};
|