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.
166 lines
4.6 KiB
TypeScript
166 lines
4.6 KiB
TypeScript
import { CollectionConfig } from "payload";
|
|
import { requirePermission, hasPermission } from "@/utils/access-control/hasPermission";
|
|
|
|
export const LockerStorages: CollectionConfig = {
|
|
slug: "locker-storages",
|
|
admin: {
|
|
group: "Locker",
|
|
useAsTitle: "name",
|
|
defaultColumns: ["name", "ownerUser", "itemCount"],
|
|
},
|
|
access: {
|
|
read: async ({ req }) => {
|
|
if (!req.user) return false;
|
|
if (await hasPermission(req.payload, req.user, "locker-storages:read")) return true;
|
|
return { ownerUser: { equals: req.user.id } };
|
|
},
|
|
create: ({ req }) => {
|
|
if (!req.user) return false;
|
|
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: async ({ req }) => {
|
|
return await hasPermission(req.payload, req.user, "locker-storages:delete");
|
|
},
|
|
},
|
|
fields: [
|
|
{
|
|
name: "name",
|
|
type: "text",
|
|
required: true,
|
|
defaultValue: "Personal Locker",
|
|
admin: {
|
|
description: "Display name for this locker.",
|
|
},
|
|
},
|
|
{
|
|
name: "ownerUser",
|
|
type: "relationship",
|
|
relationTo: "users",
|
|
required: true,
|
|
admin: {
|
|
description: "The operator who owns this locker.",
|
|
},
|
|
},
|
|
{
|
|
name: "items",
|
|
type: "array",
|
|
admin: {
|
|
description:
|
|
"Items stored in the locker grid. Position and rotation are managed from the member locker UI.",
|
|
},
|
|
fields: [
|
|
{
|
|
name: "asset",
|
|
type: "relationship",
|
|
relationTo: "assets",
|
|
required: true,
|
|
},
|
|
{
|
|
name: "quantity",
|
|
type: "number",
|
|
required: true,
|
|
min: 1,
|
|
defaultValue: 1,
|
|
},
|
|
{
|
|
name: "gridX",
|
|
type: "number",
|
|
required: true,
|
|
min: 0,
|
|
defaultValue: 0,
|
|
admin: {
|
|
description: "Column position in the locker grid (0-indexed).",
|
|
},
|
|
},
|
|
{
|
|
name: "gridY",
|
|
type: "number",
|
|
required: true,
|
|
min: 0,
|
|
defaultValue: 0,
|
|
admin: {
|
|
description: "Row position in the locker grid (0-indexed).",
|
|
},
|
|
},
|
|
{
|
|
name: "rotated",
|
|
type: "checkbox",
|
|
defaultValue: false,
|
|
admin: {
|
|
description: "Whether this item is rotated 90 degrees (swaps width and height).",
|
|
},
|
|
},
|
|
{
|
|
name: "equipment",
|
|
type: "group",
|
|
label: "Equipment Customization",
|
|
admin: {
|
|
description:
|
|
"Per-instance customization for this item: installed attachments, applied skin, and a custom name. Managed from the member locker UI.",
|
|
},
|
|
fields: [
|
|
{
|
|
name: "attachments",
|
|
type: "array",
|
|
label: "Installed Attachments",
|
|
admin: {
|
|
description:
|
|
"Attachments installed on this item (e.g. optics, muzzles, bipods on a weapon). Installing consumes the attachment from the locker grid.",
|
|
},
|
|
fields: [
|
|
{
|
|
name: "asset",
|
|
type: "relationship",
|
|
relationTo: "assets",
|
|
required: true,
|
|
},
|
|
],
|
|
},
|
|
{
|
|
name: "skin",
|
|
type: "relationship",
|
|
relationTo: "assets",
|
|
admin: {
|
|
description:
|
|
"Skin applied to this item. Applying consumes the skin from the locker grid.",
|
|
},
|
|
filterOptions: {
|
|
assetType: {
|
|
equals: "skin",
|
|
},
|
|
},
|
|
},
|
|
{
|
|
name: "customName",
|
|
type: "text",
|
|
admin: {
|
|
description: 'Optional custom name for this item (e.g. "Frank\'s Karma").',
|
|
},
|
|
},
|
|
],
|
|
},
|
|
],
|
|
},
|
|
{
|
|
name: "itemCount",
|
|
type: "number",
|
|
admin: {
|
|
readOnly: true,
|
|
description: "Total number of distinct entries currently in this locker.",
|
|
},
|
|
hooks: {
|
|
beforeChange: [
|
|
({ data }) => {
|
|
const items = (data as { items?: unknown[] } | undefined)?.items;
|
|
return Array.isArray(items) ? items.length : 0;
|
|
},
|
|
],
|
|
},
|
|
},
|
|
],
|
|
};
|