#Ensuring the first user's role can't be changed

36 messages · Page 1 of 1 (latest)

manic spear
#

I need some new ideas. I'm currently getting this error:

 ⨯ APIError: The collection with slug users can't be found. Find Operation.
    at isFirstUser (./src/lib/payload/is-first-user.ts:11:74)
    at hasAdminAccessButNotFirstUser (./src/lib/payload/access.ts:23:123)
    at async Promise.all (index 1)
    at async Promise.all (index 0)

The code with the error:

import { User } from '@/payload-types'
import payload from 'payload'

export default async function isFirstUser(id: User['id'] | undefined) {
  if (!id) {
    return false
  }
  const result = await payload.find({
    collection: 'users',
    depth: 1,
    page: 1,
    limit: 1,
    pagination: false,
    sort: '+id',
  })
  if (result.docs[0].id === id) {
    return true
  }
  return false
}

Again, my goal is to ensure the first user's role can't be changed.
This isn't working because at the first time an account is created, the slugs/database must not be setup yet. Is what I'm asking possible in Payload? I'd hope so.

keen tuskBOT
umbral field
#

The first time an account is created, the database is setup, but the table is empty

#

That's what should be happening at least

manic spear
#

Makes sense. Do you suggest going about this a different way? My goal is to prevent the first user's role being changed.

umbral field
#

beforeChange hook, if operation is create and if no other users in the collection exist, i'd assert the role returning the data with a hardcoded value for roles

#

alternatively, defaultValue on the role

#

and then access.update being false for those conditions

#

the latter sounds more pragmatic

manic spear
#

Ah hadn't considered those, thanks. I'll mess with those and see if I can get something working

#

One more question, is there a built in way to access the toast api in payload? Say I want to show a toast whenever the user tries to change the first user's role, mostly for UX

umbral field
#

so you wont need to do that

#

if you set the access.update

#

the form fields will be disabled

manic spear
#

ah

manic spear
#

So I got

access: {
  create: hasAdminAccess,
  update: isAdminNotFirstUser, // the only place i'm using this fn
},

with the the following function:

export const isAdminNotFirstUser: FieldAccess<{ id: string }, unknown, User> = async ({
  req: { user },
}) => {
  const firstUser = await isFirstUser(user?.id)
  if (user?.role === 'admin') {
    if (firstUser) {
      return false
    }
    return true
  }
  return false
}

and I'm still getting the error previously. Is this a bug?

manic spear
#

Changing it back to hasAdminAccess from isAdminNotFirstUser causes the og error to disappear, but it still happens with that function isAdminNotFirstUser. Anyone have any ideas?

#

I also tried it with what @umbral field mentioned with thebeforeChange hook, I still get that error when using the isFirstUser function:

else if (data.operation === 'update') {
    if (data.originalDoc) {
      if (await isFirstUser(data.originalDoc.id)) {
        return 'admin'
      }
    }
  }
#

Oh, and there already exists one user, the admin. So I don't see why this error is occuring.

umbral field
#

pass it the req and then reuse the same req.payload

manic spear
# umbral field what does your isFirstUser function look like?
export default async function isFirstUser(id: User['id'] | undefined) {
  if (!id) {
    return false
  }
  const result = await payload.find({
    collection: 'users',
    depth: 1,
    page: 1,
    limit: 1,
    pagination: false,
    sort: '+id',
  })
  if (result.docs[0].id === id) {
    return true
  }
  return false
}

Currently not passing in the req. I'll try it with the request.

#

Update: Using the req prevents the error from occurring:

  const result = await req.payload.find({
    collection: 'users',
    depth: 1,
    page: 1,
    limit: 1,
    pagination: false,
    sort: '+id',
  })

However, I can't seem to sort the results correctly. I've tried +id and -id, both times my first user appears last in the array of users (I'm accessing result.docs[0]).

#

I also changed the limit to 10, giving me all the current users (2) and even then the first user appars at the bottom.

umbral field
#

not sure, maybe id is not a sortable field

#

do you have createdAt?

manic spear
#

I would do a hacky solution and grab all the users and just select the last one, but I don't really like that solution

umbral field
#

but aside from that another solution here might be for you to have a flag on the first user

#

a checkbox like isFirst or isRoot

#

and then you query for it using where

umbral field
#

so you always get only 1 user

manic spear
#

Ah that could work

#

I'm going to mark this as resolved as the checkbox trick should work.