Simplify your stack and build anything. Or everything.
Build tomorrow’s web with a modern solution you truly own.
Code-based nature means you can build on top of it to power anything.
It’s time to take back your content infrastructure.

Access rights for drafts and publishing collections

default discord avatar
dkirchhoflast year
8

Hey, we have users (authors) in our cms who can create and edit pages as drafts but only specific users (editors) are allowed to publish them / update already published pages.


There are now access rules for the publish / save and unpublish buttons. Unfortunately I can only disable all fields, so an author isn't able to edit a published page and save a new version as a draft.



Do I need a custom "saveDraft"- and "publishButton"?


There is a "readVersions" access control rule. Would it usefull to add more rules?

  • default discord avatar
    zakinadhiflast year

    Yeah it seems you need to

  • default discord avatar
    dkirchhoflast year

    👍 just implemented the custom buttons a few weeks ago and it works well

  • default discord avatar
    palakrukhayalast year

    can you share example code?

    @691568994246983690
  • default discord avatar
    dkirchhoflast year

    Sure. There is a lot of custom logic in our app, but the important one is the following:



    add a custom publish button to the collection



    // collection config
    
    admin: {
        components: {
            edit: {
                PublishButton: CustomPublishButton,
            },
        },
    }


    just disable the button by yourself if the user role doesn't match



    // custom publish button
    
    if (atLeastRole(user.role, "editor")) {
        return (
            <props.DefaultButton
                canPublish={true}
                label={publishButtonText}
                disabled={props.disabled}
                publish={props.publish}
            />
        );
    }
  • default discord avatar
    yersn11 months ago

    Hi

    @691568994246983690

    , what is in atLeastRole



    trying do something similar based on roles

  • default discord avatar
    dkirchhof11 months ago

    I defined an array with roles. Each user can have only one role. Here is the code:



    export type Role = (typeof roles)[number];
    
    export const roles = ["author", "editor", "admin"] as const;
    
    export const atLeastRole = (role: Role, atLeast: Role) => {
        return roles.indexOf(role) >= roles.indexOf(atLeast);
    };
  • default discord avatar
    yersn11 months ago
    import * as React from 'react';
    
    import { CustomPublishButtonType } from 'payload/types';
    import { checkRole } from '../../collections/Users/checkRole';
    // import { admins } from '../../access/admins';
    // import { adminsOrHR } from '../../access/adminsOrHR2';
    import { Access } from "payload/config";
    
    export type Role = (typeof roles)[number];
    
    export const roles = ["hr", "academic-staff",'admissions','student-service', "admin"] as const;
    
    export const atLeastRole = (role: Role, atLeast: Role) => {
        return roles.indexOf(role) >= roles.indexOf(atLeast);
    };
    
    export const ConditionalPublish: CustomPublishButtonType = ({
      DefaultButton,
      disabled,
      label,
      publish,
    }) => {
    
      if (atLeastRole(user.role, "hr")) {
        return <DefaultButton canPublish={false} label={label} disabled={disabled} publish={publish} />
      }
    
      if (atLeastRole(user.role, "admin")) {
        return <DefaultButton canPublish={true} label={label} disabled={disabled} publish={publish} />
      }
    }


    I am making a publish button with custom access based on roles.



    where user.role comes from? do you import it from access config?



    export const ConditionalPublish: CustomPublishButtonType = ({
      DefaultButton,
      disabled,
      label,
      publish,
    }) => {
    
      const admins = ({ req: { user }}) => {
        if (user && checkRole(['admin'], user)) {
          return true
        }
        return false
      }
    
      if (admins({ req: { user: ['admin'] } })) {
        return <DefaultButton canPublish={true} label={label} disabled={disabled} publish={publish} />;
      } else {
        return <DefaultButton canPublish={false} label={label} disabled={true} publish={publish} />;
      }
    
    }


    import type { User } from '../../payload-types';
    import { useAuth } from 'payload/components/utilities'
    
    export const CustomSaveDraftButton: CustomSaveDraftButtonProps = ({
      DefaultButton,
      disabled,
      label,
      saveDraft,
    }) => {
      const { user } = useAuth<User>()
    
      if (user && checkRole(['admin'], user)) {
        return <DefaultButton label={label} disabled={disabled} saveDraft={saveDraft} />
      }
    
      if (user && checkRole(['hr'], user)) {
        return <DefaultButton label={'Send to Approve'} disabled={disabled} saveDraft={saveDraft} />
      }
    
    }


    This also have no desired result



    @691568994246983690

    Can you please take a look what I am doing wrong

  • default discord avatar
    dkirchhof11 months ago

    Actually the user role is a select field in my users collection. To get the user in this button component, I use the

    useAuth

    hook.



    const auth = useAuth();
    const user = auth.user;


    Since I conditionally render the publish button I always pass

    canPublish={true}

    to it.



    Oh I see that your second example is for the draft button. This looks fine. Probably you should return null in all other cases?

Star on GitHub

Star

Chat on Discord

Discord

online

Can't find what you're looking for?

Get dedicated engineering support directly from the Payload team.