Compare commits
1 Commits
v3.0.0-bet
...
fix/beta/m
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
9217599731 |
@@ -83,50 +83,12 @@ The following options are available:
|
||||
| **`disableLocalStrategy`** | Advanced - disable Payload's built-in local auth strategy. Only use this property if you have replaced Payload's auth mechanisms with your own. |
|
||||
| **`forgotPassword`** | Customize the way that the `forgotPassword` operation functions. [More details](./email#forgot-password). |
|
||||
| **`lockTime`** | Set the time (in milliseconds) that a user should be locked out if they fail authentication more times than `maxLoginAttempts` allows for. |
|
||||
| **`loginWithUsername`** | Ability to allow users to login with username/password. [More](/docs/authentication/overview#login-with-username) |
|
||||
| **`maxLoginAttempts`** | Only allow a user to attempt logging in X amount of times. Automatically locks out a user from authenticating if this limit is passed. Set to `0` to disable. |
|
||||
| **`strategies`** | Advanced - an array of custom authentification strategies to extend this collection's authentication with. [More details](./custom-strategies). |
|
||||
| **`tokenExpiration`** | How long (in seconds) to keep the user logged in. JWTs and HTTP-only cookies will both expire at the same time. |
|
||||
| **`useAPIKey`** | Payload Authentication provides for API keys to be set on each user within an Authentication-enabled Collection. [More details](./api-keys). |
|
||||
| **`verify`** | Set to `true` or pass an object with verification options to require users to verify by email before they are allowed to log into your app. [More details](./email#email-verification). |
|
||||
|
||||
### Login With Username
|
||||
|
||||
You can allow users to login with their username instead of their email address by setting the `loginWithUsername` property to `true`.
|
||||
|
||||
Example:
|
||||
|
||||
```ts
|
||||
{
|
||||
slug: 'customers',
|
||||
auth: {
|
||||
loginWithUsername: true,
|
||||
},
|
||||
}
|
||||
```
|
||||
|
||||
Or, you can pass an object with additional options:
|
||||
|
||||
```ts
|
||||
{
|
||||
slug: 'customers',
|
||||
auth: {
|
||||
loginWithUsername: {
|
||||
allowEmailLogin: true, // default: false
|
||||
requireEmail: false, // default: false
|
||||
},
|
||||
},
|
||||
}
|
||||
```
|
||||
|
||||
**`allowEmailLogin`**
|
||||
|
||||
If set to `true`, users can log in with either their username or email address. If set to `false`, users can only log in with their username.
|
||||
|
||||
**`requireEmail`**
|
||||
|
||||
If set to `true`, an email address is required when creating a new user. If set to `false`, email is not required upon creation.
|
||||
|
||||
## Admin Auto-Login
|
||||
|
||||
For testing and demo purposes you may want to skip forcing the admin user to login in order to access the [Admin Panel](../admin/overview). Typically, all users should be required to login to access the Admin Panel, however, you can speed up local development time by enabling auto-login.
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "payload-monorepo",
|
||||
"version": "3.0.0-beta.66",
|
||||
"version": "3.0.0-beta.65",
|
||||
"private": true,
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "create-payload-app",
|
||||
"version": "3.0.0-beta.66",
|
||||
"version": "3.0.0-beta.65",
|
||||
"homepage": "https://payloadcms.com",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@payloadcms/db-mongodb",
|
||||
"version": "3.0.0-beta.66",
|
||||
"version": "3.0.0-beta.65",
|
||||
"description": "The officially supported MongoDB database adapter for Payload",
|
||||
"homepage": "https://payloadcms.com",
|
||||
"repository": {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@payloadcms/db-postgres",
|
||||
"version": "3.0.0-beta.66",
|
||||
"version": "3.0.0-beta.65",
|
||||
"description": "The officially supported Postgres database adapter for Payload",
|
||||
"homepage": "https://payloadcms.com",
|
||||
"repository": {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@payloadcms/email-nodemailer",
|
||||
"version": "3.0.0-beta.66",
|
||||
"version": "3.0.0-beta.65",
|
||||
"description": "Payload Nodemailer Email Adapter",
|
||||
"homepage": "https://payloadcms.com",
|
||||
"repository": {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@payloadcms/email-resend",
|
||||
"version": "3.0.0-beta.66",
|
||||
"version": "3.0.0-beta.65",
|
||||
"description": "Payload Resend Email Adapter",
|
||||
"homepage": "https://payloadcms.com",
|
||||
"repository": {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@payloadcms/graphql",
|
||||
"version": "3.0.0-beta.66",
|
||||
"version": "3.0.0-beta.65",
|
||||
"homepage": "https://payloadcms.com",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
|
||||
@@ -8,7 +8,7 @@ function unlockResolver(collection: Collection) {
|
||||
async function resolver(_, args, context: Context) {
|
||||
const options = {
|
||||
collection,
|
||||
data: { email: args.email, username: args.username },
|
||||
data: { email: args.email },
|
||||
req: isolateObjectProperty(context.req, 'transactionID'),
|
||||
}
|
||||
|
||||
|
||||
@@ -429,24 +429,12 @@ function initCollectionsGraphQL({ config, graphqlResult }: InitCollectionsGraphQ
|
||||
}
|
||||
|
||||
if (!collectionConfig.auth.disableLocalStrategy) {
|
||||
const authArgs = {}
|
||||
|
||||
const canLoginWithEmail =
|
||||
!collectionConfig.auth.loginWithUsername ||
|
||||
collectionConfig.auth.loginWithUsername?.allowEmailLogin
|
||||
const canLoginWithUsername = collectionConfig.auth.loginWithUsername
|
||||
|
||||
if (canLoginWithEmail) {
|
||||
authArgs['email'] = { type: new GraphQLNonNull(GraphQLString) }
|
||||
}
|
||||
if (canLoginWithUsername) {
|
||||
authArgs['username'] = { type: new GraphQLNonNull(GraphQLString) }
|
||||
}
|
||||
|
||||
if (collectionConfig.auth.maxLoginAttempts > 0) {
|
||||
graphqlResult.Mutation.fields[`unlock${singularName}`] = {
|
||||
type: new GraphQLNonNull(GraphQLBoolean),
|
||||
args: authArgs,
|
||||
args: {
|
||||
email: { type: new GraphQLNonNull(GraphQLString) },
|
||||
},
|
||||
resolve: unlock(collection),
|
||||
}
|
||||
}
|
||||
@@ -467,8 +455,9 @@ function initCollectionsGraphQL({ config, graphqlResult }: InitCollectionsGraphQ
|
||||
},
|
||||
}),
|
||||
args: {
|
||||
...authArgs,
|
||||
email: { type: GraphQLString },
|
||||
password: { type: GraphQLString },
|
||||
username: { type: GraphQLString },
|
||||
},
|
||||
resolve: login(collection),
|
||||
}
|
||||
@@ -477,8 +466,8 @@ function initCollectionsGraphQL({ config, graphqlResult }: InitCollectionsGraphQ
|
||||
type: new GraphQLNonNull(GraphQLBoolean),
|
||||
args: {
|
||||
disableEmail: { type: GraphQLBoolean },
|
||||
email: { type: new GraphQLNonNull(GraphQLString) },
|
||||
expiration: { type: GraphQLInt },
|
||||
...authArgs,
|
||||
},
|
||||
resolve: forgotPassword(collection),
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@payloadcms/live-preview-react",
|
||||
"version": "3.0.0-beta.66",
|
||||
"version": "3.0.0-beta.65",
|
||||
"description": "The official live preview React SDK for Payload",
|
||||
"homepage": "https://payloadcms.com",
|
||||
"repository": {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@payloadcms/live-preview",
|
||||
"version": "3.0.0-beta.66",
|
||||
"version": "3.0.0-beta.65",
|
||||
"description": "The official live preview JavaScript SDK for Payload",
|
||||
"homepage": "https://payloadcms.com",
|
||||
"repository": {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@payloadcms/next",
|
||||
"version": "3.0.0-beta.66",
|
||||
"version": "3.0.0-beta.65",
|
||||
"homepage": "https://payloadcms.com",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
|
||||
@@ -8,18 +8,9 @@ import { headersWithCors } from '../../../utilities/headersWithCors.js'
|
||||
export const unlock: CollectionRouteHandler = async ({ collection, req }) => {
|
||||
const { t } = req
|
||||
|
||||
const authData = collection.config.auth?.loginWithUsername
|
||||
? {
|
||||
email: typeof req.data?.email === 'string' ? req.data.email : '',
|
||||
username: typeof req.data?.username === 'string' ? req.data.username : '',
|
||||
}
|
||||
: {
|
||||
email: typeof req.data?.email === 'string' ? req.data.email : '',
|
||||
}
|
||||
|
||||
await unlockOperation({
|
||||
collection,
|
||||
data: authData,
|
||||
data: { email: req.data.email as string },
|
||||
req,
|
||||
})
|
||||
|
||||
|
||||
@@ -98,16 +98,14 @@ export const Auth: React.FC<Props> = (props) => {
|
||||
<div className={[baseClass, className].filter(Boolean).join(' ')}>
|
||||
{!disableLocalStrategy && (
|
||||
<React.Fragment>
|
||||
{(!loginWithUsername ||
|
||||
loginWithUsername?.allowEmailLogin ||
|
||||
loginWithUsername?.requireEmail) && (
|
||||
{!loginWithUsername && (
|
||||
<EmailField
|
||||
autoComplete="email"
|
||||
disabled={disabled}
|
||||
label={t('general:email')}
|
||||
name="email"
|
||||
readOnly={readOnly}
|
||||
required={!loginWithUsername || loginWithUsername?.requireEmail}
|
||||
required
|
||||
/>
|
||||
)}
|
||||
{loginWithUsername && (
|
||||
|
||||
@@ -5,7 +5,7 @@ export type Props = {
|
||||
collectionSlug: SanitizedCollectionConfig['slug']
|
||||
disableLocalStrategy?: boolean
|
||||
email: string
|
||||
loginWithUsername: SanitizedCollectionConfig['auth']['loginWithUsername']
|
||||
loginWithUsername: boolean
|
||||
operation: 'create' | 'update'
|
||||
readOnly: boolean
|
||||
requirePassword?: boolean
|
||||
|
||||
@@ -1,109 +0,0 @@
|
||||
'use client'
|
||||
import type { PayloadRequest } from 'payload'
|
||||
|
||||
import { EmailField, TextField, useConfig, useTranslation } from '@payloadcms/ui'
|
||||
import { email, username } from 'payload/shared'
|
||||
import React from 'react'
|
||||
export type LoginFieldProps = {
|
||||
type: 'email' | 'emailOrUsername' | 'username'
|
||||
}
|
||||
export const LoginField: React.FC<LoginFieldProps> = ({ type }) => {
|
||||
const { t } = useTranslation()
|
||||
const config = useConfig()
|
||||
|
||||
if (type === 'email') {
|
||||
return (
|
||||
<EmailField
|
||||
autoComplete="email"
|
||||
label={t('general:email')}
|
||||
name="email"
|
||||
required
|
||||
validate={(value) =>
|
||||
email(value, {
|
||||
name: 'email',
|
||||
type: 'email',
|
||||
data: {},
|
||||
preferences: { fields: {} },
|
||||
req: { t } as PayloadRequest,
|
||||
required: true,
|
||||
siblingData: {},
|
||||
})
|
||||
}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
if (type === 'username') {
|
||||
return (
|
||||
<TextField
|
||||
label={t('authentication:username')}
|
||||
name="username"
|
||||
required
|
||||
validate={(value) =>
|
||||
username(value, {
|
||||
name: 'username',
|
||||
type: 'text',
|
||||
data: {},
|
||||
preferences: { fields: {} },
|
||||
req: {
|
||||
payload: {
|
||||
config,
|
||||
},
|
||||
t,
|
||||
} as PayloadRequest,
|
||||
required: true,
|
||||
siblingData: {},
|
||||
})
|
||||
}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
if (type === 'emailOrUsername') {
|
||||
return (
|
||||
<TextField
|
||||
label={t('authentication:emailOrUsername')}
|
||||
name="username"
|
||||
required
|
||||
validate={(value) => {
|
||||
const passesUsername = username(value, {
|
||||
name: 'username',
|
||||
type: 'text',
|
||||
data: {},
|
||||
preferences: { fields: {} },
|
||||
req: {
|
||||
payload: {
|
||||
config,
|
||||
},
|
||||
t,
|
||||
} as PayloadRequest,
|
||||
required: true,
|
||||
siblingData: {},
|
||||
})
|
||||
const passesEmail = email(value, {
|
||||
name: 'username',
|
||||
type: 'email',
|
||||
data: {},
|
||||
preferences: { fields: {} },
|
||||
req: {
|
||||
payload: {
|
||||
config,
|
||||
},
|
||||
t,
|
||||
} as PayloadRequest,
|
||||
required: true,
|
||||
siblingData: {},
|
||||
})
|
||||
|
||||
if (!passesEmail && !passesUsername) {
|
||||
return `${t('general:email')}: ${passesEmail} ${t('general:username')}: ${passesUsername}`
|
||||
}
|
||||
|
||||
return true
|
||||
}}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
return null
|
||||
}
|
||||
@@ -8,12 +8,17 @@ const Link = (LinkImport.default || LinkImport) as unknown as typeof LinkImport.
|
||||
|
||||
import type { FormState, PayloadRequest } from 'payload'
|
||||
|
||||
import { Form, FormSubmit, PasswordField, useConfig, useTranslation } from '@payloadcms/ui'
|
||||
import { password } from 'payload/shared'
|
||||
import {
|
||||
EmailField,
|
||||
Form,
|
||||
FormSubmit,
|
||||
PasswordField,
|
||||
TextField,
|
||||
useConfig,
|
||||
useTranslation,
|
||||
} from '@payloadcms/ui'
|
||||
import { email, password, text } from 'payload/shared'
|
||||
|
||||
import type { LoginFieldProps } from '../LoginField/index.js'
|
||||
|
||||
import { LoginField } from '../LoginField/index.js'
|
||||
import './index.scss'
|
||||
|
||||
export const LoginForm: React.FC<{
|
||||
@@ -31,17 +36,7 @@ export const LoginForm: React.FC<{
|
||||
} = config
|
||||
|
||||
const collectionConfig = config.collections?.find((collection) => collection?.slug === userSlug)
|
||||
const { auth: authOptions } = collectionConfig
|
||||
const loginWithUsername = authOptions.loginWithUsername
|
||||
const canLoginWithEmail =
|
||||
!authOptions.loginWithUsername || authOptions.loginWithUsername.allowEmailLogin
|
||||
const canLoginWithUsername = authOptions.loginWithUsername
|
||||
|
||||
const [loginType] = React.useState<LoginFieldProps['type']>(() => {
|
||||
if (canLoginWithEmail && canLoginWithUsername) return 'emailOrUsername'
|
||||
if (canLoginWithUsername) return 'username'
|
||||
return 'email'
|
||||
})
|
||||
const loginWithUsername = collectionConfig?.auth?.loginWithUsername
|
||||
|
||||
const { t } = useTranslation()
|
||||
|
||||
@@ -80,7 +75,47 @@ export const LoginForm: React.FC<{
|
||||
waitForAutocomplete
|
||||
>
|
||||
<div className={`${baseClass}__inputWrap`}>
|
||||
<LoginField type={loginType} />
|
||||
{loginWithUsername ? (
|
||||
<TextField
|
||||
label={t('authentication:username')}
|
||||
name="username"
|
||||
required
|
||||
validate={(value) =>
|
||||
text(value, {
|
||||
name: 'username',
|
||||
type: 'text',
|
||||
data: {},
|
||||
preferences: { fields: {} },
|
||||
req: {
|
||||
payload: {
|
||||
config,
|
||||
},
|
||||
t,
|
||||
} as PayloadRequest,
|
||||
required: true,
|
||||
siblingData: {},
|
||||
})
|
||||
}
|
||||
/>
|
||||
) : (
|
||||
<EmailField
|
||||
autoComplete="email"
|
||||
label={t('general:email')}
|
||||
name="email"
|
||||
required
|
||||
validate={(value) =>
|
||||
email(value, {
|
||||
name: 'email',
|
||||
type: 'email',
|
||||
data: {},
|
||||
preferences: { fields: {} },
|
||||
req: { t } as PayloadRequest,
|
||||
required: true,
|
||||
siblingData: {},
|
||||
})
|
||||
}
|
||||
/>
|
||||
)}
|
||||
<PasswordField
|
||||
autoComplete="off"
|
||||
label={t('general:password')}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "payload",
|
||||
"version": "3.0.0-beta.66",
|
||||
"version": "3.0.0-beta.65",
|
||||
"description": "Node, React, Headless CMS and Application Framework built on Next.js",
|
||||
"keywords": [
|
||||
"admin panel",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import type { Field } from '../../fields/config/types.js'
|
||||
|
||||
export const accountLockFields: Field[] = [
|
||||
export default [
|
||||
{
|
||||
name: 'loginAttempts',
|
||||
type: 'number',
|
||||
|
||||
@@ -7,7 +7,8 @@ const encryptKey: FieldHook = ({ req, value }) =>
|
||||
const decryptKey: FieldHook = ({ req, value }) =>
|
||||
value ? req.payload.decrypt(value as string) : undefined
|
||||
|
||||
export const apiKeyFields = [
|
||||
// eslint-disable-next-line no-restricted-exports
|
||||
export default [
|
||||
{
|
||||
name: 'enableAPIKey',
|
||||
type: 'checkbox',
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import type { Field } from '../../fields/config/types.js'
|
||||
|
||||
export const baseAuthFields: Field[] = [
|
||||
const baseAuthFields: Field[] = [
|
||||
{
|
||||
name: 'resetPasswordToken',
|
||||
type: 'text',
|
||||
@@ -22,3 +22,5 @@ export const baseAuthFields: Field[] = [
|
||||
hidden: true,
|
||||
},
|
||||
]
|
||||
|
||||
export default baseAuthFields
|
||||
|
||||
@@ -1,26 +0,0 @@
|
||||
import type { Field } from '../../fields/config/types.js'
|
||||
|
||||
import { email } from '../../fields/validations.js'
|
||||
|
||||
export const emailField = ({ required = true }: { required?: boolean }): Field => ({
|
||||
name: 'email',
|
||||
type: 'email',
|
||||
admin: {
|
||||
components: {
|
||||
Field: required ? () => null : undefined,
|
||||
},
|
||||
},
|
||||
hooks: {
|
||||
beforeChange: [
|
||||
({ value }) => {
|
||||
if (value) {
|
||||
return value.toLowerCase().trim()
|
||||
}
|
||||
},
|
||||
],
|
||||
},
|
||||
label: ({ t }) => t('general:email'),
|
||||
required,
|
||||
unique: true,
|
||||
validate: email,
|
||||
})
|
||||
38
packages/payload/src/auth/baseFields/loginField.ts
Normal file
38
packages/payload/src/auth/baseFields/loginField.ts
Normal file
@@ -0,0 +1,38 @@
|
||||
import type { Field } from '../../fields/config/types.js'
|
||||
|
||||
import { email } from '../../fields/validations.js'
|
||||
|
||||
export default (field: string): Field[] => {
|
||||
const formattedFields = [
|
||||
{
|
||||
name: 'email',
|
||||
type: 'email',
|
||||
admin: {
|
||||
components: {
|
||||
Field: field === 'username' ? undefined : () => null,
|
||||
},
|
||||
},
|
||||
label: ({ t }) => t('general:email'),
|
||||
required: true,
|
||||
unique: field === 'email' ? true : false,
|
||||
validate: email,
|
||||
},
|
||||
] as Field[]
|
||||
|
||||
if (field === 'username') {
|
||||
formattedFields.push({
|
||||
name: 'username',
|
||||
type: 'text',
|
||||
admin: {
|
||||
components: {
|
||||
Field: () => null,
|
||||
},
|
||||
},
|
||||
label: ({ t }) => t('authentication:username'),
|
||||
required: true,
|
||||
unique: true,
|
||||
} as Field)
|
||||
}
|
||||
|
||||
return formattedFields
|
||||
}
|
||||
@@ -1,26 +0,0 @@
|
||||
import type { Field } from '../../fields/config/types.js'
|
||||
|
||||
import { username } from '../../fields/validations.js'
|
||||
|
||||
export const usernameField: Field = {
|
||||
name: 'username',
|
||||
type: 'text',
|
||||
admin: {
|
||||
components: {
|
||||
Field: () => null,
|
||||
},
|
||||
},
|
||||
hooks: {
|
||||
beforeChange: [
|
||||
({ value }) => {
|
||||
if (value) {
|
||||
return value.toLowerCase().trim()
|
||||
}
|
||||
},
|
||||
],
|
||||
},
|
||||
label: ({ t }) => t('authentication:username'),
|
||||
required: true,
|
||||
unique: true,
|
||||
validate: username,
|
||||
}
|
||||
@@ -15,7 +15,7 @@ const autoRemoveVerificationToken: FieldHook = ({ data, operation, originalDoc,
|
||||
return value
|
||||
}
|
||||
|
||||
export const verificationFields: Field[] = [
|
||||
export default [
|
||||
{
|
||||
name: '_verified',
|
||||
type: 'checkbox',
|
||||
|
||||
@@ -1,44 +0,0 @@
|
||||
import type { Field } from '../fields/config/types.js'
|
||||
import type { IncomingAuthType } from './types.js'
|
||||
|
||||
import { accountLockFields } from './baseFields/accountLock.js'
|
||||
import { apiKeyFields } from './baseFields/apiKey.js'
|
||||
import { baseAuthFields } from './baseFields/auth.js'
|
||||
import { emailField } from './baseFields/email.js'
|
||||
import { usernameField } from './baseFields/username.js'
|
||||
import { verificationFields } from './baseFields/verification.js'
|
||||
|
||||
export const getBaseAuthFields = (authConfig: IncomingAuthType): Field[] => {
|
||||
const authFields: Field[] = []
|
||||
|
||||
if (authConfig.useAPIKey) {
|
||||
authFields.push(...apiKeyFields)
|
||||
}
|
||||
|
||||
if (!authConfig.disableLocalStrategy) {
|
||||
const emailFieldIndex = authFields.push(emailField({ required: true })) - 1
|
||||
|
||||
if (authConfig.loginWithUsername) {
|
||||
if (
|
||||
typeof authConfig.loginWithUsername === 'object' &&
|
||||
authConfig.loginWithUsername.requireEmail === false
|
||||
) {
|
||||
authFields[emailFieldIndex] = emailField({ required: false })
|
||||
}
|
||||
|
||||
authFields.push(usernameField)
|
||||
}
|
||||
|
||||
authFields.push(...baseAuthFields)
|
||||
|
||||
if (authConfig.verify) {
|
||||
authFields.push(...verificationFields)
|
||||
}
|
||||
|
||||
if (authConfig.maxLoginAttempts > 0) {
|
||||
authFields.push(...accountLockFields)
|
||||
}
|
||||
}
|
||||
|
||||
return authFields
|
||||
}
|
||||
@@ -1,5 +1,2 @@
|
||||
const isLocked = (date: number): boolean => {
|
||||
if (!date) return false
|
||||
return date > Date.now()
|
||||
}
|
||||
const isLocked = (date: number): boolean => !!(date && date > Date.now())
|
||||
export default isLocked
|
||||
|
||||
@@ -7,7 +7,7 @@ import type {
|
||||
Collection,
|
||||
} from '../../collections/config/types.js'
|
||||
import type { CollectionSlug } from '../../index.js'
|
||||
import type { PayloadRequest, Where } from '../../types/index.js'
|
||||
import type { PayloadRequest } from '../../types/index.js'
|
||||
|
||||
import { buildAfterOperation } from '../../collections/operations/utils.js'
|
||||
import { APIError } from '../../errors/index.js'
|
||||
@@ -30,20 +30,9 @@ export type Result = string
|
||||
export const forgotPasswordOperation = async <TSlug extends CollectionSlug>(
|
||||
incomingArgs: Arguments<TSlug>,
|
||||
): Promise<null | string> => {
|
||||
const loginWithUsername = incomingArgs.collection.config.auth.loginWithUsername
|
||||
const { data } = incomingArgs
|
||||
const loginWithUsername = incomingArgs.collection?.config?.auth?.loginWithUsername
|
||||
|
||||
const canLoginWithUsername = Boolean(loginWithUsername)
|
||||
const canLoginWithEmail = !loginWithUsername || loginWithUsername.allowEmailLogin
|
||||
|
||||
const sanitizedEmail =
|
||||
(canLoginWithEmail && (incomingArgs.data.email || '').toLowerCase().trim()) || null
|
||||
const sanitizedUsername =
|
||||
'username' in data && typeof data?.username === 'string'
|
||||
? data.username.toLowerCase().trim()
|
||||
: null
|
||||
|
||||
if (!sanitizedEmail && !sanitizedUsername) {
|
||||
if (!incomingArgs.data.email && !incomingArgs.data.username) {
|
||||
throw new APIError(
|
||||
`Missing ${loginWithUsername ? 'username' : 'email'}.`,
|
||||
httpStatus.BAD_REQUEST,
|
||||
@@ -96,33 +85,20 @@ export const forgotPasswordOperation = async <TSlug extends CollectionSlug>(
|
||||
resetPasswordToken?: string
|
||||
}
|
||||
|
||||
if (!sanitizedEmail && !sanitizedUsername) {
|
||||
if (!data.email && !data.username) {
|
||||
throw new APIError(
|
||||
`Missing ${loginWithUsername ? 'username' : 'email'}.`,
|
||||
httpStatus.BAD_REQUEST,
|
||||
)
|
||||
}
|
||||
|
||||
let whereConstraint: Where = {}
|
||||
|
||||
if (canLoginWithEmail && sanitizedEmail) {
|
||||
whereConstraint = {
|
||||
email: {
|
||||
equals: sanitizedEmail,
|
||||
},
|
||||
}
|
||||
} else if (canLoginWithUsername && sanitizedUsername) {
|
||||
whereConstraint = {
|
||||
username: {
|
||||
equals: sanitizedUsername,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
let user = await payload.db.findOne<UserDoc>({
|
||||
collection: collectionConfig.slug,
|
||||
req,
|
||||
where: whereConstraint,
|
||||
where:
|
||||
loginWithUsername && data?.username
|
||||
? { username: { equals: data.username } }
|
||||
: { email: { equals: data.email.toLowerCase() } },
|
||||
})
|
||||
|
||||
// We don't want to indicate specifically that an email was not found,
|
||||
@@ -140,7 +116,7 @@ export const forgotPasswordOperation = async <TSlug extends CollectionSlug>(
|
||||
req,
|
||||
})
|
||||
|
||||
if (!disableEmail && user.email) {
|
||||
if (!disableEmail) {
|
||||
const protocol = new URL(req.url).protocol // includes the final :
|
||||
const serverURL =
|
||||
config.serverURL !== null && config.serverURL !== ''
|
||||
@@ -173,7 +149,7 @@ export const forgotPasswordOperation = async <TSlug extends CollectionSlug>(
|
||||
from: `"${email.defaultFromName}" <${email.defaultFromAddress}>`,
|
||||
html,
|
||||
subject,
|
||||
to: user.email,
|
||||
to: loginWithUsername ? user.email : data.email,
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
@@ -1,26 +1,23 @@
|
||||
import type {
|
||||
AuthOperationsFromCollectionSlug,
|
||||
CollectionSlug,
|
||||
Payload,
|
||||
RequestContext,
|
||||
} from '../../../index.js'
|
||||
import type { CollectionSlug, Payload, RequestContext } from '../../../index.js'
|
||||
import type { PayloadRequest } from '../../../types/index.js'
|
||||
|
||||
import { APIError } from '../../../errors/index.js'
|
||||
import { createLocalReq } from '../../../utilities/createLocalReq.js'
|
||||
import { unlockOperation } from '../unlock.js'
|
||||
|
||||
export type Options<TSlug extends CollectionSlug> = {
|
||||
collection: TSlug
|
||||
export type Options<T extends CollectionSlug> = {
|
||||
collection: T
|
||||
context?: RequestContext
|
||||
data: AuthOperationsFromCollectionSlug<TSlug>['unlock']
|
||||
data: {
|
||||
email
|
||||
}
|
||||
overrideAccess: boolean
|
||||
req?: PayloadRequest
|
||||
}
|
||||
|
||||
async function localUnlock<TSlug extends CollectionSlug>(
|
||||
async function localUnlock<T extends CollectionSlug>(
|
||||
payload: Payload,
|
||||
options: Options<TSlug>,
|
||||
options: Options<T>,
|
||||
): Promise<boolean> {
|
||||
const { collection: collectionSlug, data, overrideAccess = true } = options
|
||||
|
||||
@@ -32,7 +29,7 @@ async function localUnlock<TSlug extends CollectionSlug>(
|
||||
)
|
||||
}
|
||||
|
||||
return unlockOperation<TSlug>({
|
||||
return unlockOperation({
|
||||
collection,
|
||||
data,
|
||||
overrideAccess,
|
||||
|
||||
@@ -6,7 +6,7 @@ import type {
|
||||
DataFromCollectionSlug,
|
||||
} from '../../collections/config/types.js'
|
||||
import type { CollectionSlug } from '../../index.js'
|
||||
import type { PayloadRequest, Where } from '../../types/index.js'
|
||||
import type { PayloadRequest } from '../../types/index.js'
|
||||
import type { User } from '../types.js'
|
||||
|
||||
import { buildAfterOperation } from '../../collections/operations/utils.js'
|
||||
@@ -82,47 +82,26 @@ export const loginOperation = async <TSlug extends CollectionSlug>(
|
||||
// /////////////////////////////////////
|
||||
|
||||
let user
|
||||
const loginWithUsername = collectionConfig?.auth?.loginWithUsername
|
||||
const { email: unsanitizedEmail, password } = data
|
||||
const loginWithUsername = collectionConfig.auth.loginWithUsername
|
||||
const username = 'username' in data && data.username
|
||||
|
||||
const sanitizedEmail =
|
||||
typeof unsanitizedEmail === 'string' ? unsanitizedEmail.toLowerCase().trim() : null
|
||||
const sanitizedUsername =
|
||||
'username' in data && typeof data?.username === 'string'
|
||||
? data.username.toLowerCase().trim()
|
||||
: null
|
||||
|
||||
const canLoginWithUsername = Boolean(loginWithUsername)
|
||||
const canLoginWithEmail = !loginWithUsername || loginWithUsername.allowEmailLogin
|
||||
|
||||
// cannot login with email, did not provide username
|
||||
if (!canLoginWithEmail && !sanitizedUsername) {
|
||||
if (loginWithUsername && !username) {
|
||||
throw new ValidationError({
|
||||
collection: collectionConfig.slug,
|
||||
errors: [{ field: 'username', message: req.i18n.t('validation:required') }],
|
||||
})
|
||||
}
|
||||
|
||||
// cannot login with username, did not provide email
|
||||
if (!canLoginWithUsername && !sanitizedEmail) {
|
||||
if (
|
||||
!loginWithUsername &&
|
||||
(typeof unsanitizedEmail !== 'string' || unsanitizedEmail.trim() === '')
|
||||
) {
|
||||
throw new ValidationError({
|
||||
collection: collectionConfig.slug,
|
||||
errors: [{ field: 'email', message: req.i18n.t('validation:required') }],
|
||||
})
|
||||
}
|
||||
|
||||
// can login with either email or username, did not provide either
|
||||
if (!sanitizedUsername && !sanitizedEmail) {
|
||||
throw new ValidationError({
|
||||
collection: collectionConfig.slug,
|
||||
errors: [
|
||||
{ field: 'email', message: req.i18n.t('validation:required') },
|
||||
{ field: 'username', message: req.i18n.t('validation:required') },
|
||||
],
|
||||
})
|
||||
}
|
||||
|
||||
// did not provide password for login
|
||||
if (typeof password !== 'string' || password.trim() === '') {
|
||||
throw new ValidationError({
|
||||
collection: collectionConfig.slug,
|
||||
@@ -130,59 +109,22 @@ export const loginOperation = async <TSlug extends CollectionSlug>(
|
||||
})
|
||||
}
|
||||
|
||||
let whereConstraint: Where = {}
|
||||
const emailConstraint: Where = {
|
||||
email: {
|
||||
equals: sanitizedEmail,
|
||||
},
|
||||
}
|
||||
const usernameConstraint: Where = {
|
||||
username: {
|
||||
equals: sanitizedUsername,
|
||||
},
|
||||
}
|
||||
|
||||
if (canLoginWithEmail && canLoginWithUsername && (sanitizedUsername || sanitizedEmail)) {
|
||||
if (sanitizedUsername) {
|
||||
whereConstraint = {
|
||||
or: [
|
||||
usernameConstraint,
|
||||
{
|
||||
email: {
|
||||
equals: sanitizedUsername,
|
||||
},
|
||||
},
|
||||
],
|
||||
}
|
||||
} else {
|
||||
whereConstraint = {
|
||||
or: [
|
||||
emailConstraint,
|
||||
{
|
||||
username: {
|
||||
equals: sanitizedEmail,
|
||||
},
|
||||
},
|
||||
],
|
||||
}
|
||||
}
|
||||
} else if (canLoginWithEmail && sanitizedEmail) {
|
||||
whereConstraint = emailConstraint
|
||||
} else if (canLoginWithUsername && sanitizedUsername) {
|
||||
whereConstraint = usernameConstraint
|
||||
}
|
||||
const email = unsanitizedEmail ? unsanitizedEmail.toLowerCase().trim() : null
|
||||
|
||||
user = await payload.db.findOne<any>({
|
||||
collection: collectionConfig.slug,
|
||||
req,
|
||||
where: whereConstraint,
|
||||
where:
|
||||
loginWithUsername && username
|
||||
? { username: { equals: username } }
|
||||
: { email: { equals: unsanitizedEmail.toLowerCase() } },
|
||||
})
|
||||
|
||||
if (!user || (args.collection.config.auth.verify && user._verified === false)) {
|
||||
throw new AuthenticationError(req.t, Boolean(canLoginWithUsername && sanitizedUsername))
|
||||
throw new AuthenticationError(req.t, loginWithUsername)
|
||||
}
|
||||
|
||||
if (user && isLocked(new Date(user.lockUntil).getTime())) {
|
||||
if (user && isLocked(user.lockUntil)) {
|
||||
throw new LockedAuth(req.t)
|
||||
}
|
||||
|
||||
@@ -218,7 +160,7 @@ export const loginOperation = async <TSlug extends CollectionSlug>(
|
||||
|
||||
const fieldsToSign = getFieldsToSign({
|
||||
collectionConfig,
|
||||
email: sanitizedEmail,
|
||||
email,
|
||||
user,
|
||||
})
|
||||
|
||||
|
||||
@@ -120,3 +120,5 @@ export const resetPasswordOperation = async (args: Arguments): Promise<Result> =
|
||||
throw error
|
||||
}
|
||||
}
|
||||
|
||||
export default resetPasswordOperation
|
||||
|
||||
@@ -1,11 +1,7 @@
|
||||
import httpStatus from 'http-status'
|
||||
|
||||
import type {
|
||||
AuthOperationsFromCollectionSlug,
|
||||
Collection,
|
||||
} from '../../collections/config/types.js'
|
||||
import type { CollectionSlug } from '../../index.js'
|
||||
import type { PayloadRequest, Where } from '../../types/index.js'
|
||||
import type { Collection } from '../../collections/config/types.js'
|
||||
import type { PayloadRequest } from '../../types/index.js'
|
||||
|
||||
import { APIError } from '../../errors/index.js'
|
||||
import { commitTransaction } from '../../utilities/commitTransaction.js'
|
||||
@@ -14,16 +10,20 @@ import { killTransaction } from '../../utilities/killTransaction.js'
|
||||
import executeAccess from '../executeAccess.js'
|
||||
import { resetLoginAttempts } from '../strategies/local/resetLoginAttempts.js'
|
||||
|
||||
export type Arguments<TSlug extends CollectionSlug> = {
|
||||
export type Args = {
|
||||
collection: Collection
|
||||
data: AuthOperationsFromCollectionSlug<TSlug>['unlock']
|
||||
data: {
|
||||
email: string
|
||||
}
|
||||
overrideAccess?: boolean
|
||||
req: PayloadRequest
|
||||
}
|
||||
|
||||
export const unlockOperation = async <TSlug extends CollectionSlug>(
|
||||
args: Arguments<TSlug>,
|
||||
): Promise<boolean> => {
|
||||
export const unlockOperation = async (args: Args): Promise<boolean> => {
|
||||
if (!Object.prototype.hasOwnProperty.call(args.data, 'email')) {
|
||||
throw new APIError('Missing email.', httpStatus.BAD_REQUEST)
|
||||
}
|
||||
|
||||
const {
|
||||
collection: { config: collectionConfig },
|
||||
overrideAccess,
|
||||
@@ -31,25 +31,6 @@ export const unlockOperation = async <TSlug extends CollectionSlug>(
|
||||
req,
|
||||
} = args
|
||||
|
||||
const loginWithUsername = collectionConfig.auth.loginWithUsername
|
||||
const canLoginWithUsername = Boolean(loginWithUsername)
|
||||
const canLoginWithEmail = !loginWithUsername || loginWithUsername.allowEmailLogin
|
||||
|
||||
const sanitizedEmail = canLoginWithEmail && (args.data?.email || '').toLowerCase().trim()
|
||||
const sanitizedUsername =
|
||||
(canLoginWithUsername &&
|
||||
'username' in args.data &&
|
||||
typeof args.data.username === 'string' &&
|
||||
args.data.username.toLowerCase().trim()) ||
|
||||
null
|
||||
|
||||
if (!sanitizedEmail && !sanitizedUsername) {
|
||||
throw new APIError(
|
||||
`Missing ${collectionConfig.auth.loginWithUsername ? 'username' : 'email'}.`,
|
||||
httpStatus.BAD_REQUEST,
|
||||
)
|
||||
}
|
||||
|
||||
try {
|
||||
const shouldCommit = await initTransaction(req)
|
||||
|
||||
@@ -61,31 +42,23 @@ export const unlockOperation = async <TSlug extends CollectionSlug>(
|
||||
await executeAccess({ req }, collectionConfig.access.unlock)
|
||||
}
|
||||
|
||||
const options = { ...args }
|
||||
|
||||
const { data } = options
|
||||
|
||||
// /////////////////////////////////////
|
||||
// Unlock
|
||||
// /////////////////////////////////////
|
||||
|
||||
let whereConstraint: Where = {}
|
||||
|
||||
if (canLoginWithEmail && sanitizedEmail) {
|
||||
whereConstraint = {
|
||||
email: {
|
||||
equals: sanitizedEmail,
|
||||
},
|
||||
}
|
||||
} else if (canLoginWithUsername && sanitizedUsername) {
|
||||
whereConstraint = {
|
||||
username: {
|
||||
equals: sanitizedUsername,
|
||||
},
|
||||
}
|
||||
if (!data.email) {
|
||||
throw new APIError('Missing email.', httpStatus.BAD_REQUEST)
|
||||
}
|
||||
|
||||
const user = await req.payload.db.findOne({
|
||||
collection: collectionConfig.slug,
|
||||
locale,
|
||||
req,
|
||||
where: whereConstraint,
|
||||
where: { email: { equals: data.email.toLowerCase() } },
|
||||
})
|
||||
|
||||
let result
|
||||
@@ -110,3 +83,5 @@ export const unlockOperation = async <TSlug extends CollectionSlug>(
|
||||
throw error
|
||||
}
|
||||
}
|
||||
|
||||
export default unlockOperation
|
||||
|
||||
@@ -118,11 +118,6 @@ export type AuthStrategy = {
|
||||
name: string
|
||||
}
|
||||
|
||||
export type LoginWithUsernameOptions = {
|
||||
allowEmailLogin?: boolean
|
||||
requireEmail?: boolean
|
||||
}
|
||||
|
||||
export interface IncomingAuthType {
|
||||
cookies?: {
|
||||
domain?: string
|
||||
@@ -136,7 +131,7 @@ export interface IncomingAuthType {
|
||||
generateEmailSubject?: GenerateForgotPasswordEmailSubject
|
||||
}
|
||||
lockTime?: number
|
||||
loginWithUsername?: LoginWithUsernameOptions | boolean
|
||||
loginWithUsername?: boolean
|
||||
maxLoginAttempts?: number
|
||||
removeTokenFromResponses?: true
|
||||
strategies?: AuthStrategy[]
|
||||
@@ -155,13 +150,11 @@ export type VerifyConfig = {
|
||||
generateEmailSubject?: GenerateVerifyEmailSubject
|
||||
}
|
||||
|
||||
export interface Auth
|
||||
extends Omit<DeepRequired<IncomingAuthType>, 'forgotPassword' | 'loginWithUsername' | 'verify'> {
|
||||
export interface Auth extends Omit<DeepRequired<IncomingAuthType>, 'forgotPassword' | 'verify'> {
|
||||
forgotPassword?: {
|
||||
generateEmailHTML?: GenerateForgotPasswordEmailHTML
|
||||
generateEmailSubject?: GenerateForgotPasswordEmailSubject
|
||||
}
|
||||
loginWithUsername: LoginWithUsernameOptions | false
|
||||
verify?: VerifyConfig | boolean
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
import type { LoginWithUsernameOptions } from '../../auth/types.js'
|
||||
|
||||
import defaultAccess from '../../auth/defaultAccess.js'
|
||||
|
||||
export const defaults = {
|
||||
@@ -61,8 +59,3 @@ export const authDefaults = {
|
||||
tokenExpiration: 7200,
|
||||
verify: false,
|
||||
}
|
||||
|
||||
export const loginWithUsernameDefaults: LoginWithUsernameOptions = {
|
||||
allowEmailLogin: false,
|
||||
requireEmail: false,
|
||||
}
|
||||
|
||||
@@ -3,7 +3,11 @@ import merge from 'deepmerge'
|
||||
import type { Config, SanitizedConfig } from '../../config/types.js'
|
||||
import type { CollectionConfig, SanitizedCollectionConfig } from './types.js'
|
||||
|
||||
import { getBaseAuthFields } from '../../auth/getAuthFields.js'
|
||||
import baseAccountLockFields from '../../auth/baseFields/accountLock.js'
|
||||
import baseAPIKeyFields from '../../auth/baseFields/apiKey.js'
|
||||
import baseAuthFields from '../../auth/baseFields/auth.js'
|
||||
import baseLoginField from '../../auth/baseFields/loginField.js'
|
||||
import baseVerificationFields from '../../auth/baseFields/verification.js'
|
||||
import { TimestampsRequired } from '../../errors/TimestampsRequired.js'
|
||||
import { sanitizeFields } from '../../fields/config/sanitize.js'
|
||||
import { fieldAffectsData } from '../../fields/config/types.js'
|
||||
@@ -13,7 +17,7 @@ import { formatLabels } from '../../utilities/formatLabels.js'
|
||||
import { isPlainObject } from '../../utilities/isPlainObject.js'
|
||||
import baseVersionFields from '../../versions/baseFields.js'
|
||||
import { versionDefaults } from '../../versions/defaults.js'
|
||||
import { authDefaults, defaults, loginWithUsernameDefaults } from './defaults.js'
|
||||
import { authDefaults, defaults } from './defaults.js'
|
||||
|
||||
export const sanitizeCollection = async (
|
||||
config: Config,
|
||||
@@ -137,8 +141,27 @@ export const sanitizeCollection = async (
|
||||
isMergeableObject: isPlainObject,
|
||||
})
|
||||
|
||||
if (!sanitized.auth.disableLocalStrategy && sanitized.auth.verify === true) {
|
||||
sanitized.auth.verify = {}
|
||||
let authFields = []
|
||||
|
||||
if (sanitized.auth.useAPIKey) {
|
||||
authFields = authFields.concat(baseAPIKeyFields)
|
||||
}
|
||||
|
||||
if (!sanitized.auth.disableLocalStrategy) {
|
||||
const loginField = sanitized.auth.loginWithUsername ? 'username' : 'email'
|
||||
|
||||
authFields = authFields.concat(baseLoginField(loginField))
|
||||
|
||||
authFields = authFields.concat(baseAuthFields)
|
||||
|
||||
if (sanitized.auth.verify) {
|
||||
if (sanitized.auth.verify === true) sanitized.auth.verify = {}
|
||||
authFields = authFields.concat(baseVerificationFields)
|
||||
}
|
||||
|
||||
if (sanitized.auth.maxLoginAttempts > 0) {
|
||||
authFields = authFields.concat(baseAccountLockFields)
|
||||
}
|
||||
}
|
||||
|
||||
// disable duplicate for auth enabled collections by default
|
||||
@@ -148,16 +171,7 @@ export const sanitizeCollection = async (
|
||||
sanitized.auth.strategies = []
|
||||
}
|
||||
|
||||
sanitized.auth.loginWithUsername = sanitized.auth.loginWithUsername
|
||||
? merge(
|
||||
loginWithUsernameDefaults,
|
||||
typeof sanitized.auth.loginWithUsername === 'boolean'
|
||||
? {}
|
||||
: sanitized.auth.loginWithUsername,
|
||||
)
|
||||
: false
|
||||
|
||||
sanitized.fields = mergeBaseFields(sanitized.fields, getBaseAuthFields(sanitized.auth))
|
||||
sanitized.fields = mergeBaseFields(sanitized.fields, authFields)
|
||||
}
|
||||
|
||||
return sanitized as SanitizedCollectionConfig
|
||||
|
||||
@@ -92,13 +92,7 @@ const collectionSchema = joi.object().keys({
|
||||
generateEmailSubject: joi.func(),
|
||||
}),
|
||||
lockTime: joi.number(),
|
||||
loginWithUsername: joi.alternatives().try(
|
||||
joi.boolean(),
|
||||
joi.object().keys({
|
||||
allowEmailLogin: joi.boolean(),
|
||||
requireEmail: joi.boolean(),
|
||||
}),
|
||||
),
|
||||
loginWithUsername: joi.boolean(),
|
||||
maxLoginAttempts: joi.number(),
|
||||
removeTokenFromResponses: joi.boolean().valid(true),
|
||||
strategies: joi.array().items(
|
||||
|
||||
@@ -214,6 +214,10 @@ export const createOperation = async <TSlug extends CollectionSlug>(
|
||||
let doc
|
||||
|
||||
if (collectionConfig.auth && !collectionConfig.auth.disableLocalStrategy) {
|
||||
if (data.email) {
|
||||
resultWithLocales.email = (data.email as string).toLowerCase()
|
||||
}
|
||||
|
||||
if (collectionConfig.auth.verify) {
|
||||
resultWithLocales._verified = Boolean(resultWithLocales._verified) || false
|
||||
resultWithLocales._verificationToken = crypto.randomBytes(20).toString('hex')
|
||||
@@ -256,7 +260,7 @@ export const createOperation = async <TSlug extends CollectionSlug>(
|
||||
// Send verification email if applicable
|
||||
// /////////////////////////////////////
|
||||
|
||||
if (collectionConfig.auth && collectionConfig.auth.verify && result.email) {
|
||||
if (collectionConfig.auth && collectionConfig.auth.verify) {
|
||||
await sendVerificationEmail({
|
||||
collection: { config: collectionConfig },
|
||||
config: payload.config,
|
||||
|
||||
@@ -126,31 +126,6 @@ export const email: Validate<string, unknown, unknown, EmailField> = (
|
||||
return true
|
||||
}
|
||||
|
||||
export const username: Validate<string, unknown, unknown, TextField> = (
|
||||
value,
|
||||
{
|
||||
req: {
|
||||
payload: { config },
|
||||
t,
|
||||
},
|
||||
required,
|
||||
},
|
||||
) => {
|
||||
let maxLength: number
|
||||
|
||||
if (typeof config?.defaultMaxTextLength === 'number') maxLength = config.defaultMaxTextLength
|
||||
|
||||
if (value && maxLength && value.length > maxLength) {
|
||||
return t('validation:shorterThanMax', { maxLength })
|
||||
}
|
||||
|
||||
if ((value && !/^[\w.-]+$/.test(value)) || (!value && required)) {
|
||||
return t('validation:username')
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
export const textarea: Validate<string, unknown, unknown, TextareaField> = (
|
||||
value,
|
||||
{
|
||||
|
||||
@@ -74,14 +74,12 @@ export interface GeneratedTypes {
|
||||
login: {
|
||||
email: string
|
||||
password: string
|
||||
username?: string
|
||||
}
|
||||
registerFirstUser: {
|
||||
email: string
|
||||
password: string
|
||||
}
|
||||
unlock: {
|
||||
email: string
|
||||
}
|
||||
}
|
||||
}
|
||||
collectionsUntyped: {
|
||||
@@ -351,7 +349,7 @@ export class BasePayload {
|
||||
options: UnlockOptions<TSlug>,
|
||||
): Promise<boolean> => {
|
||||
const { unlock } = localOperations.auth
|
||||
return unlock<TSlug>(this, options)
|
||||
return unlock(this, options)
|
||||
}
|
||||
|
||||
updateGlobal = async <TSlug extends GlobalSlug>(
|
||||
@@ -710,11 +708,11 @@ export type {
|
||||
AfterErrorHook as CollectionAfterErrorHook,
|
||||
AfterForgotPasswordHook as CollectionAfterForgotPasswordHook,
|
||||
AfterLoginHook as CollectionAfterLoginHook,
|
||||
AfterLogoutHook as CollectionAfterLogoutHook,
|
||||
AfterMeHook as CollectionAfterMeHook,
|
||||
AfterLogoutHook,
|
||||
AfterMeHook,
|
||||
AfterOperationHook as CollectionAfterOperationHook,
|
||||
AfterReadHook as CollectionAfterReadHook,
|
||||
AfterRefreshHook as CollectionAfterRefreshHook,
|
||||
AfterRefreshHook,
|
||||
AuthCollection,
|
||||
AuthOperationsFromCollectionSlug,
|
||||
BeforeChangeHook as CollectionBeforeChangeHook,
|
||||
|
||||
@@ -3,7 +3,6 @@ import type { JSONSchema4, JSONSchema4TypeName } from 'json-schema'
|
||||
import pluralize from 'pluralize'
|
||||
const { singular } = pluralize
|
||||
|
||||
import type { Auth } from '../auth/types.js'
|
||||
import type { SanitizedCollectionConfig } from '../collections/config/types.js'
|
||||
import type { SanitizedConfig } from '../config/types.js'
|
||||
import type { Field, FieldAffectingData, Option } from '../fields/config/types.js'
|
||||
@@ -608,69 +607,60 @@ export function entityToJSONSchema(
|
||||
}
|
||||
}
|
||||
|
||||
const fieldType: JSONSchema4 = {
|
||||
type: 'string',
|
||||
required: false,
|
||||
}
|
||||
const generateAuthFieldTypes = (
|
||||
loginWithUsername: Auth['loginWithUsername'],
|
||||
withPassword = false,
|
||||
): JSONSchema4 => {
|
||||
const passwordField = {
|
||||
password: fieldType,
|
||||
function generateOperationJSONSchema(
|
||||
config: SanitizedCollectionConfig,
|
||||
operation: 'forgotPassword' | 'login' | 'registerFirstUser',
|
||||
): JSONSchema4 {
|
||||
const usernameLogin = config.auth?.loginWithUsername
|
||||
const fieldType: JSONSchema4 = {
|
||||
type: 'string',
|
||||
}
|
||||
|
||||
if (loginWithUsername) {
|
||||
if (loginWithUsername.allowEmailLogin) {
|
||||
return {
|
||||
additionalProperties: false,
|
||||
oneOf: [
|
||||
{
|
||||
additionalProperties: false,
|
||||
properties: { email: fieldType, ...(withPassword ? { password: fieldType } : {}) },
|
||||
required: ['email', ...(withPassword ? ['password'] : [])],
|
||||
},
|
||||
{
|
||||
additionalProperties: false,
|
||||
properties: { username: fieldType, ...(withPassword ? { password: fieldType } : {}) },
|
||||
required: ['username', ...(withPassword ? ['password'] : [])],
|
||||
},
|
||||
],
|
||||
let properties: JSONSchema4['properties'] = {}
|
||||
switch (operation) {
|
||||
case 'login': {
|
||||
properties = {
|
||||
password: fieldType,
|
||||
[usernameLogin ? 'username' : 'email']: fieldType,
|
||||
}
|
||||
break
|
||||
}
|
||||
|
||||
return {
|
||||
additionalProperties: false,
|
||||
properties: {
|
||||
username: fieldType,
|
||||
...(withPassword ? { password: fieldType } : {}),
|
||||
},
|
||||
required: ['username', ...(withPassword ? ['password'] : [])],
|
||||
case 'forgotPassword': {
|
||||
properties = {
|
||||
[usernameLogin ? 'username' : 'email']: fieldType,
|
||||
}
|
||||
break
|
||||
}
|
||||
case 'registerFirstUser': {
|
||||
properties = {
|
||||
email: fieldType,
|
||||
password: fieldType,
|
||||
}
|
||||
if (usernameLogin) properties.username = fieldType
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
additionalProperties: false,
|
||||
properties: {
|
||||
email: fieldType,
|
||||
...(withPassword ? { password: fieldType } : {}),
|
||||
},
|
||||
required: ['email', ...(withPassword ? ['password'] : [])],
|
||||
properties,
|
||||
required: Object.keys(properties),
|
||||
}
|
||||
}
|
||||
|
||||
export function authCollectionToOperationsJSONSchema(
|
||||
config: SanitizedCollectionConfig,
|
||||
): JSONSchema4 {
|
||||
const loginWithUsername = config.auth?.loginWithUsername
|
||||
const generatedFields: JSONSchema4 = generateAuthFieldTypes(loginWithUsername)
|
||||
const generatedFieldsWithPassword: JSONSchema4 = generateAuthFieldTypes(loginWithUsername, true)
|
||||
|
||||
const properties: JSONSchema4['properties'] = {
|
||||
forgotPassword: generatedFields,
|
||||
login: generatedFieldsWithPassword,
|
||||
registerFirstUser: generatedFieldsWithPassword,
|
||||
unlock: generatedFields,
|
||||
const properties = {
|
||||
forgotPassword: {
|
||||
...generateOperationJSONSchema(config, 'forgotPassword'),
|
||||
},
|
||||
login: {
|
||||
...generateOperationJSONSchema(config, 'login'),
|
||||
},
|
||||
registerFirstUser: {
|
||||
...generateOperationJSONSchema(config, 'registerFirstUser'),
|
||||
},
|
||||
}
|
||||
|
||||
return {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@payloadcms/plugin-cloud-storage",
|
||||
"version": "3.0.0-beta.66",
|
||||
"version": "3.0.0-beta.65",
|
||||
"description": "The official cloud storage plugin for Payload CMS",
|
||||
"homepage": "https://payloadcms.com",
|
||||
"repository": {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@payloadcms/plugin-cloud",
|
||||
"version": "3.0.0-beta.66",
|
||||
"version": "3.0.0-beta.65",
|
||||
"description": "The official Payload Cloud plugin",
|
||||
"homepage": "https://payloadcms.com",
|
||||
"repository": {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@payloadcms/plugin-form-builder",
|
||||
"version": "3.0.0-beta.66",
|
||||
"version": "3.0.0-beta.65",
|
||||
"description": "Form builder plugin for Payload CMS",
|
||||
"keywords": [
|
||||
"payload",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@payloadcms/plugin-nested-docs",
|
||||
"version": "3.0.0-beta.66",
|
||||
"version": "3.0.0-beta.65",
|
||||
"description": "The official Nested Docs plugin for Payload",
|
||||
"homepage": "https://payloadcms.com",
|
||||
"repository": {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@payloadcms/plugin-redirects",
|
||||
"version": "3.0.0-beta.66",
|
||||
"version": "3.0.0-beta.65",
|
||||
"description": "Redirects plugin for Payload",
|
||||
"keywords": [
|
||||
"payload",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@payloadcms/plugin-relationship-object-ids",
|
||||
"version": "3.0.0-beta.66",
|
||||
"version": "3.0.0-beta.65",
|
||||
"description": "A Payload plugin to store all relationship IDs as ObjectIDs",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@payloadcms/plugin-search",
|
||||
"version": "3.0.0-beta.66",
|
||||
"version": "3.0.0-beta.65",
|
||||
"description": "Search plugin for Payload",
|
||||
"keywords": [
|
||||
"payload",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@payloadcms/plugin-seo",
|
||||
"version": "3.0.0-beta.66",
|
||||
"version": "3.0.0-beta.65",
|
||||
"description": "SEO plugin for Payload",
|
||||
"keywords": [
|
||||
"payload",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@payloadcms/plugin-stripe",
|
||||
"version": "3.0.0-beta.66",
|
||||
"version": "3.0.0-beta.65",
|
||||
"description": "Stripe plugin for Payload",
|
||||
"keywords": [
|
||||
"payload",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@payloadcms/richtext-lexical",
|
||||
"version": "3.0.0-beta.66",
|
||||
"version": "3.0.0-beta.65",
|
||||
"description": "The officially supported Lexical richtext adapter for Payload",
|
||||
"homepage": "https://payloadcms.com",
|
||||
"repository": {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@payloadcms/richtext-slate",
|
||||
"version": "3.0.0-beta.66",
|
||||
"version": "3.0.0-beta.65",
|
||||
"description": "The officially supported Slate richtext adapter for Payload",
|
||||
"homepage": "https://payloadcms.com",
|
||||
"repository": {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@payloadcms/storage-azure",
|
||||
"version": "3.0.0-beta.66",
|
||||
"version": "3.0.0-beta.65",
|
||||
"description": "Payload storage adapter for Azure Blob Storage",
|
||||
"homepage": "https://payloadcms.com",
|
||||
"repository": {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@payloadcms/storage-gcs",
|
||||
"version": "3.0.0-beta.66",
|
||||
"version": "3.0.0-beta.65",
|
||||
"description": "Payload storage adapter for Google Cloud Storage",
|
||||
"homepage": "https://payloadcms.com",
|
||||
"repository": {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@payloadcms/storage-s3",
|
||||
"version": "3.0.0-beta.66",
|
||||
"version": "3.0.0-beta.65",
|
||||
"description": "Payload storage adapter for Amazon S3",
|
||||
"homepage": "https://payloadcms.com",
|
||||
"repository": {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@payloadcms/storage-uploadthing",
|
||||
"version": "3.0.0-beta.66",
|
||||
"version": "3.0.0-beta.65",
|
||||
"description": "Payload storage adapter for uploadthing",
|
||||
"homepage": "https://payloadcms.com",
|
||||
"repository": {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@payloadcms/storage-vercel-blob",
|
||||
"version": "3.0.0-beta.66",
|
||||
"version": "3.0.0-beta.65",
|
||||
"description": "Payload storage adapter for Vercel Blob Storage",
|
||||
"homepage": "https://payloadcms.com",
|
||||
"repository": {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@payloadcms/translations",
|
||||
"version": "3.0.0-beta.66",
|
||||
"version": "3.0.0-beta.65",
|
||||
"homepage": "https://payloadcms.com",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
|
||||
@@ -30,12 +30,8 @@ export async function translateText(text: string, targetLang: string) {
|
||||
})
|
||||
try {
|
||||
const data = await response.json()
|
||||
if (data?.choices?.[0]) {
|
||||
console.log(' Old text:', text, 'New text:', data.choices[0].message.content.trim())
|
||||
return data.choices[0].message.content.trim()
|
||||
} else {
|
||||
console.log(`Could not translate: ${text} in lang: ${targetLang}`)
|
||||
}
|
||||
console.log(' Old text:', text, 'New text:', data.choices[0].message.content.trim())
|
||||
return data.choices[0].message.content.trim()
|
||||
} catch (e) {
|
||||
console.error('Error translating:', text, 'to', targetLang, 'response', response, '. Error:', e)
|
||||
throw e
|
||||
|
||||
@@ -21,7 +21,6 @@ export const clientTranslationKeys = createClientTranslationKeys([
|
||||
'authentication:createFirstUser',
|
||||
'authentication:emailNotValid',
|
||||
'authentication:usernameNotValid',
|
||||
'authentication:emailOrUsername',
|
||||
'authentication:emailSent',
|
||||
'authentication:emailVerified',
|
||||
'authentication:enableAPIKey',
|
||||
@@ -231,7 +230,6 @@ export const clientTranslationKeys = createClientTranslationKeys([
|
||||
'general:true',
|
||||
'general:users',
|
||||
'general:user',
|
||||
'general:username',
|
||||
'general:unauthorized',
|
||||
'general:unsavedChangesDuplicate',
|
||||
'general:untitled',
|
||||
@@ -283,7 +281,6 @@ export const clientTranslationKeys = createClientTranslationKeys([
|
||||
'validation:required',
|
||||
'validation:requiresAtLeast',
|
||||
'validation:shorterThanMax',
|
||||
'validation:username',
|
||||
|
||||
'version:aboutToPublishSelection',
|
||||
'version:aboutToRestore',
|
||||
|
||||
@@ -18,7 +18,6 @@ export const arTranslations: DefaultTranslationsObject = {
|
||||
confirmPassword: 'تأكيد كلمة المرور',
|
||||
createFirstUser: 'إنشاء المستخدم الأوّل',
|
||||
emailNotValid: 'البريد الإلكتروني غير صالح',
|
||||
emailOrUsername: 'البريد الإلكتروني أو اسم المستخدم',
|
||||
emailSent: 'تمّ ارسال البريد الإلكتروني',
|
||||
emailVerified: 'تم التحقق من البريد الإلكتروني بنجاح.',
|
||||
enableAPIKey: 'تفعيل مفتاح API',
|
||||
@@ -295,7 +294,6 @@ export const arTranslations: DefaultTranslationsObject = {
|
||||
updating: 'جار التحديث',
|
||||
uploading: 'جار الرفع',
|
||||
user: 'المستخدم',
|
||||
username: 'اسم المستخدم',
|
||||
users: 'المستخدمين',
|
||||
value: 'القيمة',
|
||||
welcome: 'مرحبًا',
|
||||
@@ -358,8 +356,6 @@ export const arTranslations: DefaultTranslationsObject = {
|
||||
requiresTwoNumbers: 'هذا الحقل يتطلب رقمين.',
|
||||
shorterThanMax: 'يجب أن تكون هذه القيمة أقصر من الحد الأقصى للطول الذي هو {{maxLength}} أحرف.',
|
||||
trueOrFalse: 'يمكن أن يكون هذا الحقل مساويًا فقط للقيمتين صحيح أو خطأ.',
|
||||
username:
|
||||
'يرجى إدخال اسم مستخدم صالح. يمكن أن يحتوي على أحرف، أرقام، شرطات، فواصل وشرطات سفلية.',
|
||||
validUploadID: 'هذا الحقل ليس معرّف تحميل صالح.',
|
||||
},
|
||||
version: {
|
||||
|
||||
@@ -18,7 +18,6 @@ export const azTranslations: DefaultTranslationsObject = {
|
||||
confirmPassword: 'Şifrəni təsdiq et',
|
||||
createFirstUser: 'İlk istifadəçini yaradın',
|
||||
emailNotValid: 'Təqdim olunan e-poçt etibarlı deyil',
|
||||
emailOrUsername: 'E-poçt və ya İstifadəçi adı',
|
||||
emailSent: 'E-poçt göndərildi',
|
||||
emailVerified: 'Email uğurla təsdiqləndi.',
|
||||
enableAPIKey: 'API açarını aktivləşdir',
|
||||
@@ -298,7 +297,6 @@ export const azTranslations: DefaultTranslationsObject = {
|
||||
updating: 'Yenilənir',
|
||||
uploading: 'Yüklənir',
|
||||
user: 'İstifadəçi',
|
||||
username: 'İstifadəçi adı',
|
||||
users: 'İstifadəçilər',
|
||||
value: 'Dəyər',
|
||||
welcome: 'Xoş gəldiniz',
|
||||
@@ -363,8 +361,6 @@ export const azTranslations: DefaultTranslationsObject = {
|
||||
requiresTwoNumbers: 'Bu sahə iki nömrə tələb edir.',
|
||||
shorterThanMax: 'Bu dəyər {{maxLength}} simvoldan qısa olmalıdır.',
|
||||
trueOrFalse: 'Bu sahə yalnız doğru və ya yanlış ola bilər.',
|
||||
username:
|
||||
'Zəhmət olmasa, etibarlı bir istifadəçi adı daxil edin. Hərflər, rəqəmlər, tire, nöqtə və alt xəttlər ola bilər.',
|
||||
validUploadID: 'Bu sahə doğru yükləmə ID-si deyil.',
|
||||
},
|
||||
version: {
|
||||
|
||||
@@ -18,7 +18,6 @@ export const bgTranslations: DefaultTranslationsObject = {
|
||||
confirmPassword: 'Потвърди парола',
|
||||
createFirstUser: 'Създай първи потребител',
|
||||
emailNotValid: 'Даденият имейл не е валиден',
|
||||
emailOrUsername: 'Имейл или Потребителско име',
|
||||
emailSent: 'Имейлът е изпратен',
|
||||
emailVerified: 'Успешно потвърден имейл.',
|
||||
enableAPIKey: 'Активирай API ключ',
|
||||
@@ -296,7 +295,6 @@ export const bgTranslations: DefaultTranslationsObject = {
|
||||
updating: 'Обновява се',
|
||||
uploading: 'Качва се',
|
||||
user: 'Потребител',
|
||||
username: 'Потребителско име',
|
||||
users: 'Потребители',
|
||||
value: 'Стойност',
|
||||
welcome: 'Добре дошъл',
|
||||
@@ -363,8 +361,6 @@ export const bgTranslations: DefaultTranslationsObject = {
|
||||
shorterThanMax:
|
||||
'Тази стойност трябва да е по-малка от максималната стойност от {{maxLength}} символа.',
|
||||
trueOrFalse: 'Това поле може да бъде само "true" или "false".',
|
||||
username:
|
||||
'Моля, въведете валидно потребителско име. Може да съдържа букви, цифри, тирета, точки и долни черти.',
|
||||
validUploadID: 'Това поле не е валиден идентификатор на качването.',
|
||||
},
|
||||
version: {
|
||||
|
||||
@@ -18,7 +18,6 @@ export const csTranslations: DefaultTranslationsObject = {
|
||||
confirmPassword: 'Potvrdit heslo',
|
||||
createFirstUser: 'Vytvořit prvního uživatele',
|
||||
emailNotValid: 'Zadaný email není platný',
|
||||
emailOrUsername: 'E-mail nebo Uživatelské jméno',
|
||||
emailSent: 'Email odeslán',
|
||||
emailVerified: 'E-mail úspěšně ověřen.',
|
||||
enableAPIKey: 'Povolit API klíč',
|
||||
@@ -296,7 +295,6 @@ export const csTranslations: DefaultTranslationsObject = {
|
||||
updating: 'Aktualizace',
|
||||
uploading: 'Nahrávání',
|
||||
user: 'Uživatel',
|
||||
username: 'Uživatelské jméno',
|
||||
users: 'Uživatelé',
|
||||
value: 'Hodnota',
|
||||
welcome: 'Vítejte',
|
||||
@@ -361,8 +359,6 @@ export const csTranslations: DefaultTranslationsObject = {
|
||||
requiresTwoNumbers: 'Toto pole vyžaduje dvě čísla.',
|
||||
shorterThanMax: 'Tato hodnota musí být kratší než maximální délka {{maxLength}} znaků.',
|
||||
trueOrFalse: 'Toto pole může být rovno pouze true nebo false.',
|
||||
username:
|
||||
'Prosím, zadejte platné uživatelské jméno. Může obsahovat písmena, čísla, pomlčky, tečky a podtržítka.',
|
||||
validUploadID: 'Toto pole není platné ID pro odeslání.',
|
||||
},
|
||||
version: {
|
||||
|
||||
@@ -18,7 +18,6 @@ export const deTranslations: DefaultTranslationsObject = {
|
||||
confirmPassword: 'Passwort bestätigen',
|
||||
createFirstUser: 'Ersten Benutzer erstellen',
|
||||
emailNotValid: 'Die angegebene E-Mail-Adresse ist ungültig',
|
||||
emailOrUsername: 'E-Mail oder Benutzername',
|
||||
emailSent: 'E-Mail verschickt',
|
||||
emailVerified: 'E-Mail erfolgreich verifiziert.',
|
||||
enableAPIKey: 'API-Key aktivieren',
|
||||
@@ -302,7 +301,6 @@ export const deTranslations: DefaultTranslationsObject = {
|
||||
updating: 'Aktualisierung',
|
||||
uploading: 'Hochladen',
|
||||
user: 'Benutzer',
|
||||
username: 'Benutzername',
|
||||
users: 'Benutzer',
|
||||
value: 'Wert',
|
||||
welcome: 'Willkommen',
|
||||
@@ -367,8 +365,6 @@ export const deTranslations: DefaultTranslationsObject = {
|
||||
requiresTwoNumbers: 'Dieses Feld muss zwei Nummern enthalten.',
|
||||
shorterThanMax: 'Dieser Wert muss kürzer als die maximale Länge von {{maxLength}} sein.',
|
||||
trueOrFalse: 'Dieses Feld kann nur wahr oder falsch sein.',
|
||||
username:
|
||||
'Bitte geben Sie einen gültigen Benutzernamen ein. Dieser kann Buchstaben, Zahlen, Bindestriche, Punkte und Unterstriche enthalten.',
|
||||
validUploadID: "'Dieses Feld enthält keine valide Upload-ID.'",
|
||||
},
|
||||
version: {
|
||||
|
||||
@@ -18,7 +18,6 @@ export const enTranslations = {
|
||||
confirmPassword: 'Confirm Password',
|
||||
createFirstUser: 'Create first user',
|
||||
emailNotValid: 'The email provided is not valid',
|
||||
emailOrUsername: 'Email or Username',
|
||||
emailSent: 'Email Sent',
|
||||
emailVerified: 'Email verified successfully.',
|
||||
enableAPIKey: 'Enable API Key',
|
||||
@@ -299,7 +298,6 @@ export const enTranslations = {
|
||||
updating: 'Updating',
|
||||
uploading: 'Uploading',
|
||||
user: 'User',
|
||||
username: 'Username',
|
||||
users: 'Users',
|
||||
value: 'Value',
|
||||
welcome: 'Welcome',
|
||||
@@ -364,8 +362,6 @@ export const enTranslations = {
|
||||
requiresTwoNumbers: 'This field requires two numbers.',
|
||||
shorterThanMax: 'This value must be shorter than the max length of {{maxLength}} characters.',
|
||||
trueOrFalse: 'This field can only be equal to true or false.',
|
||||
username:
|
||||
'Please enter a valid username. Can contain letters, numbers, hyphens, periods and underscores.',
|
||||
validUploadID: 'This field is not a valid upload ID.',
|
||||
},
|
||||
version: {
|
||||
|
||||
@@ -18,7 +18,6 @@ export const esTranslations: DefaultTranslationsObject = {
|
||||
confirmPassword: 'Confirmar Contraseña',
|
||||
createFirstUser: 'Crear al primer usuario',
|
||||
emailNotValid: 'El correo proporcionado es inválido',
|
||||
emailOrUsername: 'Correo electrónico o nombre de usuario',
|
||||
emailSent: 'Correo Enviado',
|
||||
emailVerified: 'Correo electrónico verificado con éxito.',
|
||||
enableAPIKey: 'Habilitar Clave API',
|
||||
@@ -301,7 +300,6 @@ export const esTranslations: DefaultTranslationsObject = {
|
||||
updating: 'Actualizando',
|
||||
uploading: 'Subiendo',
|
||||
user: 'Usuario',
|
||||
username: 'Nombre de usuario',
|
||||
users: 'Usuarios',
|
||||
value: 'Valor',
|
||||
welcome: 'Bienvenido',
|
||||
@@ -366,8 +364,6 @@ export const esTranslations: DefaultTranslationsObject = {
|
||||
requiresTwoNumbers: 'Este campo requiere dos números.',
|
||||
shorterThanMax: 'Este dato debe ser más corto que el máximo de {{maxLength}} caracteres.',
|
||||
trueOrFalse: 'Este campo solamente puede ser verdadero o falso.',
|
||||
username:
|
||||
'Por favor, introduzca un nombre de usuario válido. Puede contener letras, números, guiones, puntos y guiones bajos.',
|
||||
validUploadID: "'Este campo no es una ID de subida válida.'",
|
||||
},
|
||||
version: {
|
||||
|
||||
@@ -18,7 +18,6 @@ export const faTranslations: DefaultTranslationsObject = {
|
||||
confirmPassword: 'تأیید گذرواژه',
|
||||
createFirstUser: 'ایجاد کاربر نخست',
|
||||
emailNotValid: 'رایانامه ارائهشده درست نیست',
|
||||
emailOrUsername: 'ایمیل یا نام کاربری',
|
||||
emailSent: 'رایانامه فرستاده شد',
|
||||
emailVerified: 'ایمیل با موفقیت تایید شد.',
|
||||
enableAPIKey: 'فعالسازی کلید اِیپیآی',
|
||||
@@ -296,7 +295,6 @@ export const faTranslations: DefaultTranslationsObject = {
|
||||
updating: 'در حال بهروزرسانی',
|
||||
uploading: 'در حال بارگذاری',
|
||||
user: 'کاربر',
|
||||
username: 'نام کاربری',
|
||||
users: 'کاربران',
|
||||
value: 'مقدار',
|
||||
welcome: 'خوشآمدید',
|
||||
@@ -361,8 +359,6 @@ export const faTranslations: DefaultTranslationsObject = {
|
||||
requiresTwoNumbers: 'این کادر به دو عدد نیاز دارد.',
|
||||
shorterThanMax: 'ورودی باید کمتر از {{maxLength}} واژه باشد.',
|
||||
trueOrFalse: 'این کادر فقط می تواند به صورت true یا false باشد.',
|
||||
username:
|
||||
'لطفاً یک نام کاربری معتبر وارد کنید. می تواند شامل حروف، اعداد، خط فاصله، نقاط و خط زیر باشد.',
|
||||
validUploadID: 'این فیلد یک شناسه بارگذاری معتبر نیست.',
|
||||
},
|
||||
version: {
|
||||
|
||||
@@ -18,7 +18,6 @@ export const frTranslations: DefaultTranslationsObject = {
|
||||
confirmPassword: 'Confirmez le mot de passe',
|
||||
createFirstUser: 'Créer le premier utilisateur',
|
||||
emailNotValid: 'L’adresse e-mail fournie n’est pas valide',
|
||||
emailOrUsername: "Email ou Nom d'utilisateur",
|
||||
emailSent: 'E-mail envoyé',
|
||||
emailVerified: 'E-mail vérifié avec succès.',
|
||||
enableAPIKey: 'Activer la clé API',
|
||||
@@ -305,7 +304,6 @@ export const frTranslations: DefaultTranslationsObject = {
|
||||
updating: 'Mise à jour',
|
||||
uploading: 'Téléchargement',
|
||||
user: 'Utilisateur',
|
||||
username: "Nom d'utilisateur",
|
||||
users: 'Utilisateurs',
|
||||
value: 'Valeur',
|
||||
welcome: 'Bienvenue',
|
||||
@@ -372,8 +370,6 @@ export const frTranslations: DefaultTranslationsObject = {
|
||||
shorterThanMax:
|
||||
'Cette valeur doit être inférieure à la longueur maximale de {{maxLength}} caractères.',
|
||||
trueOrFalse: 'Ce champ ne peut être égal qu’à vrai ou faux.',
|
||||
username:
|
||||
"Veuillez entrer un nom d'utilisateur valide. Il peut contenir des lettres, des chiffres, des tirets, des points et des tirets bas.",
|
||||
validUploadID: 'Ce champ n’est pas un valide identifiant de fichier.',
|
||||
},
|
||||
version: {
|
||||
|
||||
@@ -17,7 +17,6 @@ export const heTranslations: DefaultTranslationsObject = {
|
||||
confirmPassword: 'אישור סיסמה',
|
||||
createFirstUser: 'יצירת משתמש ראשון',
|
||||
emailNotValid: 'הדוא"ל שסופק אינו תקין',
|
||||
emailOrUsername: 'דוא"ל או שם משתמש',
|
||||
emailSent: 'הודעת דואר נשלחה',
|
||||
emailVerified: 'דוא"ל אומת בהצלחה.',
|
||||
enableAPIKey: 'הפעלת מפתח API',
|
||||
@@ -291,7 +290,6 @@ export const heTranslations: DefaultTranslationsObject = {
|
||||
updating: 'מעדכן',
|
||||
uploading: 'מעלה',
|
||||
user: 'משתמש',
|
||||
username: 'שם משתמש',
|
||||
users: 'משתמשים',
|
||||
value: 'ערך',
|
||||
welcome: 'ברוך הבא',
|
||||
@@ -354,7 +352,6 @@ export const heTranslations: DefaultTranslationsObject = {
|
||||
requiresTwoNumbers: 'שדה זה דורש שני מספרים.',
|
||||
shorterThanMax: 'ערך זה חייב להיות קצר מ-{{maxLength}} תווים.',
|
||||
trueOrFalse: 'שדה זה יכול להיות רק true או false.',
|
||||
username: 'אנא הזן שם משתמש חוקי. יכול להכיל אותיות, מספרים, מקפים, נקודות וקווים תחתונים.',
|
||||
validUploadID: 'שדה זה אינו מזהה העלאה תקני.',
|
||||
},
|
||||
version: {
|
||||
|
||||
@@ -18,7 +18,6 @@ export const hrTranslations: DefaultTranslationsObject = {
|
||||
confirmPassword: 'Potvrdi lozinku',
|
||||
createFirstUser: 'Kreiraj prvog korisnika',
|
||||
emailNotValid: 'Email nije ispravan',
|
||||
emailOrUsername: 'E-mail ili Korisničko ime',
|
||||
emailSent: 'Email poslan',
|
||||
emailVerified: 'Email uspješno provjeren.',
|
||||
enableAPIKey: 'Omogući API ključ',
|
||||
@@ -297,7 +296,6 @@ export const hrTranslations: DefaultTranslationsObject = {
|
||||
updating: 'Ažuriranje',
|
||||
uploading: 'Prijenos',
|
||||
user: 'Korisnik',
|
||||
username: 'Korisničko ime',
|
||||
users: 'Korisnici',
|
||||
value: 'Attribute',
|
||||
welcome: 'Dobrodošli',
|
||||
@@ -362,8 +360,6 @@ export const hrTranslations: DefaultTranslationsObject = {
|
||||
requiresTwoNumbers: 'Ovo polje zahtjeva dva broja.',
|
||||
shorterThanMax: 'Ova vrijednost mora biti kraća od maksimalne dužine od {{maxLength}} znakova',
|
||||
trueOrFalse: 'Ovo polje može biti samo točno ili netočno',
|
||||
username:
|
||||
'Unesite važeće korisničko ime. Može sadržavati slova, brojeve, crtice, točke i donje crte.',
|
||||
validUploadID: 'Ovo polje nije valjani ID prijenosa.',
|
||||
},
|
||||
version: {
|
||||
|
||||
@@ -18,7 +18,6 @@ export const huTranslations: DefaultTranslationsObject = {
|
||||
confirmPassword: 'Jelszó megerősítése',
|
||||
createFirstUser: 'Első felhasználó létrehozása',
|
||||
emailNotValid: 'A megadott e-mail cím érvénytelen',
|
||||
emailOrUsername: 'E-mail vagy Felhasználónév',
|
||||
emailSent: 'E-mail elküldve',
|
||||
emailVerified: 'Az email sikeresen megerősítve.',
|
||||
enableAPIKey: 'API-kulcs engedélyezése',
|
||||
@@ -299,7 +298,6 @@ export const huTranslations: DefaultTranslationsObject = {
|
||||
updating: 'Frissítés',
|
||||
uploading: 'Feltöltés',
|
||||
user: 'Felhasználó',
|
||||
username: 'Felhasználónév',
|
||||
users: 'Felhasználók',
|
||||
value: 'Érték',
|
||||
welcome: 'Üdvözöljük',
|
||||
@@ -366,8 +364,6 @@ export const huTranslations: DefaultTranslationsObject = {
|
||||
shorterThanMax:
|
||||
'Ennek az értéknek rövidebbnek kell lennie, mint a maximálisan megengedett {{maxLength}} karakter.',
|
||||
trueOrFalse: 'Ez a mező csak igaz vagy hamis lehet.',
|
||||
username:
|
||||
'Adjon meg egy érvényes felhasználónevet. Tartalmazhat betűket, számokat, kötőjeleket, pontokat és aláhúzásokat.',
|
||||
validUploadID: 'Ez a mező nem érvényes feltöltési azonosító.',
|
||||
},
|
||||
version: {
|
||||
|
||||
@@ -18,7 +18,6 @@ export const itTranslations: DefaultTranslationsObject = {
|
||||
confirmPassword: 'Conferma Password',
|
||||
createFirstUser: 'Crea il primo utente',
|
||||
emailNotValid: "L'email fornita non è valida",
|
||||
emailOrUsername: 'Email o Nome utente',
|
||||
emailSent: 'Email Inviata',
|
||||
emailVerified: 'Email verificata con successo.',
|
||||
enableAPIKey: 'Abilita la Chiave API',
|
||||
@@ -299,7 +298,6 @@ export const itTranslations: DefaultTranslationsObject = {
|
||||
updating: 'Aggiornamento',
|
||||
uploading: 'Caricamento',
|
||||
user: 'Utente',
|
||||
username: 'Nome utente',
|
||||
users: 'Utenti',
|
||||
value: 'Valore',
|
||||
welcome: 'Benvenuto',
|
||||
@@ -366,8 +364,6 @@ export const itTranslations: DefaultTranslationsObject = {
|
||||
shorterThanMax:
|
||||
'Questo valore deve essere inferiore alla lunghezza massima di {{maxLength}} caratteri.',
|
||||
trueOrFalse: "Questo campo può essere solo uguale a 'true' o 'false'.",
|
||||
username:
|
||||
'Inserisci un nome utente valido. Può contenere lettere, numeri, trattini, punti e underscore.',
|
||||
validUploadID: "'Questo campo non è un ID di Upload valido.'",
|
||||
},
|
||||
version: {
|
||||
|
||||
@@ -18,7 +18,6 @@ export const jaTranslations: DefaultTranslationsObject = {
|
||||
confirmPassword: 'パスワードの確認',
|
||||
createFirstUser: '最初のユーザーを作成',
|
||||
emailNotValid: '入力されたメールアドレスは無効です。',
|
||||
emailOrUsername: 'メールまたはユーザー名',
|
||||
emailSent: 'Emailが送信されました。',
|
||||
emailVerified: 'メールが正常に確認されました。',
|
||||
enableAPIKey: 'API Keyを許可',
|
||||
@@ -297,7 +296,6 @@ export const jaTranslations: DefaultTranslationsObject = {
|
||||
updating: '更新中',
|
||||
uploading: 'アップロード中',
|
||||
user: 'ユーザー',
|
||||
username: 'ユーザーネーム',
|
||||
users: 'ユーザー',
|
||||
value: '値',
|
||||
welcome: 'ようこそ',
|
||||
@@ -361,8 +359,6 @@ export const jaTranslations: DefaultTranslationsObject = {
|
||||
requiresTwoNumbers: '2つの数値が必要です。',
|
||||
shorterThanMax: '{{maxLength}} 文字以下にする必要があります。',
|
||||
trueOrFalse: '"true" または "false" の値にする必要があります。',
|
||||
username:
|
||||
'有効なユーザーネームを入力してください。文字、数字、ハイフン、ピリオド、アンダースコアを使用できます。',
|
||||
validUploadID: '有効なアップロードIDではありません。',
|
||||
},
|
||||
version: {
|
||||
|
||||
@@ -18,7 +18,6 @@ export const koTranslations: DefaultTranslationsObject = {
|
||||
confirmPassword: '비밀번호 확인',
|
||||
createFirstUser: '첫 번째 사용자 생성',
|
||||
emailNotValid: '입력한 이메일은 유효하지 않습니다.',
|
||||
emailOrUsername: '이메일 또는 사용자 이름',
|
||||
emailSent: '이메일 전송됨',
|
||||
emailVerified: '이메일이 성공적으로 인증되었습니다.',
|
||||
enableAPIKey: 'API 키 활성화',
|
||||
@@ -296,7 +295,6 @@ export const koTranslations: DefaultTranslationsObject = {
|
||||
updating: '업데이트 중',
|
||||
uploading: '업로드 중',
|
||||
user: '사용자',
|
||||
username: '사용자 이름',
|
||||
users: '사용자',
|
||||
value: '값',
|
||||
welcome: '환영합니다',
|
||||
@@ -360,8 +358,6 @@ export const koTranslations: DefaultTranslationsObject = {
|
||||
requiresTwoNumbers: '이 입력란은 두 개의 숫자가 필요합니다.',
|
||||
shorterThanMax: '이 값은 최대 길이인 {{maxLength}}자보다 짧아야 합니다.',
|
||||
trueOrFalse: '이 입력란은 true 또는 false만 가능합니다.',
|
||||
username:
|
||||
'유효한 사용자 이름을 입력해 주세요. 글자, 숫자, 하이픈, 마침표, 및 밑줄을 사용할 수 있습니다.',
|
||||
validUploadID: '이 입력란은 유효한 업로드 ID가 아닙니다.',
|
||||
},
|
||||
version: {
|
||||
|
||||
@@ -18,7 +18,6 @@ export const myTranslations: DefaultTranslationsObject = {
|
||||
confirmPassword: 'စကားဝှက်အား ထပ်မံ ရိုက်ထည့်ပါ။',
|
||||
createFirstUser: 'ပထမဆုံး အသုံးပြုသူကို ဖန်တီးပါ။',
|
||||
emailNotValid: 'ထည့်သွင်းထားသော အီးမေလ်မှာ မှားယွင်းနေပါသည်။',
|
||||
emailOrUsername: 'E-mel atau Nama Pengguna',
|
||||
emailSent: 'မေးလ် ပို့ထားပါသည်။',
|
||||
emailVerified: 'အီးမေးလ်အတည်ပြုခဲ့ပါပြီ။',
|
||||
enableAPIKey: 'API Key ကိုဖွင့်ရန်',
|
||||
@@ -300,7 +299,6 @@ export const myTranslations: DefaultTranslationsObject = {
|
||||
updating: 'ပြင်ဆင်ရန်',
|
||||
uploading: 'တင်ပေးနေသည်',
|
||||
user: 'အသုံးပြုသူ',
|
||||
username: 'Nama pengguna',
|
||||
users: 'အသုံးပြုသူများ',
|
||||
value: 'တန်ဖိုး',
|
||||
welcome: 'ကြိုဆိုပါတယ်။',
|
||||
@@ -368,8 +366,6 @@ export const myTranslations: DefaultTranslationsObject = {
|
||||
requiresTwoNumbers: 'ဤအကွက်သည် နံပါတ်နှစ်ခု လိုအပ်ပါသည်။',
|
||||
shorterThanMax: 'ဤတန်ဖိုးသည် စာလုံး {{maxLength}} လုံး၏ အမြင့်ဆုံးအရှည်ထက် ပိုတိုရပါမည်။',
|
||||
trueOrFalse: 'ဤအကွက်သည် တစ်ခုခုဖြစ်ရပါမည်။',
|
||||
username:
|
||||
'Sila masukkan nama pengguna yang sah. Boleh mengandungi huruf, nombor, tanda hubung, titik dan garis bawah.',
|
||||
validUploadID: "'ဤအကွက်သည် မှန်ကန်သော အပ်လုဒ် ID မဟုတ်ပါ။'",
|
||||
},
|
||||
version: {
|
||||
|
||||
@@ -18,7 +18,6 @@ export const nbTranslations: DefaultTranslationsObject = {
|
||||
confirmPassword: 'Bekreft passord',
|
||||
createFirstUser: 'Opprett første bruker',
|
||||
emailNotValid: 'E-posten er ikke gyldig',
|
||||
emailOrUsername: 'E-post eller brukernavn',
|
||||
emailSent: 'E-post sendt',
|
||||
emailVerified: 'E-post bekreftet med hell.',
|
||||
enableAPIKey: 'Aktiver API-nøkkel',
|
||||
@@ -297,7 +296,6 @@ export const nbTranslations: DefaultTranslationsObject = {
|
||||
updating: 'Oppdatering',
|
||||
uploading: 'Opplasting',
|
||||
user: 'Bruker',
|
||||
username: 'Brukernavn',
|
||||
users: 'Brukere',
|
||||
value: 'Verdi',
|
||||
welcome: 'Velkommen',
|
||||
@@ -362,8 +360,6 @@ export const nbTranslations: DefaultTranslationsObject = {
|
||||
requiresTwoNumbers: 'Dette feltet krever to tall.',
|
||||
shorterThanMax: 'Denne verdien må være kortere enn maksimal lengde på {{maxLength}} tegn.',
|
||||
trueOrFalse: 'Dette feltet kan bare være likt true eller false.',
|
||||
username:
|
||||
'Vennligst oppgi et gyldig brukernavn. Kan inneholde bokstaver, nummer, bindestreker, punktum og understrek.',
|
||||
validUploadID: 'Dette feltet er ikke en gyldig opplastings-ID.',
|
||||
},
|
||||
version: {
|
||||
|
||||
@@ -18,7 +18,6 @@ export const nlTranslations: DefaultTranslationsObject = {
|
||||
confirmPassword: 'Wachtwoord bevestigen',
|
||||
createFirstUser: 'Eerste gebruiker aanmaken',
|
||||
emailNotValid: 'Het ingevoerde e-mailadres is niet geldig',
|
||||
emailOrUsername: 'E-mail of Gebruikersnaam',
|
||||
emailSent: 'E-mail verzonden',
|
||||
emailVerified: 'E-mail succesvol geverifieerd.',
|
||||
enableAPIKey: 'Activeer API-sleutel',
|
||||
@@ -299,7 +298,6 @@ export const nlTranslations: DefaultTranslationsObject = {
|
||||
updating: 'Bijwerken',
|
||||
uploading: 'Uploaden',
|
||||
user: 'Gebruiker',
|
||||
username: 'Gebruikersnaam',
|
||||
users: 'Gebruikers',
|
||||
value: 'Waarde',
|
||||
welcome: 'Welkom',
|
||||
@@ -364,8 +362,6 @@ export const nlTranslations: DefaultTranslationsObject = {
|
||||
requiresTwoNumbers: 'Dit veld vereist twee nummers.',
|
||||
shorterThanMax: 'Dit veld moet korter zijn dan de maximale lengte van {{maxLength}} tekens.',
|
||||
trueOrFalse: 'Dit veld kan alleen waar of onwaar zijn.',
|
||||
username:
|
||||
'Voer een geldige gebruikersnaam in. Kan letters, cijfers, koppeltekens, punten en underscores bevatten.',
|
||||
validUploadID: 'Dit veld is geen geldige upload-ID.',
|
||||
},
|
||||
version: {
|
||||
|
||||
@@ -18,7 +18,6 @@ export const plTranslations: DefaultTranslationsObject = {
|
||||
confirmPassword: 'Potwierdź hasło',
|
||||
createFirstUser: 'Utwórz pierwszego użytkownika',
|
||||
emailNotValid: 'Podany email jest nieprawidłowy',
|
||||
emailOrUsername: 'Email lub Nazwa użytkownika',
|
||||
emailSent: 'Wysłano email',
|
||||
emailVerified: 'Email zweryfikowany pomyślnie.',
|
||||
enableAPIKey: 'Aktywuj klucz API',
|
||||
@@ -297,7 +296,6 @@ export const plTranslations: DefaultTranslationsObject = {
|
||||
updating: 'Aktualizacja',
|
||||
uploading: 'Przesyłanie',
|
||||
user: 'użytkownik',
|
||||
username: 'Nazwa użytkownika',
|
||||
users: 'użytkownicy',
|
||||
value: 'Wartość',
|
||||
welcome: 'Witaj',
|
||||
@@ -362,8 +360,6 @@ export const plTranslations: DefaultTranslationsObject = {
|
||||
requiresTwoNumbers: 'To pole wymaga dwóch liczb.',
|
||||
shorterThanMax: 'Ta wartość musi być krótsza niż maksymalna długość znaków: {{maxLength}}.',
|
||||
trueOrFalse: "To pole może mieć wartość tylko 'true' lub 'false'.",
|
||||
username:
|
||||
'Proszę wprowadzić prawidłową nazwę użytkownika. Może zawierać litery, cyfry, myślniki, kropki i podkreślniki.',
|
||||
validUploadID: 'To pole nie jest prawidłowym identyfikatorem przesyłania.',
|
||||
},
|
||||
version: {
|
||||
|
||||
@@ -18,7 +18,6 @@ export const ptTranslations: DefaultTranslationsObject = {
|
||||
confirmPassword: 'Confirmar Senha',
|
||||
createFirstUser: 'Criar primeiro usuário',
|
||||
emailNotValid: 'O email fornecido não é válido',
|
||||
emailOrUsername: 'Email ou Nome de Usuário',
|
||||
emailSent: 'Email Enviado',
|
||||
emailVerified: 'Email verificado com sucesso.',
|
||||
enableAPIKey: 'Habilitar Chave API',
|
||||
@@ -298,7 +297,6 @@ export const ptTranslations: DefaultTranslationsObject = {
|
||||
updating: 'Atualizando',
|
||||
uploading: 'Fazendo upload',
|
||||
user: 'usuário',
|
||||
username: 'Nome de usuário',
|
||||
users: 'usuários',
|
||||
value: 'Valor',
|
||||
welcome: 'Boas vindas',
|
||||
@@ -363,8 +361,6 @@ export const ptTranslations: DefaultTranslationsObject = {
|
||||
requiresTwoNumbers: 'Esse campo requer dois números.',
|
||||
shorterThanMax: 'Esse valor deve ser menor do que o máximo de {{maxLength}} caracteres.',
|
||||
trueOrFalse: 'Esse campo pode ser apenas verdadeiro (true) ou falso (false)',
|
||||
username:
|
||||
'Por favor, insira um nome de usuário válido. Pode conter letras, números, hifens, pontos e sublinhados.',
|
||||
validUploadID: "'Esse campo não é um ID de upload válido.'",
|
||||
},
|
||||
version: {
|
||||
|
||||
@@ -18,7 +18,6 @@ export const roTranslations: DefaultTranslationsObject = {
|
||||
confirmPassword: 'Confirmați parola',
|
||||
createFirstUser: 'Creați primul utilizator',
|
||||
emailNotValid: 'Emailul furnizat nu este valid',
|
||||
emailOrUsername: 'Email sau Nume de utilizator',
|
||||
emailSent: 'Email trimis',
|
||||
emailVerified: 'E-mail verificat cu succes.',
|
||||
enableAPIKey: 'Activați cheia API',
|
||||
@@ -301,7 +300,6 @@ export const roTranslations: DefaultTranslationsObject = {
|
||||
updating: 'Actualizare',
|
||||
uploading: 'Încărcare',
|
||||
user: 'Utilizator',
|
||||
username: 'Nume de utilizator',
|
||||
users: 'Utilizatori',
|
||||
value: 'Valoare',
|
||||
welcome: 'Bine ați venit',
|
||||
@@ -370,8 +368,6 @@ export const roTranslations: DefaultTranslationsObject = {
|
||||
shorterThanMax:
|
||||
'Această valoare trebuie să fie mai scurtă decât lungimea maximă de {{maxLength}} caractere.',
|
||||
trueOrFalse: 'Acest câmp poate fi doar egal cu true sau false.',
|
||||
username:
|
||||
'Vă rugăm să introduceți un nume de utilizator valid. Poate conține litere, numere, cratime, puncte și sublinieri.',
|
||||
validUploadID: 'Acest câmp nu este un ID de încărcare valid.',
|
||||
},
|
||||
version: {
|
||||
|
||||
@@ -17,7 +17,6 @@ export const rsTranslations: DefaultTranslationsObject = {
|
||||
confirmPassword: 'Потврди лозинку',
|
||||
createFirstUser: 'Креирај првог корисника',
|
||||
emailNotValid: 'Адреса е-поште није валидна',
|
||||
emailOrUsername: 'Email ili Korisničko ime',
|
||||
emailSent: 'Порука е-поште прослеђена',
|
||||
emailVerified: 'Uspešno verifikovan email.',
|
||||
enableAPIKey: 'Омогући API кључ',
|
||||
@@ -296,7 +295,6 @@ export const rsTranslations: DefaultTranslationsObject = {
|
||||
updating: 'Ажурирање',
|
||||
uploading: 'Пренос',
|
||||
user: 'Корисник',
|
||||
username: 'Korisničko ime',
|
||||
users: 'Корисници',
|
||||
value: 'Вредност',
|
||||
welcome: 'Добродошли',
|
||||
@@ -361,8 +359,6 @@ export const rsTranslations: DefaultTranslationsObject = {
|
||||
requiresTwoNumbers: 'Ово поље захтева два броја.',
|
||||
shorterThanMax: 'Ова вредност мора бити краћа од максималне дужине од {{maxLength}} карактера',
|
||||
trueOrFalse: 'Ово поље може бити само тачно или нетачно',
|
||||
username:
|
||||
'Molimo unesite važeće korisničko ime. Može sadržati slova, brojeve, crtice, tačke i donje crte.',
|
||||
validUploadID: 'Ово поље не садржи валидан ИД преноса.',
|
||||
},
|
||||
version: {
|
||||
|
||||
@@ -17,7 +17,6 @@ export const rsLatinTranslations: DefaultTranslationsObject = {
|
||||
confirmPassword: 'Potvrdi lozinku',
|
||||
createFirstUser: 'Kreiraj prvog korisnika',
|
||||
emailNotValid: 'Adresa e-pošte nije validna',
|
||||
emailOrUsername: 'Email ili Korisničko ime',
|
||||
emailSent: 'Poruka e-pošte prosleđena',
|
||||
emailVerified: 'E-pošta je uspešno verifikovana.',
|
||||
enableAPIKey: 'Omogući API ključ',
|
||||
@@ -296,7 +295,6 @@ export const rsLatinTranslations: DefaultTranslationsObject = {
|
||||
updating: 'Ažuriranje',
|
||||
uploading: 'Prenos',
|
||||
user: 'Korisnik',
|
||||
username: 'Korisničko ime',
|
||||
users: 'Korisnici',
|
||||
value: 'Vrednost',
|
||||
welcome: 'Dobrodošli',
|
||||
@@ -361,8 +359,6 @@ export const rsLatinTranslations: DefaultTranslationsObject = {
|
||||
requiresTwoNumbers: 'Ovo polje zahteva dva broja.',
|
||||
shorterThanMax: 'Ova vrednost mora biti kraća od maksimalne dužine od {{maxLength}} karaktera',
|
||||
trueOrFalse: 'Ovo polje može biti samo tačno ili netačno',
|
||||
username:
|
||||
'Molimo unesite važeće korisničko ime. Može sadržavati slova, brojeve, crtice, tačke i donje crte.',
|
||||
validUploadID: 'Ovo polje ne sadrži validan ID prenosa.',
|
||||
},
|
||||
version: {
|
||||
|
||||
@@ -18,7 +18,6 @@ export const ruTranslations: DefaultTranslationsObject = {
|
||||
confirmPassword: 'Подтверждение пароля',
|
||||
createFirstUser: 'Создание первого пользователя',
|
||||
emailNotValid: 'Указанный адрес электронной почты неверен',
|
||||
emailOrUsername: 'Электронная почта или Имя пользователя',
|
||||
emailSent: 'Email отправлен',
|
||||
emailVerified: 'Электронная почта успешно подтверждена.',
|
||||
enableAPIKey: 'Активировать API ключ',
|
||||
@@ -300,7 +299,6 @@ export const ruTranslations: DefaultTranslationsObject = {
|
||||
updating: 'Обновление',
|
||||
uploading: 'Загрузка',
|
||||
user: 'пользователь',
|
||||
username: 'Имя пользователя',
|
||||
users: 'пользователи',
|
||||
value: 'Значение',
|
||||
welcome: 'Добро пожаловать',
|
||||
@@ -365,8 +363,6 @@ export const ruTranslations: DefaultTranslationsObject = {
|
||||
requiresTwoNumbers: 'В этом поле требуется два числа.',
|
||||
shorterThanMax: 'Это значение должно быть короче максимальной длины символов {{maxLength}}.',
|
||||
trueOrFalse: 'Это поле может быть равно только true или false.',
|
||||
username:
|
||||
'Пожалуйста, введите действительное имя пользователя. Может содержать буквы, цифры, дефисы, точки и подчёркивания.',
|
||||
validUploadID: "'Это поле не является действительным ID загрузки.'",
|
||||
},
|
||||
version: {
|
||||
|
||||
@@ -18,7 +18,6 @@ export const skTranslations: DefaultTranslationsObject = {
|
||||
confirmPassword: 'Potvrdiť heslo',
|
||||
createFirstUser: 'Vytvorenie prvého používateľa',
|
||||
emailNotValid: 'Zadaný e-mail nie je platný',
|
||||
emailOrUsername: 'E-mail alebo Užívateľské meno',
|
||||
emailSent: 'E-mail bol odoslaný',
|
||||
emailVerified: 'Email úspešne overený.',
|
||||
enableAPIKey: 'Povolenie API kľúča',
|
||||
@@ -298,7 +297,6 @@ export const skTranslations: DefaultTranslationsObject = {
|
||||
updating: 'Aktualizácia',
|
||||
uploading: 'Nahrávanie',
|
||||
user: 'Používateľ',
|
||||
username: 'Používateľské meno',
|
||||
users: 'Používatelia',
|
||||
value: 'Hodnota',
|
||||
welcome: 'Vitajte',
|
||||
@@ -363,8 +361,6 @@ export const skTranslations: DefaultTranslationsObject = {
|
||||
requiresTwoNumbers: 'Toto pole vyžaduje dve čísla.',
|
||||
shorterThanMax: 'Táto hodnota musí byť kratšia ako maximálna dĺžka {{maxLength}} znakov.',
|
||||
trueOrFalse: 'Toto pole môže byť rovné iba true alebo false.',
|
||||
username:
|
||||
'Prosím, zadajte platné používateľské meno. Môže obsahovať písmená, čísla, pomlčky, bodky a podčiarknutia.',
|
||||
validUploadID: 'Toto pole nie je platné ID pre odoslanie.',
|
||||
},
|
||||
version: {
|
||||
|
||||
@@ -18,7 +18,6 @@ export const svTranslations: DefaultTranslationsObject = {
|
||||
confirmPassword: 'Bekräfta Lösenord',
|
||||
createFirstUser: 'Skapa första användaren',
|
||||
emailNotValid: 'Angiven e-postadress är inte giltig',
|
||||
emailOrUsername: 'E-post eller användarnamn',
|
||||
emailSent: 'E-posten Skickad',
|
||||
emailVerified: 'E-post verifierad framgångsrikt.',
|
||||
enableAPIKey: 'Aktivera API nyckel',
|
||||
@@ -297,7 +296,6 @@ export const svTranslations: DefaultTranslationsObject = {
|
||||
updating: 'Uppdatering',
|
||||
uploading: 'Uppladdning',
|
||||
user: 'Användare',
|
||||
username: 'Användarnamn',
|
||||
users: 'Användare',
|
||||
value: 'Värde',
|
||||
welcome: 'Välkommen',
|
||||
@@ -362,8 +360,6 @@ export const svTranslations: DefaultTranslationsObject = {
|
||||
requiresTwoNumbers: 'Detta fält kräver två nummer.',
|
||||
shorterThanMax: 'Detta värde måste vara kortare än maxlängden på {{maxLength}} tecken.',
|
||||
trueOrFalse: 'Detta fält kan bara vara lika med sant eller falskt.',
|
||||
username:
|
||||
'Var god ange ett giltigt användarnamn. Kan innehålla bokstäver, siffror, bindestreck, punkter och understreck.',
|
||||
validUploadID: 'Det här fältet är inte ett giltigt uppladdnings-ID',
|
||||
},
|
||||
version: {
|
||||
|
||||
@@ -18,7 +18,6 @@ export const thTranslations: DefaultTranslationsObject = {
|
||||
confirmPassword: 'ยืนยันรหัสผ่าน',
|
||||
createFirstUser: 'สร้างผู้ใช้แรก',
|
||||
emailNotValid: 'อีเมลไม่ถูกต้อง',
|
||||
emailOrUsername: 'อีเมลหรือชื่อผู้ใช้',
|
||||
emailSent: 'ส่งอีเมลเรียบร้อยแล้ว',
|
||||
emailVerified: 'อีเมลได้รับการยืนยันเรียบร้อยแล้ว',
|
||||
enableAPIKey: 'เปิดใช้ API Key',
|
||||
@@ -293,7 +292,6 @@ export const thTranslations: DefaultTranslationsObject = {
|
||||
updating: 'กำลังอัปเดต',
|
||||
uploading: 'กำลังอัปโหลด',
|
||||
user: 'ผู้ใช้',
|
||||
username: 'ชื่อผู้ใช้',
|
||||
users: 'ผู้ใช้',
|
||||
value: 'ค่า',
|
||||
welcome: 'ยินดีต้อนรับ',
|
||||
@@ -356,7 +354,6 @@ export const thTranslations: DefaultTranslationsObject = {
|
||||
requiresTwoNumbers: 'ต้องมีตัวเลข 2 ค่า',
|
||||
shorterThanMax: 'ค่าต้องมีความยาวน้อยกว่า {{maxLength}} ตัวอักษร',
|
||||
trueOrFalse: 'เป็นได้แค่ "ใช่" หรือ "ไม่ใช่"',
|
||||
username: 'กรุณาใส่ชื่อผู้ใช้ที่ถูกต้อง สามารถมีตัวอักษร ตัวเลข ขีดกลาง จุด และขีดล่าง',
|
||||
validUploadID: 'ไม่ใช่ ID ของการอัปโหลดที่ถูกต้อง',
|
||||
},
|
||||
version: {
|
||||
|
||||
@@ -18,7 +18,6 @@ export const trTranslations: DefaultTranslationsObject = {
|
||||
confirmPassword: 'Parolayı Onayla',
|
||||
createFirstUser: 'İlk kullanıcı oluştur',
|
||||
emailNotValid: 'Girilen e-posta geçersiz',
|
||||
emailOrUsername: 'E-posta veya Kullanıcı Adı',
|
||||
emailSent: 'E-posta gönderildi',
|
||||
emailVerified: 'E-posta başarıyla doğrulandı.',
|
||||
enableAPIKey: 'Api anahtarını etkinleştir',
|
||||
@@ -301,7 +300,6 @@ export const trTranslations: DefaultTranslationsObject = {
|
||||
updating: 'Güncelleniyor',
|
||||
uploading: 'Yükleniyor',
|
||||
user: 'kullanıcı',
|
||||
username: 'Kullanıcı Adı',
|
||||
users: 'kullanıcı',
|
||||
value: 'Değer',
|
||||
welcome: 'Hoşgeldiniz',
|
||||
@@ -366,8 +364,6 @@ export const trTranslations: DefaultTranslationsObject = {
|
||||
requiresTwoNumbers: 'Bu alana en az iki rakam girilmesi zorunludur.',
|
||||
shorterThanMax: 'Bu alan {{maxLength}} karakterden daha kısa olmalıdır.',
|
||||
trueOrFalse: 'Bu alan yalnızca doğru ve yanlış olabilir.',
|
||||
username:
|
||||
'Lütfen geçerli bir kullanıcı adı girin. Harfler, numaralar, kısa çizgiler, noktalar ve alt çizgiler içerebilir.',
|
||||
validUploadID: "'Bu alan geçerli bir karşıya yükleme ID'sine sahip değil.'",
|
||||
},
|
||||
version: {
|
||||
|
||||
@@ -18,7 +18,6 @@ export const ukTranslations: DefaultTranslationsObject = {
|
||||
confirmPassword: 'Підтвердження паролю',
|
||||
createFirstUser: 'Створення першого користувача',
|
||||
emailNotValid: 'Вказана адреса електронної пошти недійсна',
|
||||
emailOrUsername: "Електронна пошта або Ім'я користувача",
|
||||
emailSent: 'Лист відправлено',
|
||||
emailVerified: 'Електронну пошту успішно підтверджено.',
|
||||
enableAPIKey: 'Активувати API ключ',
|
||||
@@ -297,7 +296,6 @@ export const ukTranslations: DefaultTranslationsObject = {
|
||||
updating: 'оновлення',
|
||||
uploading: 'завантаження',
|
||||
user: 'Користувач',
|
||||
username: "Ім'я користувача",
|
||||
users: 'Користувачі',
|
||||
value: 'Значення',
|
||||
welcome: 'Вітаю',
|
||||
@@ -362,8 +360,6 @@ export const ukTranslations: DefaultTranslationsObject = {
|
||||
requiresTwoNumbers: 'У цьому полі потрібно ввести два числа.',
|
||||
shorterThanMax: 'Це значення має дорівнювати або бути коротшим, ніж {{maxLength}} символів.',
|
||||
trueOrFalse: 'Це поле може мати значення тільки true або false.',
|
||||
username:
|
||||
"Будь ласка, введіть дійсне ім'я користувача. Може містити літери, цифри, дефіси, крапки та підкреслення.",
|
||||
validUploadID: 'Це поле не є дійсним ID завантаження.',
|
||||
},
|
||||
version: {
|
||||
|
||||
@@ -17,7 +17,6 @@ export const viTranslations: DefaultTranslationsObject = {
|
||||
confirmPassword: 'Xác nhận mật khẩu',
|
||||
createFirstUser: 'Tạo người dùng đầu tiên',
|
||||
emailNotValid: 'Email không chính xác',
|
||||
emailOrUsername: 'Email hoặc Tên tài khoản',
|
||||
emailSent: 'Email đã được gửi',
|
||||
emailVerified: 'Email đã được xác minh thành công.',
|
||||
enableAPIKey: 'Kích hoạt API Key',
|
||||
@@ -295,7 +294,6 @@ export const viTranslations: DefaultTranslationsObject = {
|
||||
updating: 'Đang cập nhật',
|
||||
uploading: 'Đang tải lên',
|
||||
user: 'Người dùng',
|
||||
username: 'Tên đăng nhập',
|
||||
users: 'Người dùng',
|
||||
value: 'Giá trị',
|
||||
welcome: 'Xin chào',
|
||||
@@ -360,8 +358,6 @@ export const viTranslations: DefaultTranslationsObject = {
|
||||
requiresTwoNumbers: 'Field này cần tối thiểu 2 chữ số.',
|
||||
shorterThanMax: 'Giá trị phải ngắn hơn hoặc bằng {{maxLength}} ký tự.',
|
||||
trueOrFalse: 'Field này chỉ có thể chứa giá trị true hoặc false.',
|
||||
username:
|
||||
'Vui lòng nhập một tên người dùng hợp lệ. Có thể chứa các chữ cái, số, dấu gạch ngang, dấu chấm và dấu gạch dưới.',
|
||||
validUploadID: "'Field này không chứa ID tải lên hợp lệ.'",
|
||||
},
|
||||
version: {
|
||||
|
||||
@@ -17,7 +17,6 @@ export const zhTranslations: DefaultTranslationsObject = {
|
||||
confirmPassword: '确认密码',
|
||||
createFirstUser: '创建第一个用户',
|
||||
emailNotValid: '所提供的电子邮件时无效的',
|
||||
emailOrUsername: '电子邮件或用户名',
|
||||
emailSent: '电子邮件已发送',
|
||||
emailVerified: '电子邮件验证成功。',
|
||||
enableAPIKey: '启用API密钥',
|
||||
@@ -289,7 +288,6 @@ export const zhTranslations: DefaultTranslationsObject = {
|
||||
updating: '更新中',
|
||||
uploading: '上传中',
|
||||
user: '用户',
|
||||
username: '用户名',
|
||||
users: '用户',
|
||||
value: '值',
|
||||
welcome: '欢迎',
|
||||
@@ -352,7 +350,6 @@ export const zhTranslations: DefaultTranslationsObject = {
|
||||
requiresTwoNumbers: '该字段需要两个数字。',
|
||||
shorterThanMax: '该值必须小于{{maxLength}}字符的最大长度',
|
||||
trueOrFalse: '该字段只能等于真或伪。',
|
||||
username: '请输入一个有效的用户名。可包含字母,数字,连字符,句点和下划线。',
|
||||
validUploadID: '该字段不是有效的上传ID。',
|
||||
},
|
||||
version: {
|
||||
|
||||
@@ -17,7 +17,6 @@ export const zhTwTranslations: DefaultTranslationsObject = {
|
||||
confirmPassword: '確認密碼',
|
||||
createFirstUser: '建立第一個使用者',
|
||||
emailNotValid: '提供的電子郵件無效',
|
||||
emailOrUsername: '電子郵件或使用者名稱',
|
||||
emailSent: '電子郵件已寄出',
|
||||
emailVerified: '電子郵件驗證成功。',
|
||||
enableAPIKey: '啟用API金鑰',
|
||||
@@ -289,7 +288,6 @@ export const zhTwTranslations: DefaultTranslationsObject = {
|
||||
updating: '更新中',
|
||||
uploading: '上傳中',
|
||||
user: '使用者',
|
||||
username: '使用者名稱',
|
||||
users: '使用者',
|
||||
value: '值',
|
||||
welcome: '歡迎',
|
||||
@@ -352,7 +350,6 @@ export const zhTwTranslations: DefaultTranslationsObject = {
|
||||
requiresTwoNumbers: '該字串需要兩個數字。',
|
||||
shorterThanMax: '該值長度必須小於{{maxLength}}個字元',
|
||||
trueOrFalse: '該字串只能等於是或否。',
|
||||
username: '請輸入有效的使用者名稱。可以包含字母、數字、連字號、句點和底線。',
|
||||
validUploadID: '該字串不是有效的上傳ID。',
|
||||
},
|
||||
version: {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@payloadcms/ui",
|
||||
"version": "3.0.0-beta.66",
|
||||
"version": "3.0.0-beta.65",
|
||||
"homepage": "https://payloadcms.com",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
|
||||
@@ -24,8 +24,9 @@ export const MultiValueLabel: React.FC<MultiValueProps<Option>> = (props) => {
|
||||
// @ts-expect-error-next-line// TODO Fix this - moduleResolution 16 breaks our declare module
|
||||
draggableProps,
|
||||
// @ts-expect-error-next-line // TODO Fix this - moduleResolution 16 breaks our declare module
|
||||
onSave,
|
||||
// @ts-expect-error-next-line // TODO Fix this - moduleResolution 16 breaks our declare module
|
||||
setDrawerIsOpen,
|
||||
// onSave,
|
||||
} = {},
|
||||
} = {},
|
||||
} = props
|
||||
@@ -77,7 +78,7 @@ export const MultiValueLabel: React.FC<MultiValueProps<Option>> = (props) => {
|
||||
</Tooltip>
|
||||
<EditIcon className={`${baseClass}__icon`} />
|
||||
</DocumentDrawerToggler>
|
||||
<DocumentDrawer onSave={/* onSave */ null} />
|
||||
<DocumentDrawer onSave={onSave} />
|
||||
</Fragment>
|
||||
)}
|
||||
</div>
|
||||
|
||||
1820
pnpm-lock.yaml
generated
1820
pnpm-lock.yaml
generated
File diff suppressed because it is too large
Load Diff
@@ -1,12 +1,13 @@
|
||||
import type { CollectionConfig } from 'payload'
|
||||
|
||||
import {
|
||||
BlocksFeature,
|
||||
FixedToolbarFeature,
|
||||
HeadingFeature,
|
||||
HorizontalRuleFeature,
|
||||
InlineToolbarFeature,
|
||||
lexicalEditor } from '@payloadcms/richtext-lexical'
|
||||
lexicalEditor,
|
||||
} from '@payloadcms/richtext-lexical'
|
||||
import { BlocksFeature } from '@payloadcms/richtext-lexical'
|
||||
|
||||
import { authenticated } from '../../access/authenticated'
|
||||
import { authenticatedOrPublished } from '../../access/authenticatedOrPublished'
|
||||
|
||||
@@ -460,42 +460,11 @@ describe('Auth', () => {
|
||||
await tryLogin()
|
||||
await tryLogin()
|
||||
|
||||
const loginAfterLimit = await restClient
|
||||
.POST(`/${slug}/login`, {
|
||||
body: JSON.stringify({
|
||||
email: userEmail,
|
||||
password,
|
||||
}),
|
||||
headers: {
|
||||
Authorization: `JWT ${token}`,
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
method: 'post',
|
||||
})
|
||||
.then((res) => res.json())
|
||||
|
||||
expect(loginAfterLimit.errors.length).toBeGreaterThan(0)
|
||||
|
||||
const lockedUser = await payload.find({
|
||||
collection: slug,
|
||||
showHiddenFields: true,
|
||||
where: {
|
||||
email: {
|
||||
equals: userEmail,
|
||||
},
|
||||
},
|
||||
})
|
||||
|
||||
expect(lockedUser.docs[0].loginAttempts).toBe(2)
|
||||
expect(lockedUser.docs[0].lockUntil).toBeDefined()
|
||||
|
||||
const manuallyReleaseLock = new Date(Date.now() - 605 * 1000)
|
||||
const userLockElapsed = await payload.update({
|
||||
await payload.update({
|
||||
collection: slug,
|
||||
data: {
|
||||
lockUntil: manuallyReleaseLock,
|
||||
lockUntil: Date.now() - 605 * 1000,
|
||||
},
|
||||
showHiddenFields: true,
|
||||
where: {
|
||||
email: {
|
||||
equals: userEmail,
|
||||
@@ -503,8 +472,6 @@ describe('Auth', () => {
|
||||
},
|
||||
})
|
||||
|
||||
expect(userLockElapsed.docs[0].lockUntil).toEqual(manuallyReleaseLock.toISOString())
|
||||
|
||||
// login
|
||||
await restClient.POST(`/${slug}/login`, {
|
||||
body: JSON.stringify({
|
||||
|
||||
@@ -207,6 +207,6 @@ export interface Auth {
|
||||
|
||||
|
||||
declare module 'payload' {
|
||||
// @ts-ignore
|
||||
// @ts-ignore
|
||||
export interface GeneratedTypes extends Config {}
|
||||
}
|
||||
}
|
||||
@@ -98,21 +98,21 @@ export class NextRESTClient {
|
||||
const url = `${this.serverURL}${this.config.routes.api}/${slugs}`
|
||||
|
||||
return {
|
||||
url,
|
||||
slug: slugs.split('/'),
|
||||
params: params ? qs.parse(params) : undefined,
|
||||
url,
|
||||
}
|
||||
}
|
||||
|
||||
async DELETE(path: ValidPath, options: RequestInit & RequestOptions = {}): Promise<Response> {
|
||||
const { slug, params, url } = this.generateRequestParts(path)
|
||||
const { url, slug, params } = this.generateRequestParts(path)
|
||||
const { query, ...rest } = options || {}
|
||||
const queryParams = generateQueryString(query, params)
|
||||
|
||||
const request = new Request(`${url}${queryParams}`, {
|
||||
...rest,
|
||||
headers: this.buildHeaders(options),
|
||||
method: 'DELETE',
|
||||
headers: this.buildHeaders(options),
|
||||
})
|
||||
return this._DELETE(request, { params: { slug } })
|
||||
}
|
||||
@@ -121,14 +121,14 @@ export class NextRESTClient {
|
||||
path: ValidPath,
|
||||
options: Omit<RequestInit, 'body'> & RequestOptions = {},
|
||||
): Promise<Response> {
|
||||
const { slug, params, url } = this.generateRequestParts(path)
|
||||
const { url, slug, params } = this.generateRequestParts(path)
|
||||
const { query, ...rest } = options || {}
|
||||
const queryParams = generateQueryString(query, params)
|
||||
|
||||
const request = new Request(`${url}${queryParams}`, {
|
||||
...rest,
|
||||
headers: this.buildHeaders(options),
|
||||
method: 'GET',
|
||||
headers: this.buildHeaders(options),
|
||||
})
|
||||
return this._GET(request, { params: { slug } })
|
||||
}
|
||||
@@ -140,8 +140,8 @@ export class NextRESTClient {
|
||||
`${this.serverURL}${this.config.routes.api}${this.config.routes.graphQL}${queryParams}`,
|
||||
{
|
||||
...rest,
|
||||
headers: this.buildHeaders(options),
|
||||
method: 'POST',
|
||||
headers: this.buildHeaders(options),
|
||||
},
|
||||
)
|
||||
return this._GRAPHQL_POST(request)
|
||||
@@ -154,8 +154,8 @@ export class NextRESTClient {
|
||||
|
||||
const request = new Request(`${url}${queryParams}`, {
|
||||
...rest,
|
||||
headers: this.buildHeaders(options),
|
||||
method: 'PATCH',
|
||||
headers: this.buildHeaders(options),
|
||||
})
|
||||
return this._PATCH(request, { params: { slug } })
|
||||
}
|
||||
@@ -164,12 +164,12 @@ export class NextRESTClient {
|
||||
path: ValidPath,
|
||||
options: FileArg & RequestInit & RequestOptions = {},
|
||||
): Promise<Response> {
|
||||
const { slug, params, url } = this.generateRequestParts(path)
|
||||
const { url, slug, params } = this.generateRequestParts(path)
|
||||
const queryParams = generateQueryString({}, params)
|
||||
const request = new Request(`${url}${queryParams}`, {
|
||||
...options,
|
||||
headers: this.buildHeaders(options),
|
||||
method: 'POST',
|
||||
headers: this.buildHeaders(options),
|
||||
})
|
||||
return this._POST(request, { params: { slug } })
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user