fix(ui): public users unable to log out (#10188)
Fixes #10180. When logged in as an unauthorized user who cannot access the admin panel, the user is unable to log out through the prompted `/admin/logout` page. This was because that page was using an incorrect API endpoint, reading from `admin.user` instead of `user.collection` when formatting the route. This page was also able to get stuck in an infinite loading state when attempting to log out without any user at all. Now, public users can properly log out and then back in with another user who might have access. The messaging around this was also misleading. Instead of displaying the "Unauthorized, you must be logged in to make this request" message, we now display a new "Unauthorized, this user does not have access to the admin panel" message for added clarity.
This commit is contained in:
@@ -9,6 +9,7 @@ type Args = {
|
||||
searchParams: { [key: string]: string | string[] }
|
||||
user?: User
|
||||
}
|
||||
|
||||
export const handleAuthRedirect = ({ config, route, searchParams, user }: Args): string => {
|
||||
const {
|
||||
admin: {
|
||||
|
||||
@@ -110,7 +110,7 @@ export const initPage = async ({
|
||||
},
|
||||
})
|
||||
?.then((res) => res.docs?.[0]?.value as string)
|
||||
} catch (error) {} // eslint-disable-line no-empty
|
||||
} catch (_err) {} // eslint-disable-line no-empty
|
||||
}
|
||||
|
||||
locale = findLocaleFromCode(localization, localeCode)
|
||||
|
||||
@@ -19,8 +19,11 @@ export const LogoutClient: React.FC<{
|
||||
const { adminRoute, inactivity, redirect } = props
|
||||
|
||||
const { logOut, user } = useAuth()
|
||||
|
||||
const [isLoggedOut, setIsLoggedOut] = React.useState<boolean>(!user)
|
||||
|
||||
const logOutSuccessRef = React.useRef(false)
|
||||
|
||||
const [loginRoute] = React.useState(() =>
|
||||
formatAdminURL({
|
||||
adminRoute,
|
||||
@@ -49,8 +52,10 @@ export const LogoutClient: React.FC<{
|
||||
useEffect(() => {
|
||||
if (!isLoggedOut) {
|
||||
void handleLogOut()
|
||||
} else {
|
||||
router.push(loginRoute)
|
||||
}
|
||||
}, [handleLogOut, isLoggedOut])
|
||||
}, [handleLogOut, isLoggedOut, loginRoute, router])
|
||||
|
||||
if (isLoggedOut && inactivity) {
|
||||
return (
|
||||
|
||||
@@ -2,8 +2,9 @@
|
||||
|
||||
@layer payload-default {
|
||||
.unauthorized {
|
||||
&__button {
|
||||
&__button.btn {
|
||||
margin: 0;
|
||||
margin-block: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,6 +18,7 @@ export const UnauthorizedView: PayloadServerReactComponent<AdminViewComponent> =
|
||||
initPageResult,
|
||||
}) => {
|
||||
const {
|
||||
permissions,
|
||||
req: {
|
||||
i18n,
|
||||
payload: {
|
||||
@@ -28,6 +29,7 @@ export const UnauthorizedView: PayloadServerReactComponent<AdminViewComponent> =
|
||||
routes: { admin: adminRoute },
|
||||
},
|
||||
},
|
||||
user,
|
||||
},
|
||||
} = initPageResult
|
||||
|
||||
@@ -35,9 +37,10 @@ export const UnauthorizedView: PayloadServerReactComponent<AdminViewComponent> =
|
||||
<div className={baseClass}>
|
||||
<FormHeader
|
||||
description={i18n.t('error:notAllowedToAccessPage')}
|
||||
heading={i18n.t('error:unauthorized')}
|
||||
heading={i18n.t(
|
||||
user && !permissions.canAccessAdmin ? 'error:unauthorizedAdmin' : 'error:unauthorized',
|
||||
)}
|
||||
/>
|
||||
|
||||
<Button
|
||||
className={`${baseClass}__button`}
|
||||
el="link"
|
||||
|
||||
@@ -78,6 +78,7 @@ export const clientTranslationKeys = createClientTranslationKeys([
|
||||
'error:unableToReindexCollection',
|
||||
'error:unableToUpdateCount',
|
||||
'error:unauthorized',
|
||||
'error:unauthorizedAdmin',
|
||||
'error:unknown',
|
||||
'error:unspecific',
|
||||
'error:userEmailAlreadyRegistered',
|
||||
|
||||
@@ -115,6 +115,7 @@ export const arTranslations: DefaultTranslationsObject = {
|
||||
unableToReindexCollection: 'خطأ في إعادة فهرسة المجموعة {{collection}}. تم إيقاف العملية.',
|
||||
unableToUpdateCount: 'يتعذّر تحديث {{count}} من {{total}} {{label}}.',
|
||||
unauthorized: 'غير مصرّح لك ، عليك أن تقوم بتسجيل الدّخول لتتمكّن من تقديم هذا الطّلب.',
|
||||
unauthorizedAdmin: 'غير مصرّح لك بالوصول إلى لوحة التحكّم.',
|
||||
unknown: 'حدث خطأ غير معروف.',
|
||||
unPublishingDocument: 'حدث خطأ أثناء إلغاء نشر هذا المستند.',
|
||||
unspecific: 'حدث خطأ.',
|
||||
|
||||
@@ -116,6 +116,7 @@ export const azTranslations: DefaultTranslationsObject = {
|
||||
'{{collection}} kolleksiyasının yenidən indekslənməsi zamanı səhv baş verdi. Əməliyyat dayandırıldı.',
|
||||
unableToUpdateCount: '{{count}} dən {{total}} {{label}} yenilənə bilmir.',
|
||||
unauthorized: 'İcazəniz yoxdur, bu tələbi yerinə yetirmək üçün daxil olmalısınız.',
|
||||
unauthorizedAdmin: 'Bu əməliyyatı yerinə yetirmək üçün admin olmalısınız.',
|
||||
unknown: 'Naməlum bir xəta baş verdi.',
|
||||
unPublishingDocument: 'Bu sənədin nəşrini ləğv etmək zamanı problem baş verdi.',
|
||||
unspecific: 'Xəta baş verdi.',
|
||||
|
||||
@@ -116,6 +116,7 @@ export const bgTranslations: DefaultTranslationsObject = {
|
||||
'Грешка при преиндексиране на колекцията {{collection}}. Операцията е прекратена.',
|
||||
unableToUpdateCount: 'Не беше възможно да се обновят {{count}} от {{total}} {{label}}.',
|
||||
unauthorized: 'Неоторизиран, трябва да влезеш, за да извършиш тази заявка.',
|
||||
unauthorizedAdmin: 'Неоторизиран, трябва да си администратор, за да извършиш тази заявка.',
|
||||
unknown: 'Неизвестна грешка.',
|
||||
unPublishingDocument: 'Имаше проблем при скриването на този документ.',
|
||||
unspecific: 'Грешка.',
|
||||
|
||||
@@ -116,6 +116,7 @@ export const csTranslations: DefaultTranslationsObject = {
|
||||
'Chyba při přeindexování kolekce {{collection}}. Operace byla přerušena.',
|
||||
unableToUpdateCount: 'Nelze aktualizovat {{count}} z {{total}} {{label}}.',
|
||||
unauthorized: 'Neautorizováno, pro zadání tohoto požadavku musíte být přihlášeni.',
|
||||
unauthorizedAdmin: 'Neautorizováno, tento uživatel nemá přístup k administraci.',
|
||||
unknown: 'Došlo k neznámé chybě.',
|
||||
unPublishingDocument: 'Při zrušení publikování tohoto dokumentu došlo k chybě.',
|
||||
unspecific: 'Došlo k chybě.',
|
||||
|
||||
@@ -115,6 +115,7 @@ export const daTranslations: DefaultTranslationsObject = {
|
||||
'Fejl ved genindeksering af samling {{collection}}. Operationen blev afbrudt.',
|
||||
unableToUpdateCount: 'Kunne ikke slette {{count}} mangler {{total}} {{label}}.',
|
||||
unauthorized: 'Uautoriseret, log in for at gennemføre handlingen.',
|
||||
unauthorizedAdmin: 'Uautoriseret, denne bruger har ikke adgang til adminpanelet.',
|
||||
unknown: 'En ukendt fejl er opstået.',
|
||||
unPublishingDocument: 'Der opstod et problem med at ophæve udgivelsen af dette dokument.',
|
||||
unspecific: 'En fejl er opstået.',
|
||||
|
||||
@@ -118,6 +118,7 @@ export const deTranslations: DefaultTranslationsObject = {
|
||||
'Fehler beim Neuindizieren der Sammlung {{collection}}. Vorgang abgebrochen.',
|
||||
unableToUpdateCount: '{{count}} von {{total}} {{label}} konnte nicht aktualisiert werden.',
|
||||
unauthorized: 'Nicht autorisiert - du musst angemeldet sein, um diese Anfrage zu stellen.',
|
||||
unauthorizedAdmin: 'Nicht autorisiert, dieser Benutzer hat keinen Zugriff auf das Admin-Panel.',
|
||||
unknown: 'Ein unbekannter Fehler ist aufgetreten.',
|
||||
unPublishingDocument: 'Es gab ein Problem, dieses Dokument auf Entwurf zu setzen.',
|
||||
unspecific: 'Ein Fehler ist aufgetreten.',
|
||||
|
||||
@@ -116,6 +116,7 @@ export const enTranslations = {
|
||||
unableToReindexCollection: 'Error reindexing collection {{collection}}. Operation aborted.',
|
||||
unableToUpdateCount: 'Unable to update {{count}} out of {{total}} {{label}}.',
|
||||
unauthorized: 'Unauthorized, you must be logged in to make this request.',
|
||||
unauthorizedAdmin: 'Unauthorized, this user does not have access to the admin panel.',
|
||||
unknown: 'An unknown error has occurred.',
|
||||
unPublishingDocument: 'There was a problem while un-publishing this document.',
|
||||
unspecific: 'An error has occurred.',
|
||||
|
||||
@@ -116,6 +116,7 @@ export const esTranslations: DefaultTranslationsObject = {
|
||||
'Error al reindexar la colección {{collection}}. Operación abortada.',
|
||||
unableToUpdateCount: 'No se puede actualizar {{count}} de {{total}} {{label}}.',
|
||||
unauthorized: 'No autorizado, debes iniciar sesión para realizar esta solicitud.',
|
||||
unauthorizedAdmin: 'No autorizado, este usuario no tiene acceso al panel de administración.',
|
||||
unknown: 'Ocurrió un error desconocido.',
|
||||
unPublishingDocument: 'Ocurrió un error al despublicar este documento.',
|
||||
unspecific: 'Ocurrió un error.',
|
||||
|
||||
@@ -114,6 +114,7 @@ export const faTranslations: DefaultTranslationsObject = {
|
||||
unableToReindexCollection: 'خطا در بازنمایهسازی مجموعه {{collection}}. عملیات متوقف شد.',
|
||||
unableToUpdateCount: 'امکان به روز رسانی {{count}} خارج از {{total}} {{label}} وجود ندارد.',
|
||||
unauthorized: 'درخواست نامعتبر، جهت فرستادن این درخواست باید وارد شوید.',
|
||||
unauthorizedAdmin: 'دسترسی به پیشخوان برای این کاربر مجاز نیست.',
|
||||
unknown: 'یک خطای ناشناخته رخ داد.',
|
||||
unPublishingDocument: 'هنگام لغو انتشار این سند خطایی رخ داد.',
|
||||
unspecific: 'خطایی رخ داد.',
|
||||
|
||||
@@ -119,6 +119,7 @@ export const frTranslations: DefaultTranslationsObject = {
|
||||
'Erreur lors de la réindexation de la collection {{collection}}. Opération annulée.',
|
||||
unableToUpdateCount: 'Impossible de mettre à jour {{count}} sur {{total}} {{label}}.',
|
||||
unauthorized: 'Non autorisé, vous devez être connecté pour effectuer cette demande.',
|
||||
unauthorizedAdmin: 'Non autorisé, cet utilisateur n’a pas accès au panneau d’administration.',
|
||||
unknown: 'Une erreur inconnue s’est produite.',
|
||||
unPublishingDocument:
|
||||
'Un problème est survenu lors de l’annulation de la publication de ce document.',
|
||||
|
||||
@@ -113,6 +113,7 @@ export const heTranslations: DefaultTranslationsObject = {
|
||||
unableToReindexCollection: 'שגיאה בהחזרת אינדקס של אוסף {{collection}}. הפעולה בוטלה.',
|
||||
unableToUpdateCount: 'לא ניתן לעדכן {{count}} מתוך {{total}} {{label}}.',
|
||||
unauthorized: 'אין הרשאה, עליך להתחבר כדי לבצע בקשה זו.',
|
||||
unauthorizedAdmin: 'אין הרשאה, משתמש זה אינו יכול לגשת לפאנל הניהול.',
|
||||
unknown: 'אירעה שגיאה לא ידועה.',
|
||||
unPublishingDocument: 'אירעה בעיה בביטול הפרסום של מסמך זה.',
|
||||
unspecific: 'אירעה שגיאה.',
|
||||
|
||||
@@ -117,6 +117,7 @@ export const hrTranslations: DefaultTranslationsObject = {
|
||||
'Pogreška pri ponovnom indeksiranju kolekcije {{collection}}. Operacija je prekinuta.',
|
||||
unableToUpdateCount: 'Nije moguće ažurirati {{count}} od {{total}} {{label}}.',
|
||||
unauthorized: 'Neovlašteno, morate biti prijavljeni da biste uputili ovaj zahtjev.',
|
||||
unauthorizedAdmin: 'Neovlašteno, ovaj korisnik nema pristup administratorskom panelu.',
|
||||
unknown: 'Došlo je do nepoznate pogreške.',
|
||||
unPublishingDocument: 'Došlo je do problema pri poništavanju objave ovog dokumenta.',
|
||||
unspecific: 'Došlo je do pogreške.',
|
||||
|
||||
@@ -118,6 +118,7 @@ export const huTranslations: DefaultTranslationsObject = {
|
||||
'Hiba a(z) {{collection}} gyűjtemény újraindexelésekor. A művelet megszakítva.',
|
||||
unableToUpdateCount: 'Nem sikerült frissíteni {{count}}/{{total}} {{label}}.',
|
||||
unauthorized: 'Jogosulatlan, a kéréshez be kell jelentkeznie.',
|
||||
unauthorizedAdmin: 'Jogosulatlan, ez a felhasználó nem fér hozzá az admin panelhez.',
|
||||
unknown: 'Ismeretlen hiba történt.',
|
||||
unPublishingDocument: 'Hiba történt a dokumentum közzétételének visszavonása közben.',
|
||||
unspecific: 'Hiba történt.',
|
||||
|
||||
@@ -118,6 +118,8 @@ export const itTranslations: DefaultTranslationsObject = {
|
||||
'Errore durante la reindicizzazione della collezione {{collection}}. Operazione annullata.',
|
||||
unableToUpdateCount: 'Impossibile aggiornare {{count}} su {{total}} {{label}}.',
|
||||
unauthorized: 'Non autorizzato, devi essere loggato per effettuare questa richiesta.',
|
||||
unauthorizedAdmin:
|
||||
'Non autorizzato, questo utente non ha accesso al pannello di amministrazione.',
|
||||
unknown: 'Si è verificato un errore sconosciuto.',
|
||||
unPublishingDocument:
|
||||
"Si è verificato un problema durante l'annullamento della pubblicazione di questo documento.",
|
||||
|
||||
@@ -117,6 +117,7 @@ export const jaTranslations: DefaultTranslationsObject = {
|
||||
'コレクション {{collection}} の再インデックス中にエラーが発生しました。操作は中止されました。',
|
||||
unableToUpdateCount: '{{total}} {{label}} のうち {{count}} 個を更新できません。',
|
||||
unauthorized: '認証されていません。このリクエストを行うにはログインが必要です。',
|
||||
unauthorizedAdmin: '管理画面へのアクセス権がないため、認証されていません。',
|
||||
unknown: '不明なエラーが発生しました。',
|
||||
unPublishingDocument: 'このデータを非公開する際に問題が発生しました。',
|
||||
unspecific: 'エラーが発生しました。',
|
||||
|
||||
@@ -116,6 +116,7 @@ export const koTranslations: DefaultTranslationsObject = {
|
||||
'{{collection}} 컬렉션의 재인덱싱 중 오류가 발생했습니다. 작업이 중단되었습니다.',
|
||||
unableToUpdateCount: '총 {{total}}개 중 {{count}}개의 {{label}}을(를) 업데이트할 수 없습니다.',
|
||||
unauthorized: '권한 없음, 이 요청을 수행하려면 로그인해야 합니다.',
|
||||
unauthorizedAdmin: '관리자 패널에 액세스할 수 없습니다.',
|
||||
unknown: '알 수 없는 오류가 발생했습니다.',
|
||||
unPublishingDocument: '이 문서의 게시 취소 중에 문제가 발생했습니다.',
|
||||
unspecific: '오류가 발생했습니다.',
|
||||
|
||||
@@ -116,6 +116,7 @@ export const myTranslations: DefaultTranslationsObject = {
|
||||
'{{collection}} စုစည်းမှုကို ပြန်လည်အညွှန်းပြုလုပ်ခြင်း အမှားရှိနေသည်။ လုပ်ဆောင်မှုကို ဖျက်သိမ်းခဲ့သည်။',
|
||||
unableToUpdateCount: '{{total}} {{label}} မှ {{count}} ကို အပ်ဒိတ်လုပ်၍မရပါ။',
|
||||
unauthorized: 'အခွင့်မရှိပါ။ ဤတောင်းဆိုချက်ကို လုပ်ဆောင်နိုင်ရန် သင်သည် လော့ဂ်အင်ဝင်ရပါမည်။',
|
||||
unauthorizedAdmin: 'အခွင့်မရှိပါ။ ဤအကောင့်အသုံးပြုသူသည် အဆင့်မပြုပါနိုင်ပါ။',
|
||||
unknown: 'ဘာမှန်းမသိသော error တက်သွားပါသည်။',
|
||||
unPublishingDocument: 'ဖိုင်ကို ပြန်လည့် သိမ်းဆည်းခြင်းမှာ ပြဿနာရှိနေသည်။',
|
||||
unspecific: 'Error တက်နေပါသည်။',
|
||||
|
||||
@@ -116,6 +116,7 @@ export const nbTranslations: DefaultTranslationsObject = {
|
||||
'Feil ved reindeksering av samlingen {{collection}}. Operasjonen ble avbrutt.',
|
||||
unableToUpdateCount: 'Kan ikke oppdatere {{count}} av {{total}} {{label}}.',
|
||||
unauthorized: 'Uautorisert, du må være innlogget for å gjøre denne forespørselen.',
|
||||
unauthorizedAdmin: 'Uautorisert, denne brukeren har ikke tilgang til kontrollpanelet.',
|
||||
unknown: 'En ukjent feil har oppstått.',
|
||||
unPublishingDocument: 'Det oppstod et problem under avpublisering av dokumentet.',
|
||||
unspecific: 'En feil har oppstått.',
|
||||
|
||||
@@ -117,6 +117,8 @@ export const nlTranslations: DefaultTranslationsObject = {
|
||||
'Fout bij het herindexeren van de collectie {{collection}}. De operatie is afgebroken.',
|
||||
unableToUpdateCount: 'Kan {{count}} van {{total}} {{label}} niet updaten.',
|
||||
unauthorized: 'Ongeautoriseerd, u moet ingelogd zijn om dit verzoek te doen.',
|
||||
unauthorizedAdmin:
|
||||
'Ongeautoriseerd, deze gebruiker heeft geen toegang tot het beheerderspaneel.',
|
||||
unknown: 'Er is een onbekende fout opgetreden.',
|
||||
unPublishingDocument: 'Er was een probleem met het depubliceren van dit document.',
|
||||
unspecific: 'Er is een fout opgetreden.',
|
||||
|
||||
@@ -116,6 +116,7 @@ export const plTranslations: DefaultTranslationsObject = {
|
||||
'Błąd podczas ponownego indeksowania kolekcji {{collection}}. Operacja została przerwana.',
|
||||
unableToUpdateCount: 'Nie można zaktualizować {{count}} z {{total}} {{label}}.',
|
||||
unauthorized: 'Brak dostępu, musisz być zalogowany.',
|
||||
unauthorizedAdmin: 'Brak dostępu, ten użytkownik nie ma dostępu do panelu administracyjnego.',
|
||||
unknown: 'Wystąpił nieznany błąd.',
|
||||
unPublishingDocument: 'Wystąpił problem podczas cofania publikacji tego dokumentu.',
|
||||
unspecific: 'Wystąpił błąd',
|
||||
|
||||
@@ -116,6 +116,7 @@ export const ptTranslations: DefaultTranslationsObject = {
|
||||
unableToReindexCollection: 'Erro ao reindexar a coleção {{collection}}. Operação abortada.',
|
||||
unableToUpdateCount: 'Não foi possível atualizar {{count}} de {{total}} {{label}}.',
|
||||
unauthorized: 'Não autorizado. Você deve estar logado para fazer essa requisição',
|
||||
unauthorizedAdmin: 'Não autorizado, esse usuário não tem acesso ao painel de administração.',
|
||||
unknown: 'Ocorreu um erro desconhecido.',
|
||||
unPublishingDocument: 'Ocorreu um problema ao despublicar esse documento',
|
||||
unspecific: 'Ocorreu um erro.',
|
||||
|
||||
@@ -117,7 +117,8 @@ export const roTranslations: DefaultTranslationsObject = {
|
||||
unableToReindexCollection:
|
||||
'Eroare la reindexarea colecției {{collection}}. Operațiune anulată.',
|
||||
unableToUpdateCount: 'Nu se poate șterge {{count}} din {{total}} {{label}}.',
|
||||
unauthorized: 'neautorizat, trebuie să vă conectați pentru a face această cerere.',
|
||||
unauthorized: 'Neautorizat, trebuie să vă conectați pentru a face această cerere.',
|
||||
unauthorizedAdmin: 'Neautorizat, acest utilizator nu are acces la panoul de administrare.',
|
||||
unknown: 'S-a produs o eroare necunoscută.',
|
||||
unPublishingDocument: 'A existat o problemă în timpul nepublicării acestui document.',
|
||||
unspecific: 'S-a produs o eroare.',
|
||||
|
||||
@@ -117,6 +117,7 @@ export const rsTranslations: DefaultTranslationsObject = {
|
||||
'Грешка при реиндексирању колекције {{collection}}. Операција је прекинута.',
|
||||
unableToUpdateCount: 'Није могуће ажурирати {{count}} од {{total}} {{label}}.',
|
||||
unauthorized: 'Нисте ауторизовани да бисте упутили овај захтев.',
|
||||
unauthorizedAdmin: 'Немате приступ администраторском панелу.',
|
||||
unknown: 'Дошло је до непознате грешке.',
|
||||
unPublishingDocument: 'Постоји проблем при поништавању објаве овог документа.',
|
||||
unspecific: 'Дошло је до грешке.',
|
||||
|
||||
@@ -117,6 +117,7 @@ export const rsLatinTranslations: DefaultTranslationsObject = {
|
||||
'Greška pri reindeksiranju kolekcije {{collection}}. Operacija je prekinuta.',
|
||||
unableToUpdateCount: 'Nije moguće ažurirati {{count}} od {{total}} {{label}}.',
|
||||
unauthorized: 'Niste autorizovani da biste uputili ovaj zahtev.',
|
||||
unauthorizedAdmin: 'Nemate pristup administratorskom panelu.',
|
||||
unknown: 'Došlo je do nepoznate greške.',
|
||||
unPublishingDocument: 'Postoji problem pri poništavanju objave ovog dokumenta.',
|
||||
unspecific: 'Došlo je do greške.',
|
||||
|
||||
@@ -117,6 +117,7 @@ export const ruTranslations: DefaultTranslationsObject = {
|
||||
'Ошибка при переиндексации коллекции {{collection}}. Операция прервана.',
|
||||
unableToUpdateCount: 'Не удалось обновить {{count}} из {{total}} {{label}}.',
|
||||
unauthorized: 'Нет доступа, вы должны войти, чтобы сделать этот запрос.',
|
||||
unauthorizedAdmin: 'Нет доступа, этот пользователь не имеет доступа к панели администратора.',
|
||||
unknown: 'Произошла неизвестная ошибка.',
|
||||
unPublishingDocument: 'При отмене публикации этого документа возникла проблема.',
|
||||
unspecific: 'Произошла ошибка.',
|
||||
|
||||
@@ -117,6 +117,8 @@ export const skTranslations: DefaultTranslationsObject = {
|
||||
'Chyba pri reindexácii kolekcie {{collection}}. Operácia bola prerušená.',
|
||||
unableToUpdateCount: 'Nie je možné aktualizovať {{count}} z {{total}} {{label}}.',
|
||||
unauthorized: 'Neautorizováno, pro zadání tohoto požadavku musíte být přihlášeni.',
|
||||
unauthorizedAdmin:
|
||||
'Neoprávnený prístup, tento používateľ nemá prístup k administrátorskému panelu.',
|
||||
unknown: 'Došlo k neznámej chybe.',
|
||||
unPublishingDocument: 'Pri zrušení publikovania tohto dokumentu došlo k chybe.',
|
||||
unspecific: 'Došlo k chybe.',
|
||||
|
||||
@@ -116,6 +116,7 @@ export const slTranslations: DefaultTranslationsObject = {
|
||||
'Napaka pri reindeksiranju zbirke {{collection}}. Operacija je bila prekinjena.',
|
||||
unableToUpdateCount: 'Ni bilo mogoče posodobiti {{count}} od {{total}} {{label}}.',
|
||||
unauthorized: 'Neavtorizirano, za to zahtevo morate biti prijavljeni.',
|
||||
unauthorizedAdmin: 'Neavtorizirano, ta uporabnik nima dostopa do skrbniškega vmesnika.',
|
||||
unknown: 'Prišlo je do neznane napake.',
|
||||
unPublishingDocument: 'Pri umiku objave tega dokumenta je prišlo do težave.',
|
||||
unspecific: 'Prišlo je do napake.',
|
||||
|
||||
@@ -116,6 +116,7 @@ export const svTranslations: DefaultTranslationsObject = {
|
||||
'Fel vid omindexering av samlingen {{collection}}. Operationen avbröts.',
|
||||
unableToUpdateCount: 'Det gick inte att uppdatera {{count}} av {{total}} {{label}}.',
|
||||
unauthorized: 'Obehörig, du måste vara inloggad för att göra denna begäran.',
|
||||
unauthorizedAdmin: 'Obehörig, denna användare har inte åtkomst till adminpanelen.',
|
||||
unknown: 'Ett okänt fel har uppstått.',
|
||||
unPublishingDocument: 'Det uppstod ett problem när det här dokumentet skulle avpubliceras.',
|
||||
unspecific: 'Ett fel har uppstått.',
|
||||
|
||||
@@ -114,6 +114,7 @@ export const thTranslations: DefaultTranslationsObject = {
|
||||
'เกิดข้อผิดพลาดในการจัดทำดัชนีใหม่ของคอลเลกชัน {{collection}}. การดำเนินการถูกยกเลิก',
|
||||
unableToUpdateCount: 'ไม่สามารถอัปเดต {{count}} จาก {{total}} {{label}}',
|
||||
unauthorized: 'คุณไม่ได้รับอนุญาต กรุณาเข้าสู่ระบบเพื่อทำคำขอนี้',
|
||||
unauthorizedAdmin: 'คุณไม่ได้รับอนุญาตให้เข้าถึงแผงผู้ดูแล',
|
||||
unknown: 'เกิดปัญหาบางอย่างที่ไม่ทราบสาเหตุ',
|
||||
unPublishingDocument: 'เกิดปัญหาระหว่างการยกเลิกการเผยแพร่เอกสารนี้',
|
||||
unspecific: 'เกิดปัญหาบางอย่าง',
|
||||
|
||||
@@ -117,6 +117,7 @@ export const trTranslations: DefaultTranslationsObject = {
|
||||
'{{collection}} koleksiyonunun yeniden indekslenmesinde hata oluştu. İşlem durduruldu.',
|
||||
unableToUpdateCount: '{{total}} {{label}} içinden {{count}} güncellenemiyor.',
|
||||
unauthorized: 'Bu işlemi gerçekleştirmek için lütfen giriş yapın.',
|
||||
unauthorizedAdmin: 'Bu kullanıcı yönetici paneline erişim iznine sahip değil.',
|
||||
unknown: 'Bilinmeyen bir hata oluştu.',
|
||||
unPublishingDocument: 'Geçerli döküman yayından kaldırılırken bir sorun oluştu.',
|
||||
unspecific: 'Bir hata oluştu.',
|
||||
|
||||
@@ -117,6 +117,7 @@ export const ukTranslations: DefaultTranslationsObject = {
|
||||
'Помилка при повторному індексуванні колекції {{collection}}. Операцію скасовано.',
|
||||
unableToUpdateCount: 'Не вдалося оновити {{count}} із {{total}} {{label}}.',
|
||||
unauthorized: 'Немає доступу, ви повинні увійти, щоб виконати цей запит.',
|
||||
unauthorizedAdmin: 'Немає доступу, цей користувач не має доступу до панелі адміністратора.',
|
||||
unknown: 'Виникла невідома помилка.',
|
||||
unPublishingDocument: 'Під час скасування публікації даного документа виникла помилка.',
|
||||
unspecific: 'Виникла помилка.',
|
||||
|
||||
@@ -116,6 +116,7 @@ export const viTranslations: DefaultTranslationsObject = {
|
||||
'Lỗi khi tái lập chỉ mục bộ sưu tập {{collection}}. Quá trình bị hủy.',
|
||||
unableToUpdateCount: 'Không thể cập nhật {{count}} trên {{total}} {{label}}.',
|
||||
unauthorized: 'Lỗi - Bạn cần phải đăng nhập trước khi gửi request sau.',
|
||||
unauthorizedAdmin: 'Lỗi - Người dùng không có quyền truy cập vào bảng điều khiển.',
|
||||
unknown: 'Lỗi - Không xác định (unknown error).',
|
||||
unPublishingDocument: 'Lỗi - Đã xảy ra vấn để khi ẩn bản tài liệu.',
|
||||
unspecific: 'Lỗi - Đã xảy ra (unspecific error).',
|
||||
|
||||
@@ -111,6 +111,7 @@ export const zhTranslations: DefaultTranslationsObject = {
|
||||
unableToReindexCollection: '重新索引集合 {{collection}} 时出错。操作已中止。',
|
||||
unableToUpdateCount: '无法更新 {{count}} 个,共 {{total}} 个 {{label}}。',
|
||||
unauthorized: '未经授权,您必须登录才能提出这个请求。',
|
||||
unauthorizedAdmin: '未经授权,此用户无权访问管理面板。',
|
||||
unknown: '发生了一个未知的错误。',
|
||||
unPublishingDocument: '取消发布此文件时出现了问题。',
|
||||
unspecific: '发生了一个错误。',
|
||||
|
||||
@@ -111,6 +111,7 @@ export const zhTwTranslations: DefaultTranslationsObject = {
|
||||
unableToReindexCollection: '重新索引集合 {{collection}} 時出現錯誤。操作已中止。',
|
||||
unableToUpdateCount: '無法從 {{total}} 個中更新 {{count}} 個 {{label}}。',
|
||||
unauthorized: '未經授權,您必須登錄才能提出這個請求。',
|
||||
unauthorizedAdmin: '未經授權,此使用者無法訪問管理面板。',
|
||||
unknown: '發生了一個未知的錯誤。',
|
||||
unPublishingDocument: '取消發布此文件時出現了問題。',
|
||||
unspecific: '發生了一個錯誤。',
|
||||
|
||||
@@ -196,7 +196,7 @@ export function AuthProvider({
|
||||
|
||||
const logOut = useCallback(async () => {
|
||||
try {
|
||||
await requests.post(`${serverURL}${apiRoute}/${userSlug}/logout`)
|
||||
await requests.post(`${serverURL}${apiRoute}/${user.collection}/logout`)
|
||||
setNewUser(null)
|
||||
revokeTokenAndExpire()
|
||||
return true
|
||||
@@ -204,7 +204,7 @@ export function AuthProvider({
|
||||
toast.error(`Logging out failed: ${e.message}`)
|
||||
return false
|
||||
}
|
||||
}, [apiRoute, revokeTokenAndExpire, serverURL, setNewUser, userSlug])
|
||||
}, [apiRoute, revokeTokenAndExpire, serverURL, setNewUser, user])
|
||||
|
||||
const refreshPermissions = useCallback(
|
||||
async ({ locale }: { locale?: string } = {}) => {
|
||||
@@ -309,7 +309,7 @@ export function AuthProvider({
|
||||
clearTimeout(forceLogOut)
|
||||
}
|
||||
}
|
||||
}, [tokenExpiration, openModal, i18n, setNewUser, user])
|
||||
}, [tokenExpiration, openModal, i18n, setNewUser, user, redirectToInactivityRoute])
|
||||
|
||||
return (
|
||||
<Context.Provider
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -9,12 +9,7 @@ import { wait } from 'payload/shared'
|
||||
import { fileURLToPath } from 'url'
|
||||
|
||||
import type { PayloadTestSDK } from '../helpers/sdk/index.js'
|
||||
import type {
|
||||
Config,
|
||||
NonAdminUser,
|
||||
ReadOnlyCollection,
|
||||
RestrictedVersion,
|
||||
} from './payload-types.js'
|
||||
import type { Config, ReadOnlyCollection, RestrictedVersion } from './payload-types.js'
|
||||
|
||||
import {
|
||||
closeNav,
|
||||
@@ -34,9 +29,9 @@ import {
|
||||
disabledSlug,
|
||||
docLevelAccessSlug,
|
||||
fullyRestrictedSlug,
|
||||
noAdminAccessEmail,
|
||||
nonAdminUserEmail,
|
||||
nonAdminUserSlug,
|
||||
nonAdminEmail,
|
||||
publicUserEmail,
|
||||
publicUsersSlug,
|
||||
readNotUpdateGlobalSlug,
|
||||
readOnlyGlobalSlug,
|
||||
readOnlySlug,
|
||||
@@ -610,56 +605,56 @@ describe('access control', () => {
|
||||
})
|
||||
|
||||
describe('admin access', () => {
|
||||
test('should block admin access to admin user', async () => {
|
||||
const adminURL = `${serverURL}/admin`
|
||||
await page.goto(adminURL)
|
||||
await page.waitForURL(adminURL)
|
||||
test('unauthenticated users should not have access to the admin panel', async () => {
|
||||
await page.goto(url.logout)
|
||||
await page.waitForURL(url.logout)
|
||||
|
||||
await expect(page.locator('.dashboard')).toBeVisible()
|
||||
await expect(page.locator('.payload-toast-container')).toContainText(
|
||||
'You have been logged out successfully.',
|
||||
)
|
||||
|
||||
await page.goto(logoutURL)
|
||||
await page.waitForURL(logoutURL)
|
||||
await expect(page.locator('form.login__form')).toBeVisible()
|
||||
|
||||
await page.goto(url.admin)
|
||||
await page.waitForURL(url.login)
|
||||
expect(page.url()).toEqual(url.login)
|
||||
})
|
||||
|
||||
test('non-admin users should not have access to the admin panel', async () => {
|
||||
await page.goto(url.logout)
|
||||
await page.waitForURL(url.logout)
|
||||
|
||||
await login({
|
||||
data: {
|
||||
email: noAdminAccessEmail,
|
||||
email: nonAdminEmail,
|
||||
password: 'test',
|
||||
},
|
||||
page,
|
||||
serverURL,
|
||||
})
|
||||
|
||||
await expect(page.locator('.unauthorized')).toBeVisible()
|
||||
await expect(page.locator('.unauthorized .form-header h1')).toHaveText(
|
||||
'Unauthorized, this user does not have access to the admin panel.',
|
||||
)
|
||||
|
||||
// Log back in for the next test
|
||||
await page.goto(logoutURL)
|
||||
await login({
|
||||
data: {
|
||||
email: devUser.email,
|
||||
password: devUser.password,
|
||||
},
|
||||
page,
|
||||
serverURL,
|
||||
})
|
||||
await page.goto(url.logout)
|
||||
await page.waitForURL(url.logout)
|
||||
|
||||
await expect(page.locator('.payload-toast-container')).toContainText(
|
||||
'You have been logged out successfully.',
|
||||
)
|
||||
|
||||
await expect(page.locator('form.login__form')).toBeVisible()
|
||||
})
|
||||
|
||||
test('should block admin access to non-admin user', async () => {
|
||||
const adminURL = `${serverURL}/admin`
|
||||
const unauthorizedURL = `${serverURL}/admin/unauthorized`
|
||||
await page.goto(adminURL)
|
||||
await page.waitForURL(adminURL)
|
||||
test('public users should not have access to access admin', async () => {
|
||||
await page.goto(url.logout)
|
||||
await page.waitForURL(url.logout)
|
||||
|
||||
await expect(page.locator('.dashboard')).toBeVisible()
|
||||
|
||||
await page.goto(logoutURL)
|
||||
await page.waitForURL(logoutURL)
|
||||
|
||||
const nonAdminUser: {
|
||||
token?: string
|
||||
} & NonAdminUser = await payload.login({
|
||||
collection: nonAdminUserSlug,
|
||||
const user = await payload.login({
|
||||
collection: publicUsersSlug,
|
||||
data: {
|
||||
email: nonAdminUserEmail,
|
||||
email: publicUserEmail,
|
||||
password: devUser.password,
|
||||
},
|
||||
})
|
||||
@@ -667,20 +662,36 @@ describe('access control', () => {
|
||||
await context.addCookies([
|
||||
{
|
||||
name: 'payload-token',
|
||||
url: serverURL,
|
||||
value: nonAdminUser.token,
|
||||
value: user.token,
|
||||
domain: 'localhost',
|
||||
path: '/',
|
||||
httpOnly: true,
|
||||
secure: true,
|
||||
},
|
||||
])
|
||||
|
||||
await page.goto(adminURL)
|
||||
await page.waitForURL(unauthorizedURL)
|
||||
await page.reload()
|
||||
|
||||
await expect(page.locator('.unauthorized')).toBeVisible()
|
||||
await page.goto(url.admin)
|
||||
await page.waitForURL(/unauthorized$/)
|
||||
|
||||
// Log back in for the next test
|
||||
await context.clearCookies()
|
||||
await page.goto(logoutURL)
|
||||
await page.waitForURL(logoutURL)
|
||||
await expect(page.locator('.unauthorized .form-header h1')).toHaveText(
|
||||
'Unauthorized, this user does not have access to the admin panel.',
|
||||
)
|
||||
|
||||
await page.goto(url.logout)
|
||||
await page.waitForURL(url.logout)
|
||||
|
||||
await expect(page.locator('.payload-toast-container')).toContainText(
|
||||
'You have been logged out successfully.',
|
||||
)
|
||||
|
||||
await expect(page.locator('form.login__form')).toBeVisible()
|
||||
})
|
||||
})
|
||||
|
||||
describe('read-only from access control', () => {
|
||||
beforeAll(async () => {
|
||||
await login({
|
||||
data: {
|
||||
email: devUser.email,
|
||||
@@ -690,9 +701,7 @@ describe('access control', () => {
|
||||
serverURL,
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe('read-only from access control', () => {
|
||||
test('should be read-only when update returns false', async () => {
|
||||
await page.goto(disabledFields.create)
|
||||
|
||||
|
||||
@@ -9,11 +9,11 @@
|
||||
export interface Config {
|
||||
auth: {
|
||||
users: UserAuthOperations;
|
||||
'non-admin-user': NonAdminUserAuthOperations;
|
||||
'public-users': PublicUserAuthOperations;
|
||||
};
|
||||
collections: {
|
||||
users: User;
|
||||
'non-admin-user': NonAdminUser;
|
||||
'public-users': PublicUser;
|
||||
posts: Post;
|
||||
unrestricted: Unrestricted;
|
||||
'relation-restricted': RelationRestricted;
|
||||
@@ -40,7 +40,7 @@ export interface Config {
|
||||
collectionsJoins: {};
|
||||
collectionsSelect: {
|
||||
users: UsersSelect<false> | UsersSelect<true>;
|
||||
'non-admin-user': NonAdminUserSelect<false> | NonAdminUserSelect<true>;
|
||||
'public-users': PublicUsersSelect<false> | PublicUsersSelect<true>;
|
||||
posts: PostsSelect<false> | PostsSelect<true>;
|
||||
unrestricted: UnrestrictedSelect<false> | UnrestrictedSelect<true>;
|
||||
'relation-restricted': RelationRestrictedSelect<false> | RelationRestrictedSelect<true>;
|
||||
@@ -86,8 +86,8 @@ export interface Config {
|
||||
| (User & {
|
||||
collection: 'users';
|
||||
})
|
||||
| (NonAdminUser & {
|
||||
collection: 'non-admin-user';
|
||||
| (PublicUser & {
|
||||
collection: 'public-users';
|
||||
});
|
||||
jobs: {
|
||||
tasks: unknown;
|
||||
@@ -112,7 +112,7 @@ export interface UserAuthOperations {
|
||||
password: string;
|
||||
};
|
||||
}
|
||||
export interface NonAdminUserAuthOperations {
|
||||
export interface PublicUserAuthOperations {
|
||||
forgotPassword: {
|
||||
email: string;
|
||||
password: string;
|
||||
@@ -150,9 +150,9 @@ export interface User {
|
||||
}
|
||||
/**
|
||||
* This interface was referenced by `Config`'s JSON-Schema
|
||||
* via the `definition` "non-admin-user".
|
||||
* via the `definition` "public-users".
|
||||
*/
|
||||
export interface NonAdminUser {
|
||||
export interface PublicUser {
|
||||
id: string;
|
||||
updatedAt: string;
|
||||
createdAt: string;
|
||||
@@ -624,8 +624,8 @@ export interface PayloadLockedDocument {
|
||||
value: string | User;
|
||||
} | null)
|
||||
| ({
|
||||
relationTo: 'non-admin-user';
|
||||
value: string | NonAdminUser;
|
||||
relationTo: 'public-users';
|
||||
value: string | PublicUser;
|
||||
} | null)
|
||||
| ({
|
||||
relationTo: 'posts';
|
||||
@@ -710,8 +710,8 @@ export interface PayloadLockedDocument {
|
||||
value: string | User;
|
||||
}
|
||||
| {
|
||||
relationTo: 'non-admin-user';
|
||||
value: string | NonAdminUser;
|
||||
relationTo: 'public-users';
|
||||
value: string | PublicUser;
|
||||
};
|
||||
updatedAt: string;
|
||||
createdAt: string;
|
||||
@@ -728,8 +728,8 @@ export interface PayloadPreference {
|
||||
value: string | User;
|
||||
}
|
||||
| {
|
||||
relationTo: 'non-admin-user';
|
||||
value: string | NonAdminUser;
|
||||
relationTo: 'public-users';
|
||||
value: string | PublicUser;
|
||||
};
|
||||
key?: string | null;
|
||||
value?:
|
||||
@@ -773,9 +773,9 @@ export interface UsersSelect<T extends boolean = true> {
|
||||
}
|
||||
/**
|
||||
* This interface was referenced by `Config`'s JSON-Schema
|
||||
* via the `definition` "non-admin-user_select".
|
||||
* via the `definition` "public-users_select".
|
||||
*/
|
||||
export interface NonAdminUserSelect<T extends boolean = true> {
|
||||
export interface PublicUsersSelect<T extends boolean = true> {
|
||||
updatedAt?: T;
|
||||
createdAt?: T;
|
||||
email?: T;
|
||||
|
||||
@@ -18,11 +18,8 @@ export const docLevelAccessSlug = 'doc-level-access'
|
||||
export const hiddenFieldsSlug = 'hidden-fields'
|
||||
export const hiddenAccessSlug = 'hidden-access'
|
||||
export const hiddenAccessCountSlug = 'hidden-access-count'
|
||||
|
||||
export const noAdminAccessEmail = 'no-admin-access@payloadcms.com'
|
||||
|
||||
export const nonAdminUserEmail = 'non-admin-user@payloadcms.com'
|
||||
|
||||
export const nonAdminUserSlug = 'non-admin-user'
|
||||
|
||||
export const disabledSlug = 'disabled'
|
||||
|
||||
export const nonAdminEmail = 'no-admin-access@payloadcms.com'
|
||||
export const publicUserEmail = 'public-user@payloadcms.com'
|
||||
export const publicUsersSlug = 'public-users'
|
||||
|
||||
@@ -10,6 +10,7 @@ import {
|
||||
apiKeysSlug,
|
||||
namedSaveToJWTValue,
|
||||
partialDisableLocaleStrategiesSlug,
|
||||
publicUsersSlug,
|
||||
saveToJWTKey,
|
||||
slug,
|
||||
} from './shared.js'
|
||||
@@ -209,7 +210,7 @@ export default buildConfigWithDefaults({
|
||||
if (!user) {
|
||||
return false
|
||||
}
|
||||
if (user?.collection === 'api-keys') {
|
||||
if (user?.collection === apiKeysSlug) {
|
||||
return {
|
||||
id: {
|
||||
equals: user.id,
|
||||
@@ -230,7 +231,7 @@ export default buildConfigWithDefaults({
|
||||
},
|
||||
},
|
||||
{
|
||||
slug: 'public-users',
|
||||
slug: publicUsersSlug,
|
||||
auth: {
|
||||
verify: true,
|
||||
},
|
||||
@@ -263,7 +264,7 @@ export default buildConfigWithDefaults({
|
||||
})
|
||||
|
||||
await payload.create({
|
||||
collection: 'api-keys',
|
||||
collection: apiKeysSlug,
|
||||
data: {
|
||||
apiKey: uuid(),
|
||||
enableAPIKey: true,
|
||||
@@ -271,7 +272,7 @@ export default buildConfigWithDefaults({
|
||||
})
|
||||
|
||||
await payload.create({
|
||||
collection: 'api-keys',
|
||||
collection: apiKeysSlug,
|
||||
data: {
|
||||
apiKey: uuid(),
|
||||
enableAPIKey: true,
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
import type { Page } from '@playwright/test'
|
||||
import type { BrowserContext, Page } from '@playwright/test'
|
||||
import type { SanitizedConfig } from 'payload'
|
||||
|
||||
import { expect, test } from '@playwright/test'
|
||||
import { devUser } from 'credentials.js'
|
||||
import path from 'path'
|
||||
import { wait } from 'payload/shared'
|
||||
import { fileURLToPath } from 'url'
|
||||
import { v4 as uuid } from 'uuid'
|
||||
|
||||
@@ -83,6 +84,7 @@ const createFirstUser = async ({
|
||||
|
||||
describe('auth', () => {
|
||||
let page: Page
|
||||
let context: BrowserContext
|
||||
let url: AdminUrlUtil
|
||||
let serverURL: string
|
||||
let apiURL: string
|
||||
@@ -93,7 +95,7 @@ describe('auth', () => {
|
||||
apiURL = `${serverURL}/api`
|
||||
url = new AdminUrlUtil(serverURL, slug)
|
||||
|
||||
const context = await browser.newContext()
|
||||
context = await browser.newContext()
|
||||
page = await context.newPage()
|
||||
initPageConsoleErrorCatch(page)
|
||||
|
||||
@@ -107,7 +109,7 @@ describe('auth', () => {
|
||||
})
|
||||
|
||||
await payload.create({
|
||||
collection: 'api-keys',
|
||||
collection: apiKeysSlug,
|
||||
data: {
|
||||
apiKey: uuid(),
|
||||
enableAPIKey: true,
|
||||
@@ -115,7 +117,7 @@ describe('auth', () => {
|
||||
})
|
||||
|
||||
await payload.create({
|
||||
collection: 'api-keys',
|
||||
collection: apiKeysSlug,
|
||||
data: {
|
||||
apiKey: uuid(),
|
||||
enableAPIKey: true,
|
||||
|
||||
@@ -13,6 +13,7 @@ import {
|
||||
apiKeysSlug,
|
||||
namedSaveToJWTValue,
|
||||
partialDisableLocaleStrategiesSlug,
|
||||
publicUsersSlug,
|
||||
saveToJWTKey,
|
||||
slug,
|
||||
} from './shared.js'
|
||||
@@ -276,7 +277,7 @@ describe('Auth', () => {
|
||||
|
||||
it('should allow verification of a user', async () => {
|
||||
const emailToVerify = 'verify@me.com'
|
||||
const response = await restClient.POST(`/public-users`, {
|
||||
const response = await restClient.POST(`/${publicUsersSlug}`, {
|
||||
body: JSON.stringify({
|
||||
email: emailToVerify,
|
||||
password,
|
||||
@@ -290,7 +291,7 @@ describe('Auth', () => {
|
||||
expect(response.status).toBe(201)
|
||||
|
||||
const userResult = await payload.find({
|
||||
collection: 'public-users',
|
||||
collection: publicUsersSlug,
|
||||
limit: 1,
|
||||
showHiddenFields: true,
|
||||
where: {
|
||||
@@ -306,13 +307,13 @@ describe('Auth', () => {
|
||||
expect(_verificationToken).toBeDefined()
|
||||
|
||||
const verificationResponse = await restClient.POST(
|
||||
`/public-users/verify/${_verificationToken}`,
|
||||
`/${publicUsersSlug}/verify/${_verificationToken}`,
|
||||
)
|
||||
|
||||
expect(verificationResponse.status).toBe(200)
|
||||
|
||||
const afterVerifyResult = await payload.find({
|
||||
collection: 'public-users',
|
||||
collection: publicUsersSlug,
|
||||
limit: 1,
|
||||
showHiddenFields: true,
|
||||
where: {
|
||||
@@ -782,24 +783,24 @@ describe('Auth', () => {
|
||||
describe('API Key', () => {
|
||||
it('should authenticate via the correct API key user', async () => {
|
||||
const usersQuery = await payload.find({
|
||||
collection: 'api-keys',
|
||||
collection: apiKeysSlug,
|
||||
})
|
||||
|
||||
const [user1, user2] = usersQuery.docs
|
||||
|
||||
const success = await restClient
|
||||
.GET(`/api-keys/${user2.id}`, {
|
||||
.GET(`/${apiKeysSlug}/${user2.id}`, {
|
||||
headers: {
|
||||
Authorization: `api-keys API-Key ${user2.apiKey}`,
|
||||
Authorization: `${apiKeysSlug} API-Key ${user2.apiKey}`,
|
||||
},
|
||||
})
|
||||
.then((res) => res.json())
|
||||
|
||||
expect(success.apiKey).toStrictEqual(user2.apiKey)
|
||||
|
||||
const fail = await restClient.GET(`/api-keys/${user1.id}`, {
|
||||
const fail = await restClient.GET(`/${apiKeysSlug}/${user1.id}`, {
|
||||
headers: {
|
||||
Authorization: `api-keys API-Key ${user2.apiKey}`,
|
||||
Authorization: `${apiKeysSlug} API-Key ${user2.apiKey}`,
|
||||
},
|
||||
})
|
||||
|
||||
@@ -809,7 +810,7 @@ describe('Auth', () => {
|
||||
it('should not remove an API key from a user when updating other fields', async () => {
|
||||
const apiKey = uuid()
|
||||
const user = await payload.create({
|
||||
collection: 'api-keys',
|
||||
collection: apiKeysSlug,
|
||||
data: {
|
||||
apiKey,
|
||||
enableAPIKey: true,
|
||||
@@ -818,14 +819,14 @@ describe('Auth', () => {
|
||||
|
||||
const updatedUser = await payload.update({
|
||||
id: user.id,
|
||||
collection: 'api-keys',
|
||||
collection: apiKeysSlug,
|
||||
data: {
|
||||
enableAPIKey: true,
|
||||
},
|
||||
})
|
||||
|
||||
const userResult = await payload.find({
|
||||
collection: 'api-keys',
|
||||
collection: apiKeysSlug,
|
||||
where: {
|
||||
id: {
|
||||
equals: user.id,
|
||||
@@ -857,7 +858,7 @@ describe('Auth', () => {
|
||||
|
||||
// use the api key in a fetch to assert that it is disabled
|
||||
const response = await restClient
|
||||
.GET(`/api-keys/me`, {
|
||||
.GET(`/${apiKeysSlug}/me`, {
|
||||
headers: {
|
||||
Authorization: `${apiKeysSlug} API-Key ${apiKey}`,
|
||||
},
|
||||
@@ -888,7 +889,7 @@ describe('Auth', () => {
|
||||
|
||||
// use the api key in a fetch to assert that it is disabled
|
||||
const response = await restClient
|
||||
.GET(`/api-keys/me`, {
|
||||
.GET(`/${apiKeysSlug}/me`, {
|
||||
headers: {
|
||||
Authorization: `${apiKeysSlug} API-Key ${apiKey}`,
|
||||
},
|
||||
|
||||
@@ -1,4 +1,7 @@
|
||||
export const slug = 'users'
|
||||
|
||||
export const publicUsersSlug = 'public-users'
|
||||
|
||||
export const apiKeysSlug = 'api-keys'
|
||||
|
||||
export const partialDisableLocaleStrategiesSlug = 'partial-disable-locale-strategies'
|
||||
|
||||
@@ -28,6 +28,7 @@ type LoginArgs = {
|
||||
page: Page
|
||||
serverURL: string
|
||||
}
|
||||
|
||||
const random = (min: number, max: number) => Math.floor(Math.random() * (max - min + 1)) + min
|
||||
|
||||
const networkConditions = {
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
import type { Config } from 'payload'
|
||||
|
||||
// IMPORTANT: ensure that imports do not contain React components, etc. as this breaks Playwright tests
|
||||
// Instead of pointing to the bundled code, which will include React components, use direct import paths
|
||||
import { formatAdminURL } from '../../packages/ui/src/utilities/formatAdminURL.js' // eslint-disable-line payload/no-relative-monorepo-imports
|
||||
|
||||
import type { Config } from 'payload'
|
||||
|
||||
export class AdminUrlUtil {
|
||||
account: string
|
||||
|
||||
@@ -15,9 +15,14 @@ export class AdminUrlUtil {
|
||||
|
||||
list: string
|
||||
|
||||
login: string
|
||||
|
||||
logout: string
|
||||
|
||||
routes: Config['routes']
|
||||
|
||||
serverURL: string
|
||||
|
||||
constructor(serverURL: string, slug: string, routes?: Config['routes']) {
|
||||
this.routes = {
|
||||
admin: routes?.admin || '/admin',
|
||||
@@ -39,6 +44,18 @@ export class AdminUrlUtil {
|
||||
serverURL: this.serverURL,
|
||||
})
|
||||
|
||||
this.login = formatAdminURL({
|
||||
adminRoute: this.routes.admin,
|
||||
path: '/login',
|
||||
serverURL: this.serverURL,
|
||||
})
|
||||
|
||||
this.logout = formatAdminURL({
|
||||
adminRoute: this.routes.admin,
|
||||
path: '/logout',
|
||||
serverURL: this.serverURL,
|
||||
})
|
||||
|
||||
this.list = formatAdminURL({
|
||||
adminRoute: this.routes.admin,
|
||||
path: `/collections/${this.entitySlug}`,
|
||||
|
||||
@@ -28,7 +28,7 @@
|
||||
}
|
||||
],
|
||||
"paths": {
|
||||
"@payload-config": ["./test/live-preview/config.ts"],
|
||||
"@payload-config": ["./test/access-control/config.ts"],
|
||||
"@payloadcms/live-preview": ["./packages/live-preview/src"],
|
||||
"@payloadcms/live-preview-react": ["./packages/live-preview-react/src/index.ts"],
|
||||
"@payloadcms/live-preview-vue": ["./packages/live-preview-vue/src/index.ts"],
|
||||
|
||||
Reference in New Issue
Block a user