mirror of
https://github.com/strapi/strapi.git
synced 2025-09-25 08:19:07 +00:00
Merge branch 'master' into fix/upload-url-relative
This commit is contained in:
commit
1ac92c28d3
@ -197,6 +197,7 @@ module.exports = {
|
||||
'/3.0.0-beta.x/guides/process-manager',
|
||||
'/3.0.0-beta.x/guides/jwt-validation',
|
||||
'/3.0.0-beta.x/guides/api-token',
|
||||
'/3.0.0-beta.x/guides/auth-request',
|
||||
'/3.0.0-beta.x/guides/error-catching',
|
||||
'/3.0.0-beta.x/guides/secure-your-app',
|
||||
'/3.0.0-beta.x/guides/external-data',
|
||||
|
@ -52,10 +52,10 @@ As an **example** let's consider the following models:
|
||||
|
||||
### `Image With Description` Component
|
||||
|
||||
| Fields | Type | Description |
|
||||
| :---------- | :----- | :------------------- |
|
||||
| image | media | The image file |
|
||||
| title | string | the image title |
|
||||
| Fields | Type | Description |
|
||||
| :---------- | :----- | :-------------------- |
|
||||
| image | media | The image file |
|
||||
| title | string | the image title |
|
||||
| description | text | the image description |
|
||||
|
||||
:::
|
||||
|
172
docs/3.0.0-beta.x/guides/auth-request.md
Normal file
172
docs/3.0.0-beta.x/guides/auth-request.md
Normal file
@ -0,0 +1,172 @@
|
||||
# Authenticated request
|
||||
|
||||
In this guide you will see how you can request the API as an authenticated user.
|
||||
|
||||
## Introduction
|
||||
|
||||
To show you many of the concepts on the [roles and permissions](../plugins/users-permissions.md#manage-roles-permissions) part, we will use many users and roles.
|
||||
|
||||
After that we will see the [authentication workflow](../plugins/users-permissions.md#authentication) to get a `JWT` and use it for an API request.
|
||||
|
||||
We will have one group of users that will be able to only fetch **Articles** and an other group that will be able to fetch, create and update **Articles**.
|
||||
|
||||
## Setup
|
||||
|
||||
### Create Content Type
|
||||
|
||||
Lets create a new Content Type **Article**
|
||||
|
||||
- Click on `Content Type Builder` in the left menu
|
||||
- Then `+ Create new content-type`
|
||||
- Fill `Display name` with `article`
|
||||
- Create 2 fields
|
||||
- **Text** short named `title`
|
||||
- **Rich text** named `content`
|
||||
- And save this new Content Type
|
||||
|
||||
Then create some **Articles** from the Content Manager.
|
||||
|
||||
### Create Roles & Permissions
|
||||
|
||||
We will create 2 new groups to manage available actions for different kind of users.
|
||||
|
||||
- Click on `Roles & Permissions` in the left menu
|
||||
- Then `+ Add New Role`
|
||||
- Fill `name` with `Author`
|
||||
- Check `Select All` for the Application Article Content Type.
|
||||
- And save the new role
|
||||
|
||||
And repeat the opperation for the `Reader` group and check `find`, `findOne` and `count`.
|
||||
|
||||
### Create users
|
||||
|
||||
Finally create **2 users** with the following data.
|
||||
|
||||
**User 1**
|
||||
|
||||
- **username**: author
|
||||
- **email**: author@strapi.io
|
||||
- **password**: strapi
|
||||
- **role**: Author
|
||||
|
||||
**User 2**
|
||||
|
||||
- **username**: reader
|
||||
- **email**: reader@strapi.io
|
||||
- **password**: strapi
|
||||
- **role**: Reader
|
||||
|
||||
## Login as a Reader
|
||||
|
||||
To login as a user your will have to follow the [login documentation](../plugins/users-permissions.md#login).
|
||||
|
||||
Here is the API route for the authentication `/auth/local`.
|
||||
|
||||
You have to request it in **POST**.
|
||||
|
||||
:::: tabs
|
||||
|
||||
::: tab axios
|
||||
|
||||
```js
|
||||
import axios from 'axios';
|
||||
|
||||
const { data } = await axios.post('http://localhost:1337/auth/local', {
|
||||
identifier: 'reader@strapi.io',
|
||||
password: 'strapi',
|
||||
});
|
||||
|
||||
console.log(data);
|
||||
```
|
||||
|
||||
:::
|
||||
|
||||
::: tab Postman
|
||||
|
||||
If you are using **Postman** for example you will have to set the `body` as `raw` with the `JSON (application/json)` type.
|
||||
|
||||
```json
|
||||
{
|
||||
"identifier": "reader@strapi.io",
|
||||
"password": "strapi"
|
||||
}
|
||||
```
|
||||
|
||||
:::
|
||||
|
||||
::::
|
||||
|
||||
The API response contains the **user's JWT** in the `jwt` key.
|
||||
|
||||
```json
|
||||
{
|
||||
"jwt": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6MSwiaWF0IjoxNTc2OTM4MTUwLCJleHAiOjE1Nzk1MzAxNTB9.UgsjjXkAZ-anD257BF7y1hbjuY3ogNceKfTAQtzDEsU",
|
||||
"user": {
|
||||
"id": 1,
|
||||
"username": "reader",
|
||||
...
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
You will have to store this `JWT` in your application, it's important because you will have to use it the next requests.
|
||||
|
||||
### Fetch articles
|
||||
|
||||
Let's fetch Articles you created.
|
||||
|
||||
To do so, you will have to fetch `/articles` route in **GET**.
|
||||
|
||||
```js
|
||||
import axios from 'axios';
|
||||
|
||||
const { data } = await axios.get('http://localhost:1337/articles');
|
||||
|
||||
console.log(data);
|
||||
```
|
||||
|
||||
Here you should receive a **403 error** because you are not allowed, as Public user, to access to the **articles**.
|
||||
|
||||
You should use the `JWT` in the request to say that you can access to this data as **Reader user**.
|
||||
|
||||
```js
|
||||
import axios from 'axios';
|
||||
|
||||
const { data } = await axios.get('http://localhost:1337/articles', {
|
||||
headers: {
|
||||
Authorization:
|
||||
'Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6MSwiaWF0IjoxNTc2OTM4MTUwLCJleHAiOjE1Nzk1MzAxNTB9.UgsjjXkAZ-anD257BF7y1hbjuY3ogNceKfTAQtzDEsU',
|
||||
},
|
||||
});
|
||||
|
||||
console.log(data);
|
||||
```
|
||||
|
||||
And tada you have access to the data.
|
||||
|
||||
### Create an Article
|
||||
|
||||
To do so, you will have to request the `/articles` route in **POST**.
|
||||
|
||||
```js
|
||||
import axios from 'axios';
|
||||
|
||||
const {data} = await axios
|
||||
.get('http://localhost:1337/articles', {
|
||||
data: {
|
||||
title: 'my article'
|
||||
content: 'my super article content'
|
||||
},
|
||||
headers: {
|
||||
'Authorization': 'Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6MSwiaWF0IjoxNTc2OTM4MTUwLCJleHAiOjE1Nzk1MzAxNTB9.UgsjjXkAZ-anD257BF7y1hbjuY3ogNceKfTAQtzDEsU'
|
||||
}
|
||||
});
|
||||
|
||||
console.log(data);
|
||||
```
|
||||
|
||||
If you request this as a **Reader user**, you will receive a **403 error**. It's because the **Reader role** does not have access to the create function of the **Article** Content Type.
|
||||
|
||||
To fix that you will have to login with the **Author user** and use its `JWT` into the request to create an **Article**.
|
||||
|
||||
With that done, you will be able to create an **Article**.
|
@ -491,20 +491,22 @@ sudo nano ecosystem.config.js
|
||||
|
||||
```js
|
||||
module.exports = {
|
||||
apps : [{
|
||||
name: 'your-app-name',
|
||||
cwd: '/home/ubuntu/my-strapi-project/my-project',
|
||||
script: 'npm',
|
||||
args: 'start',
|
||||
env: {
|
||||
NODE_ENV: 'production',
|
||||
DATABASE_HOST: 'your-unique-url.rds.amazonaws.com', // database Endpoint under 'Connectivity & Security' tab
|
||||
DATABASE_PORT: '5432',
|
||||
DATABASE_NAME: 'strapi', // DB name under 'Configuration' tab
|
||||
DATABASE_USERNAME: 'postgres', // default username
|
||||
DATABASE_PASSWORD: 'Password',
|
||||
apps: [
|
||||
{
|
||||
name: 'your-app-name',
|
||||
cwd: '/home/ubuntu/my-strapi-project/my-project',
|
||||
script: 'npm',
|
||||
args: 'start',
|
||||
env: {
|
||||
NODE_ENV: 'production',
|
||||
DATABASE_HOST: 'your-unique-url.rds.amazonaws.com', // database Endpoint under 'Connectivity & Security' tab
|
||||
DATABASE_PORT: '5432',
|
||||
DATABASE_NAME: 'strapi', // DB name under 'Configuration' tab
|
||||
DATABASE_USERNAME: 'postgres', // default username
|
||||
DATABASE_PASSWORD: 'Password',
|
||||
},
|
||||
},
|
||||
}],
|
||||
],
|
||||
};
|
||||
```
|
||||
|
||||
|
@ -19,6 +19,10 @@ Starting from beta.18 the database packages have been changed to allow future ch
|
||||
|
||||
Update your package.json accordingly:
|
||||
|
||||
:::: tabs
|
||||
|
||||
::: tab bookshelf
|
||||
|
||||
**Before**
|
||||
|
||||
```json
|
||||
@ -46,20 +50,68 @@ Update your package.json accordingly:
|
||||
{
|
||||
//...
|
||||
"dependencies": {
|
||||
"strapi": "3.0.0-beta.18",
|
||||
"strapi-admin": "3.0.0-beta.18",
|
||||
"strapi-connector-bookshelf": "3.0.0-beta.18",
|
||||
"strapi-plugin-content-manager": "3.0.0-beta.18",
|
||||
"strapi-plugin-content-type-builder": "3.0.0-beta.18",
|
||||
"strapi-plugin-email": "3.0.0-beta.18",
|
||||
"strapi-plugin-graphql": "3.0.0-beta.18",
|
||||
"strapi-plugin-upload": "3.0.0-beta.18",
|
||||
"strapi-plugin-users-permissions": "3.0.0-beta.18",
|
||||
"strapi-utils": "3.0.0-beta.18"
|
||||
"strapi": "3.0.0-beta.18.3",
|
||||
"strapi-admin": "3.0.0-beta.18.3",
|
||||
"strapi-connector-bookshelf": "3.0.0-beta.18.3",
|
||||
"strapi-plugin-content-manager": "3.0.0-beta.18.3",
|
||||
"strapi-plugin-content-type-builder": "3.0.0-beta.18.3",
|
||||
"strapi-plugin-email": "3.0.0-beta.18.3",
|
||||
"strapi-plugin-graphql": "3.0.0-beta.18.3",
|
||||
"strapi-plugin-upload": "3.0.0-beta.18.3",
|
||||
"strapi-plugin-users-permissions": "3.0.0-beta.18.3",
|
||||
"strapi-utils": "3.0.0-beta.18.3"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
:::
|
||||
|
||||
::: tab mongoose
|
||||
|
||||
**Before**
|
||||
|
||||
```json
|
||||
{
|
||||
//...
|
||||
"dependencies": {
|
||||
"strapi": "3.0.0-beta.17.4",
|
||||
"strapi-admin": "3.0.0-beta.17.4",
|
||||
"strapi-hook-mongoose": "3.0.0-beta.17.4", // rename to strapi-connector-mongoose
|
||||
"strapi-plugin-content-manager": "3.0.0-beta.17.4",
|
||||
"strapi-plugin-content-type-builder": "3.0.0-beta.17.4",
|
||||
"strapi-plugin-email": "3.0.0-beta.17.4",
|
||||
"strapi-plugin-graphql": "3.0.0-beta.17.4",
|
||||
"strapi-plugin-upload": "3.0.0-beta.17.4",
|
||||
"strapi-plugin-users-permissions": "3.0.0-beta.17.4",
|
||||
"strapi-utils": "3.0.0-beta.17.4"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**After**
|
||||
|
||||
```json
|
||||
{
|
||||
//...
|
||||
"dependencies": {
|
||||
"strapi": "3.0.0-beta.18.3",
|
||||
"strapi-admin": "3.0.0-beta.18.3",
|
||||
"strapi-connector-mongoose": "3.0.0-beta.18.3",
|
||||
"strapi-plugin-content-manager": "3.0.0-beta.18.3",
|
||||
"strapi-plugin-content-type-builder": "3.0.0-beta.18.3",
|
||||
"strapi-plugin-email": "3.0.0-beta.18.3",
|
||||
"strapi-plugin-graphql": "3.0.0-beta.18.3",
|
||||
"strapi-plugin-upload": "3.0.0-beta.18.3",
|
||||
"strapi-plugin-users-permissions": "3.0.0-beta.18.3",
|
||||
"strapi-utils": "3.0.0-beta.18.3"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
:::
|
||||
|
||||
::::
|
||||
|
||||
Then run either `yarn install` or `npm install`.
|
||||
|
||||
## Database configuration
|
||||
@ -68,6 +120,10 @@ Now that you have installed the new database package. You need to update your `d
|
||||
|
||||
You can now only use the connector name instead of the complete package name.
|
||||
|
||||
:::: tabs
|
||||
|
||||
::: tab bookshelf
|
||||
|
||||
**Before**
|
||||
|
||||
```json
|
||||
@ -104,6 +160,91 @@ You can now only use the connector name instead of the complete package name.
|
||||
}
|
||||
```
|
||||
|
||||
:::
|
||||
|
||||
::: tab mongoose
|
||||
|
||||
**Before**
|
||||
|
||||
```json
|
||||
{
|
||||
"defaultConnection": "default",
|
||||
"connections": {
|
||||
"default": {
|
||||
"connector": "strapi-hook-mongoose",
|
||||
"settings": {
|
||||
//...
|
||||
},
|
||||
"options": {}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**After**
|
||||
|
||||
```json
|
||||
{
|
||||
"defaultConnection": "default",
|
||||
"connections": {
|
||||
"default": {
|
||||
"connector": "mongoose",
|
||||
"settings": {
|
||||
//...
|
||||
},
|
||||
"options": {
|
||||
//...
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
:::
|
||||
|
||||
::::
|
||||
|
||||
## Adding new root page files
|
||||
|
||||
We created new home pages when your go to your api url.
|
||||
You will need to copy `index.html` and `production.html` into your `public` folder.
|
||||
You can find those two files [here](https://github.com/strapi/strapi/tree/master/packages/strapi-generate-new/lib/resources/files/public).
|
||||
|
||||
## Updating `csp` options
|
||||
|
||||
The admin panel contains certain assets that use `data:img;base64` images. To allow rendering of those assets you can update the files `./config/environments/{env}/security.json` as follows:
|
||||
|
||||
**Before**
|
||||
|
||||
```json
|
||||
{
|
||||
"csp": {
|
||||
"enabled": true,
|
||||
"policy": [
|
||||
{
|
||||
"img-src": "'self' http:"
|
||||
},
|
||||
"block-all-mixed-content"
|
||||
]
|
||||
}
|
||||
//....
|
||||
}
|
||||
```
|
||||
|
||||
**After**
|
||||
|
||||
```json
|
||||
{
|
||||
"csp": {
|
||||
"enabled": true,
|
||||
"policy": ["block-all-mixed-content"]
|
||||
}
|
||||
//....
|
||||
}
|
||||
```
|
||||
|
||||
If you need more fine control you can also simply add the `data:` option to the `img-src` option.
|
||||
|
||||
## `ctx.state.user`
|
||||
|
||||
Previously the ctx.state.user was populated with the user informations, its role and permissions. To avoid perfromance issues the role is the only populated relation on the user by default.
|
||||
@ -112,11 +253,11 @@ Previously the ctx.state.user was populated with the user informations, its role
|
||||
|
||||
The file model has been updated. The `size` field is now a decimal number, allowing correct sorting behavior.
|
||||
|
||||
You will need to clear some database indexes if you are using either Mysql or PostgreSQL.
|
||||
You will need to clear some database indexes if you are using either MySQL or PostgreSQL.
|
||||
|
||||
:::: tabs
|
||||
|
||||
::: tab Mysql
|
||||
::: tab MySQL
|
||||
|
||||
Run the following statement in your database:
|
||||
|
||||
@ -298,7 +439,7 @@ RENAME COLUMN group_id to component_id;
|
||||
|
||||
:::
|
||||
|
||||
::: tab Mysql
|
||||
::: tab MySQL
|
||||
|
||||
```sql
|
||||
-- renaming the table
|
||||
@ -342,7 +483,7 @@ RENAME TO components_new_table_name;
|
||||
```
|
||||
|
||||
:::
|
||||
::: tab Mysql
|
||||
::: tab MySQL
|
||||
|
||||
```sql
|
||||
-- renaming the table
|
||||
@ -355,7 +496,7 @@ RENAME TABLE groups_old_table_name TO components_new_table_name;
|
||||
**2. Change the `collectionName` of the component**
|
||||
|
||||
**Before**
|
||||
`./api/components/category/component.json`
|
||||
`./components/component.json`
|
||||
|
||||
```json
|
||||
{
|
||||
@ -365,7 +506,7 @@ RENAME TABLE groups_old_table_name TO components_new_table_name;
|
||||
```
|
||||
|
||||
**After**
|
||||
`./api/components/category/component.json`
|
||||
`./components/component.json`
|
||||
|
||||
```json
|
||||
{
|
||||
@ -392,7 +533,6 @@ SET related_type = 'components_new_table_name'
|
||||
WHERE related_type = 'groups_old_table_name';
|
||||
```
|
||||
|
||||
|
||||
#### Mongo
|
||||
|
||||
In `mongo` the relation between a content type and its components is held in an array of references. To know which component type it referes to, the array also contains a `kind` attribute containing the component Schema name.
|
||||
@ -425,7 +565,7 @@ db.collection.renameCollection('groups_my_group', 'components_my_component');
|
||||
**3. Change the `collectionName` of the component**
|
||||
|
||||
**Before**
|
||||
`./api/components/category/component.json`
|
||||
`./components/component.json`
|
||||
|
||||
```json
|
||||
{
|
||||
@ -435,7 +575,7 @@ db.collection.renameCollection('groups_my_group', 'components_my_component');
|
||||
```
|
||||
|
||||
**After**
|
||||
`./api/components/category/component.json`
|
||||
`./components/component.json`
|
||||
|
||||
```json
|
||||
{
|
||||
@ -463,47 +603,6 @@ db.getCollection('contentTypeCollection').update(
|
||||
);
|
||||
```
|
||||
|
||||
## Adding new root page files
|
||||
|
||||
We created new home pages when your go to your api url.
|
||||
You will need to copy `index.html` and `production.html` into your `public` folder.
|
||||
You can find those two files [here](https://github.com/strapi/strapi/tree/master/packages/strapi-generate-new/lib/resources/files/public).
|
||||
|
||||
## Updating `csp` options
|
||||
|
||||
The admin panel contains certain assets that use `data:img;base64` images. To allow rendering of those assets you can update the files `./config/environments/{env}/security.json` as follows:
|
||||
|
||||
**Before**
|
||||
|
||||
```json
|
||||
{
|
||||
"csp": {
|
||||
"enabled": true,
|
||||
"policy": [
|
||||
{
|
||||
"img-src": "'self' http:"
|
||||
},
|
||||
"block-all-mixed-content"
|
||||
]
|
||||
}
|
||||
//....
|
||||
}
|
||||
```
|
||||
|
||||
**After**
|
||||
|
||||
```json
|
||||
{
|
||||
"csp": {
|
||||
"enabled": true,
|
||||
"policy": ["block-all-mixed-content"]
|
||||
}
|
||||
//....
|
||||
}
|
||||
```
|
||||
|
||||
If you need more fine control you can also simply add the `data:` option to the `img-src` option.
|
||||
|
||||
## Rebuilding your administration panel
|
||||
|
||||
Now delete the `.cache` and `build` folders. Then run `yarn develop`.
|
||||
|
@ -111,3 +111,42 @@ If you want to create your own provider without publishing it on **npm** you can
|
||||
```
|
||||
|
||||
- Finally, run `yarn install` or `npm install` to install your new custom provider.
|
||||
|
||||
## Trouble shooting
|
||||
|
||||
You received an `Auth.form.error.email.invalid` error even though the email is valid and exists in the database.
|
||||
|
||||
Here is the error response you get from the API.
|
||||
|
||||
```json
|
||||
{
|
||||
"statusCode": 400,
|
||||
"error": "Bad Request",
|
||||
"message": [
|
||||
{
|
||||
"messages": [
|
||||
{
|
||||
"id": "Auth.form.error.email.invalid"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
This error is due to your IP connection. By default, Strapi uses the [`sendmail`](https://github.com/guileen/node-sendmail) package.
|
||||
|
||||
This package sends an email from the server it runs on. Depending on the network you are on, the connection to the SMTP server could fail.
|
||||
|
||||
Here is the `sendmail` error.
|
||||
|
||||
```
|
||||
Error: SMTP code:550 msg:550-5.7.1 [87.88.179.13] The IP you're using to send mail is not authorized to
|
||||
550-5.7.1 send email directly to our servers. Please use the SMTP relay at your
|
||||
550-5.7.1 service provider instead. Learn more at
|
||||
550 5.7.1 https://support.google.com/mail/?p=NotAuthorizedError 30si2132728pjz.75 - gsmtp
|
||||
```
|
||||
|
||||
To fix it, I suggest you to use another email provider that uses third party to send emails.
|
||||
|
||||
When using a third party provider, you avoid having to setup a mail server on your server and get extra features such as email analytics.
|
||||
|
@ -4,7 +4,7 @@ import PropTypes from 'prop-types';
|
||||
const Wrapper = styled.div`
|
||||
padding-top: 0.7rem;
|
||||
position: absolute;
|
||||
top: 60px;
|
||||
top: 6rem;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
|
@ -137,7 +137,7 @@
|
||||
"Auth.advanced.allow_register": "",
|
||||
"Auth.form.button.forgot-password": "发送电子邮件",
|
||||
"Auth.form.button.forgot-password.success": "再次发送",
|
||||
"Auth.form.button.login": "登陆",
|
||||
"Auth.form.button.login": "登录",
|
||||
"Auth.form.button.register": "准备开始",
|
||||
"Auth.form.button.register-success": "再次发送",
|
||||
"Auth.form.button.reset-password": "修改密码",
|
||||
@ -176,6 +176,6 @@
|
||||
"Auth.form.register.username.placeholder": "John Doe",
|
||||
"Auth.header.register.description": "要完成安装并保护您的应用程序,请通过输入必要的信息来创建第一个用户(root管理员)。",
|
||||
"Auth.link.forgot-password": "忘记密码了吗?",
|
||||
"Auth.link.ready": "准备好登陆?",
|
||||
"Auth.link.ready": "准备好登录?",
|
||||
"components.Input.error.password.noMatch": "密码不匹配"
|
||||
}
|
||||
|
@ -270,11 +270,16 @@ module.exports = {
|
||||
: null
|
||||
);
|
||||
|
||||
const reverseAssoc = model.associations.find(assoc => assoc.alias === obj.field);
|
||||
const reverseAssoc = model.associations.find(
|
||||
assoc => assoc.alias === obj.field
|
||||
);
|
||||
|
||||
// Remove existing relationship because only one file
|
||||
// can be related to this field.
|
||||
if (reverseAssoc && reverseAssoc.nature === 'oneToManyMorph') {
|
||||
if (
|
||||
reverseAssoc &&
|
||||
reverseAssoc.nature === 'oneToManyMorph'
|
||||
) {
|
||||
relationUpdates.push(
|
||||
module.exports.removeRelationMorph
|
||||
.call(
|
||||
|
@ -14,7 +14,7 @@ const DragWrapper = styled.div`
|
||||
}
|
||||
> div > div {
|
||||
overflow-x: auto;
|
||||
overflow-y: hidden;
|
||||
overflow-y: scroll;
|
||||
}
|
||||
`;
|
||||
|
||||
|
@ -343,6 +343,7 @@ const forms = {
|
||||
},
|
||||
],
|
||||
[fields.divider],
|
||||
[fields.private],
|
||||
[fields.required],
|
||||
[fields.unique],
|
||||
];
|
||||
|
@ -82,6 +82,18 @@ const fields = {
|
||||
},
|
||||
validations: {},
|
||||
},
|
||||
private: {
|
||||
autoFocus: false,
|
||||
name: 'private',
|
||||
type: 'checkbox',
|
||||
label: {
|
||||
id: getTrad('form.attribute.item.privateField'),
|
||||
},
|
||||
description: {
|
||||
id: getTrad('form.attribute.item.privateField.description'),
|
||||
},
|
||||
validations: {},
|
||||
},
|
||||
unique: {
|
||||
autoFocus: false,
|
||||
name: 'unique',
|
||||
|
@ -77,6 +77,8 @@
|
||||
"form.attribute.item.requiredField": "Required field",
|
||||
"form.attribute.item.requiredField.description": "You won't be able to create an entry if this field is empty",
|
||||
"form.attribute.item.settings.name": "Settings",
|
||||
"form.attribute.item.privateField": "Private field",
|
||||
"form.attribute.item.privateField.description": "This field will not show up in the API response",
|
||||
"form.attribute.item.uniqueField": "Unique field",
|
||||
"form.attribute.item.uniqueField.description": "You won't be able to create an entry if there is an existing entry with identical content",
|
||||
"form.attribute.media.option.multiple": "Multiple media",
|
||||
|
@ -1,51 +1,151 @@
|
||||
{
|
||||
"attribute.boolean": "Boolean",
|
||||
"attribute.boolean.description": "Да или нет, 1 или 0, Истина или Ложь",
|
||||
"attribute.component": "Component",
|
||||
"attribute.component.description": "Компонент - группа полей, доступных для повторения или повторного использования",
|
||||
"attribute.date": "Date",
|
||||
"attribute.date.description": "Элемент управления датой и временем",
|
||||
"attribute.datetime": "Datetime",
|
||||
"attribute.dynamiczone": "Dynamic zone",
|
||||
"attribute.dynamiczone.description": "Компоненты с динамическим редактированием",
|
||||
"attribute.email": "Email",
|
||||
"attribute.email.description": "Поле электронной почты с проверкой формата",
|
||||
"attribute.enumeration": "Enumeration",
|
||||
"attribute.enumeration.description": "Перечень значений, выбирается одно",
|
||||
"attribute.json": "JSON",
|
||||
"attribute.json.description": "Данные в формате JSON",
|
||||
"attribute.media": "Media",
|
||||
"attribute.media.description": "Аудио- видео- и прочие медиафайлы",
|
||||
"attribute.null": " ",
|
||||
"attribute.number": "Number",
|
||||
"attribute.number.description": "Числа (integer, float, decimal)",
|
||||
"attribute.password": "Password",
|
||||
"attribute.relation": "Связь",
|
||||
"attribute.password.description": "Поле пароля с шифрованием",
|
||||
"attribute.relation": "Relation",
|
||||
"attribute.relation.description": "Ссылка на какой-либо тип контента",
|
||||
"attribute.richtext": "Rich text",
|
||||
"attribute.richtext.description": "Элемент управления для редактирования текста с форматированием",
|
||||
"attribute.text": "Text",
|
||||
"attribute.text.description": "Простой текст для заголовка или описания",
|
||||
"attribute.time": "Time",
|
||||
"attribute.uid": "Uuid",
|
||||
"attribute.uid.description": "Уникальный идентификатор",
|
||||
"button.attributes.add.another": "Ещё поле",
|
||||
"button.component.add": "Добавить компонент",
|
||||
"button.component.create": "Создать компонент",
|
||||
"button.model.create": "Создать новый тип контента",
|
||||
"components.componentSelect.no-component-available": "Вы уже добавили все имеющиеся группы полей",
|
||||
"components.componentSelect.no-component-available.with-search": "Подходящих групп полей не найдено",
|
||||
"components.componentSelect.value-component": "Выбрано компонентов - {number} (наберите для поиска)",
|
||||
"components.componentSelect.value-components": "Компонентов выбрано - {number}",
|
||||
"component.repeatable": "(повторяется)",
|
||||
"configurations": "конфигурации",
|
||||
"contentType.UID.description": "Идентификатор, используемый для генерации маршрутов и таблиц в API",
|
||||
"contentType.collectionName.description": "Полезно, когда имя типа контента и таблицы различаются",
|
||||
"contentType.collectionName.label": "Имя таблицы/коллекции",
|
||||
"contentType.displayName.label": "Отображаемое имя",
|
||||
"error.contentTypeName.reserved-name": "Это название зарезервировано и не может быть использовано в проекте",
|
||||
"error.validation.minSupMax": "Не может выходить за ограничения",
|
||||
"form.attribute.component.option.add": "Добавление компонента",
|
||||
"form.attribute.component.option.create": "Создание нового компонента",
|
||||
"form.attribute.component.option.create.description": "Компонент предоставляется в разных типах и группах и будет доступен отовсюду",
|
||||
"form.attribute.component.option.repeatable": "Повторяющийся компонент",
|
||||
"form.attribute.component.option.repeatable.description": "Применимо для множественных вхождений (массивов) ингредиентов, мета-тегов и т.д.",
|
||||
"form.attribute.component.option.reuse-existing": "Использовать существующий компонент",
|
||||
"form.attribute.component.option.reuse-existing.description": "Использовать повторно созданный ранее компонент, чтобы обеспечить согласованность данных в разных типах контента.",
|
||||
"form.attribute.component.option.single": "Одиночный компонент",
|
||||
"form.attribute.component.option.single.description": "Применимо для группировки полей, таких как полный адрес, основная информация и т.д.",
|
||||
"form.attribute.item.customColumnName": "Названия столбцов",
|
||||
"form.attribute.item.customColumnName.description": "Может быть полезно переименовать названия столбцов для более читаемых ответов API.",
|
||||
"form.attribute.item.date.type.date": "дата",
|
||||
"form.attribute.item.date.type.datetime": "дата/время",
|
||||
"form.attribute.item.date.type.time": "время",
|
||||
"form.attribute.item.defineRelation.fieldName": "Название поля",
|
||||
"form.attribute.item.enumeration.graphql": "Название поля в GraphQL",
|
||||
"form.attribute.item.enumeration.graphql.description": "Позволяет переопределить название поля в GraphQL, сгенерированное по умолчанию",
|
||||
"form.attribute.item.enumeration.placeholder": "Например:\nmorning\nnoon\nevening",
|
||||
"form.attribute.item.enumeration.rules": "Values (one line per value)",
|
||||
"form.attribute.item.enumeration.placeholder": "Например:\nутро\nполдень\nвечер",
|
||||
"form.attribute.item.enumeration.rules": "Значения (одна линия на значение)",
|
||||
"form.attribute.item.maximum": "Максимальное значение",
|
||||
"form.attribute.item.maximumLength": "Максимальная длина",
|
||||
"form.attribute.item.minimum": "Минимальное значение",
|
||||
"form.attribute.item.minimumLength": "Минимальная длина",
|
||||
"form.attribute.item.number.type": "Числовой формат",
|
||||
"form.attribute.item.number.type.decimal": "decimal (ex: 2.22)",
|
||||
"form.attribute.item.number.type.float": "float (ex: 3.33333333)",
|
||||
"form.attribute.item.number.type.integer": "integer (ex: 10)",
|
||||
"form.attribute.item.number.type.biginteger": "Большое целое (ex: 123456789)",
|
||||
"form.attribute.item.number.type.decimal": "Десятичное (ex: 2.22)",
|
||||
"form.attribute.item.number.type.float": "С плавающей точкой (ex: 3.33333333)",
|
||||
"form.attribute.item.number.type.integer": "Целое (ex: 10)",
|
||||
"form.attribute.item.requiredField": "Обязательное поле",
|
||||
"form.attribute.item.requiredField.description": "Вы не сможете создать запись, если это поле не заполнено",
|
||||
"form.attribute.item.settings.name": "Настройки",
|
||||
"form.attribute.item.uniqueField": "Уникальное поле",
|
||||
"form.attribute.item.uniqueField.description": "Вы не сможете создать запись, если уже существует запись с таким значением",
|
||||
"form.attribute.media.option.multiple": "Множественные медиа",
|
||||
"form.attribute.media.option.multiple.description": "Применимо для слайдеров и каруселей",
|
||||
"form.attribute.media.option.single": "Одиночное медиа",
|
||||
"form.attribute.media.option.single.description": "Применимо для аватаров, картинок профиля и пр.",
|
||||
"form.attribute.settings.default": "Стандартное значение",
|
||||
"form.attribute.text.option.long-text": "Большой текст",
|
||||
"form.attribute.text.option.long-text.description": "Применимо для описания, биографии... (не учествует в поиске)",
|
||||
"form.attribute.text.option.short-text": "Короткий текст",
|
||||
"form.attribute.text.option.short-text.description": "Применимо для названий, заголовков, ссылок... (участвует в поиске)",
|
||||
"form.button.add-components-to-dynamiczone": "Добавить компоненты в зону",
|
||||
"form.button.add-field": "Еще поле",
|
||||
"form.button.add-first-field-to-created-component": "Добавить первое поле в компонент",
|
||||
"form.button.add.field.to.component": "Добавить еще поле в компонент",
|
||||
"form.button.add.field.to.contentType": "Добавить еще поле в тип контента",
|
||||
"form.button.cancel": "Отменить",
|
||||
"form.button.configure-component": "настроить компонент",
|
||||
"form.button.configure-view": "Настроить отображение",
|
||||
"form.button.continue": "Продолжить",
|
||||
"form.button.delete": "Удалить",
|
||||
"form.button.finish": "Завершить",
|
||||
"form.button.save": "Сохранить",
|
||||
"from": "from",
|
||||
"menu.section.models.name.plural": "Типы Контента",
|
||||
"menu.section.models.name.singular": "Тип Контента",
|
||||
"form.button.select-component": "Выбрать компонент",
|
||||
"from": "из",
|
||||
"injected-components.content-manager.edit-settings-view.link.content-types": "Редактирование типа контента",
|
||||
"injected-components.content-manager.edit-settings-view.link.components": "Редактирование компонента",
|
||||
"menu.section.components.name.plural": "Компоненты",
|
||||
"menu.section.components.name.singular": "Компонент",
|
||||
"menu.section.models.name.plural": "Типы контента",
|
||||
"menu.section.models.name.singular": "Тип контента",
|
||||
"modalForm.attribute.form.base.name": "Имя атрибута",
|
||||
"modalForm.attribute.form.base.name.description": "Пробелы в имени атрибута недопустимы",
|
||||
"modalForm.attribute.text.type-selection": "Тип",
|
||||
"modalForm.attributes.select-component": "Выбор компонента",
|
||||
"modalForm.attributes.select-components": "Выбор компонентов",
|
||||
"modalForm.component.header-create": "Создание компонента",
|
||||
"modalForm.components.create-component.category.label": "Выберите категорию или введите имя новой",
|
||||
"modalForm.components.icon.label": "Иконка",
|
||||
"modalForm.contentType.header-create": "Создание типа контента",
|
||||
"modalForm.editCategory.base.name.description": "Пробелы в имени категории недопустимы",
|
||||
"modalForm.header-edit": "Редактирование {name}",
|
||||
"modalForm.header.categories": "Категории",
|
||||
"modalForm.sub-header.addComponentToDynamicZone": "Добавить компонент в динамическую зону",
|
||||
"modalForm.sub-header.attribute.create": "Добавить новое поле типа {type}",
|
||||
"modalForm.sub-header.attribute.create.step": "Добавить новый компонент ({step}/2)",
|
||||
"modalForm.sub-header.attribute.edit": "Изменение {name}",
|
||||
"modalForm.sub-header.chooseAttribute.component": "Выбрать имя поля компонента",
|
||||
"modalForm.sub-header.chooseAttribute.contentType": "Выбрать имя поля типа контента",
|
||||
"modelPage.attribute.relationWith": "Связь с",
|
||||
"modelPage.contentHeader.emptyDescription.description": "Для этого Типа Контента нет описания",
|
||||
"modelPage.contentHeader.emptyDescription.description": "Для этого типа контента нет описания",
|
||||
"notification.info.creating.notSaved": "Пожалуйста, сохраните изменения перед созданием нового компонента типа контента ",
|
||||
"plugin.description.long": "Моделируйте структуру данных вашего API. Создавайте новые поля и связи всего за минуту. Файлы в вашем проекте создаются и обновляются автоматически.",
|
||||
"plugin.description.short": "Моделируйте структуру данных вашего API.",
|
||||
"popUpForm.navContainer.advanced": "Расширенные настройки",
|
||||
"popUpForm.navContainer.base": "Базовые настройки",
|
||||
"popUpWarning.bodyMessage.contentType.delete": "Вы уверены, что хотите удалить этот Тип Контента?",
|
||||
"popUpWarning.bodyMessage.cancel-modifications": "Вы уверены, что хотите отменить изменения?",
|
||||
"popUpWarning.bodyMessage.cancel-modifications.with-components": "Вы уверены, что хотите отменить сделанные изменения? Некоторые компоненты были созданы или изменены...",
|
||||
"popUpWarning.bodyMessage.category.delete": "Вы уверены, что хотите удалить категорию? Все входящие в нее компоненты будут также удалены.",
|
||||
"popUpWarning.bodyMessage.component.delete": "Вы уверены, что хотите удалить этот компонент?",
|
||||
"popUpWarning.bodyMessage.contentType.delete": "Вы уверены, что хотите удалить этот тип контента?",
|
||||
"relation.attributeName.placeholder": "Пример: автор, категория, тег",
|
||||
"relation.manyToMany": "имеет и принадлежит многим",
|
||||
"relation.manyToOne": "имеет много",
|
||||
"relation.manyWay": "имеет много",
|
||||
"relation.oneToMany": "принадлежит многим",
|
||||
"relation.oneToOne": "имеет один",
|
||||
"relation.oneWay": "один принадлежит"
|
||||
"relation.oneWay": "один принадлежит",
|
||||
"table.attributes.title.plural": "Полей - {number}",
|
||||
"table.attributes.title.singular": "Поле - {number}",
|
||||
"prompt.unsaved": "Вы уверены, что хотите выйти? Все изменения будут потеряны."
|
||||
}
|
||||
|
@ -26,5 +26,7 @@
|
||||
"notification.dropFile.success": "تم تحميل ملفك",
|
||||
"notification.dropFiles.success": "{number} ملفات تم تحميلها",
|
||||
"Upload.status.sizeLimit": "{file} أكبر من حجم الحد الذي تمت تهيئته",
|
||||
"Upload.status.disabled" : "تم تعطيل تحميل الملف"
|
||||
"Upload.status.disabled" : "تم تعطيل تحميل الملف",
|
||||
"plugin.description.long": "إدارة ملفات الوسائط المتعددة.",
|
||||
"plugin.description.short": "إدارة ملفات الوسائط المتعددة."
|
||||
}
|
||||
|
@ -26,5 +26,7 @@
|
||||
"notification.dropFile.success": "Deine Datei wurde hochgeladen",
|
||||
"notification.dropFiles.success": "{number} Dateien wurden hochgeladen",
|
||||
"Upload.status.sizeLimit": "{file} ist größer als die konfigurierte Begrenzungsgröße",
|
||||
"Upload.status.disabled" : "Das Hochladen von Dateien ist deaktiviert"
|
||||
"Upload.status.disabled" : "Das Hochladen von Dateien ist deaktiviert",
|
||||
"plugin.description.long": "Multimedia-Dateiverwaltung.",
|
||||
"plugin.description.short": "Multimedia-Dateiverwaltung."
|
||||
}
|
||||
|
@ -27,5 +27,7 @@
|
||||
"notification.config.success": "The settings has been updated",
|
||||
"notification.delete.success": "The file has been deleted",
|
||||
"notification.dropFile.success": "Your file has been uploaded",
|
||||
"notification.dropFiles.success": "{number} files have been uploaded"
|
||||
"notification.dropFiles.success": "{number} files have been uploaded",
|
||||
"plugin.description.long": "Media file management.",
|
||||
"plugin.description.short": "Media file management."
|
||||
}
|
||||
|
@ -27,5 +27,7 @@
|
||||
"notification.dropFiles.success": "{number} archivos han sido cargados",
|
||||
"Upload.status.sizeLimit": "{file} es más grande que el tamaño límite configurado",
|
||||
"Upload.status.disabled" : "La carga de archivos está deshabilitada",
|
||||
"Upload.status.empty": "Los archivos están vacíos"
|
||||
"Upload.status.empty": "Los archivos están vacíos",
|
||||
"plugin.description.long": "Gestión de archivos multimedia.",
|
||||
"plugin.description.short": "Gestión de archivos multimedia."
|
||||
}
|
||||
|
@ -26,5 +26,7 @@
|
||||
"notification.dropFile.success": "Votre fichier a été téléchargé",
|
||||
"notification.dropFiles.success": "{number} fichiers ont été téléchargées",
|
||||
"Upload.status.sizeLimit": "{file} est plus grand que la taille limite configurée",
|
||||
"Upload.status.disabled" : "Le téléchargement de fichier est désactivé"
|
||||
"Upload.status.disabled" : "Le téléchargement de fichier est désactivé",
|
||||
"plugin.description.long": "Gestion de fichiers multimédia.",
|
||||
"plugin.description.short": "Gestion de fichiers multimédia."
|
||||
}
|
||||
|
@ -26,5 +26,7 @@
|
||||
"notification.dropFile.success": "Il file è stato caricato",
|
||||
"notification.dropFiles.success": "{number} file sono stati caricati",
|
||||
"Upload.status.sizeLimit": "{file} è più grande della dimensione limite configurata",
|
||||
"Upload.status.disabled" : "Il caricamento del file è disabilitato"
|
||||
"Upload.status.disabled" : "Il caricamento del file è disabilitato",
|
||||
"plugin.description.long": "Gestione dei file multimediali.",
|
||||
"plugin.description.short": "Gestione dei file multimediali."
|
||||
}
|
||||
|
@ -26,5 +26,7 @@
|
||||
"notification.dropFile.success": "ファイルがアップロードされました",
|
||||
"notification.dropFiles.success": "{number}個のファイルがアップロードされました",
|
||||
"Upload.status.sizeLimit": "{file}は設定された制限サイズよりも大きいです",
|
||||
"Upload.status.disabled" : "ファイルのアップロードが無効になっています"
|
||||
"Upload.status.disabled" : "ファイルのアップロードが無効になっています",
|
||||
"plugin.description.long": "マルチメディアファイル管理.",
|
||||
"plugin.description.short": "マルチメディアファイル管理."
|
||||
}
|
||||
|
@ -27,5 +27,7 @@
|
||||
"notification.config.success": "설정을 업데이트했습니다.",
|
||||
"notification.delete.success": "파일을 삭제했습니다.",
|
||||
"notification.dropFile.success": "파일을 업로드했습니다.",
|
||||
"notification.dropFiles.success": "{number}개의 파일을 업로드 했습니다."
|
||||
"notification.dropFiles.success": "{number}개의 파일을 업로드 했습니다.",
|
||||
"plugin.description.long": "멀티미디어 파일 관리.",
|
||||
"plugin.description.short": "멀티미디어 파일 관리."
|
||||
}
|
||||
|
@ -26,5 +26,7 @@
|
||||
"notification.dropFile.success": "Je bestand is geüpload",
|
||||
"notification.dropFiles.success": "{number} bestanden zijn geüpload",
|
||||
"Upload.status.sizeLimit": "{file} is groter dan de geconfigureerde limietgrootte",
|
||||
"Upload.status.disabled" : "Bestand uploaden is uitgeschakeld"
|
||||
"Upload.status.disabled" : "Bestand uploaden is uitgeschakeld",
|
||||
"plugin.description.long": "Multimediabestandsbeheer.",
|
||||
"plugin.description.short": "Multimediabestandsbeheer."
|
||||
}
|
||||
|
@ -26,5 +26,7 @@
|
||||
"notification.dropFile.success": "Plik został przesłany",
|
||||
"notification.dropFiles.success": "{number} plików zostało przesłanych",
|
||||
"Upload.status.sizeLimit": "{plik} jest większy niż skonfigurowany rozmiar limitu",
|
||||
"Upload.status.disabled" : "Przesyłanie plików jest wyłączone"
|
||||
"Upload.status.disabled" : "Przesyłanie plików jest wyłączone",
|
||||
"plugin.description.long": "Zarządzanie plikami multimedialnymi.",
|
||||
"plugin.description.short": "Zarządzanie plikami multimedialnymi."
|
||||
}
|
||||
|
@ -24,5 +24,7 @@
|
||||
"notification.config.success": "As configurações foram atualizadas",
|
||||
"notification.delete.success": "O arquivo foi removido",
|
||||
"notification.dropFile.success": "Seu arquivo foi enviado com sucesso",
|
||||
"notification.dropFiles.success": "{number} arquivos foram enviados com sucesso"
|
||||
"notification.dropFiles.success": "{number} arquivos foram enviados com sucesso",
|
||||
"plugin.description.long": "Gerenciamento de arquivos multimídia.",
|
||||
"plugin.description.short": "Gerenciamento de arquivos multimídia."
|
||||
}
|
||||
|
@ -26,5 +26,7 @@
|
||||
"notification.dropFile.success": "Seu arquivo foi transferido com sucesso",
|
||||
"notification.dropFiles.success": "{number} arquivos foram transferidos com sucesso",
|
||||
"Upload.status.sizeLimit": "{file} é maior que o tamanho limite configurado",
|
||||
"Upload.status.disabled" : "O upload de arquivos está desativado"
|
||||
"Upload.status.disabled" : "O upload de arquivos está desativado",
|
||||
"plugin.description.long": "Gerenciamento de arquivos multimídia.",
|
||||
"plugin.description.short": "Gerenciamento de arquivos multimídia."
|
||||
}
|
||||
|
@ -26,5 +26,7 @@
|
||||
"notification.dropFile.success": "Ваш файл загружен",
|
||||
"notification.dropFiles.success": "Файлов загружено: {number}",
|
||||
"Upload.status.sizeLimit": "{file} больше настроенного предельного размера",
|
||||
"Upload.status.disabled" : "Загрузка файла отключена"
|
||||
"Upload.status.disabled" : "Загрузка файла отключена",
|
||||
"plugin.description.long": "Управление мультимедийными файлами.",
|
||||
"plugin.description.short": "Управление мультимедийными файлами."
|
||||
}
|
||||
|
@ -26,5 +26,7 @@
|
||||
"notification.dropFile.success": "Dosyanız yüklendi",
|
||||
"notification.dropFiles.success": "{number} dosyalar yüklendi",
|
||||
"Upload.status.sizeLimit": "{file} yapılandırılmış sınır boyutundan daha büyük",
|
||||
"Upload.status.disabled" : "Dosya yükleme devre dışı"
|
||||
"Upload.status.disabled" : "Dosya yükleme devre dışı",
|
||||
"plugin.description.long": "Multimedya Dosya Yönetimi.",
|
||||
"plugin.description.short": "Multimedya Dosya Yönetimi."
|
||||
}
|
||||
|
@ -27,5 +27,7 @@
|
||||
"notification.config.success": "Các cấu hình đã được cập nhật",
|
||||
"notification.delete.success": "Tập tin đã được xoá",
|
||||
"notification.dropFile.success": "Các tập tin của bạn đã được tải lên",
|
||||
"notification.dropFiles.success": "{number} tập tin đã được tải lên"
|
||||
"notification.dropFiles.success": "{number} tập tin đã được tải lên",
|
||||
"plugin.description.long": "Quản lý tập tin đa phương tiện.",
|
||||
"plugin.description.short": "Quản lý tập tin đa phương tiện."
|
||||
}
|
||||
|
@ -26,5 +26,7 @@
|
||||
"notification.dropFile.success": "您的文件已上传",
|
||||
"notification.dropFiles.success": "{number} 个文件已上传",
|
||||
"Upload.status.sizeLimit": "{file}大于配置的限制大小",
|
||||
"Upload.status.disabled" : "文件上传已禁用"
|
||||
"Upload.status.disabled" : "文件上传已禁用",
|
||||
"plugin.description.long": "多媒体档案管理.",
|
||||
"plugin.description.short": "多媒体档案管理."
|
||||
}
|
||||
|
@ -26,5 +26,7 @@
|
||||
"notification.dropFile.success": "您的檔案已上傳",
|
||||
"notification.dropFiles.success": "{number} 個檔案已上傳",
|
||||
"Upload.status.sizeLimit": "{file}大於配置的限制大小",
|
||||
"Upload.status.disabled" : "文件上傳已禁用"
|
||||
"Upload.status.disabled" : "文件上傳已禁用",
|
||||
"plugin.description.long": "多媒體檔案管理.",
|
||||
"plugin.description.short": "多媒體檔案管理."
|
||||
}
|
||||
|
@ -5,7 +5,7 @@
|
||||
"strapi": {
|
||||
"name": "Files Upload",
|
||||
"icon": "cloud-upload-alt",
|
||||
"description": "Description of upload plugin."
|
||||
"description": "upload.plugin.description"
|
||||
},
|
||||
"scripts": {
|
||||
"test": "echo \"no tests yet\""
|
||||
|
@ -1,4 +1,4 @@
|
||||
# strapi-provider-email-sendmail
|
||||
# strapi-provider-email-mailgun
|
||||
|
||||
## Resources
|
||||
|
||||
|
@ -6,7 +6,7 @@
|
||||
|
||||
/* eslint-disable prefer-template */
|
||||
// Public node modules.
|
||||
const _ = require('lodash');
|
||||
const isObject = require('lodash/isObject');
|
||||
const mailgunFactory = require('mailgun-js');
|
||||
|
||||
/* eslint-disable no-unused-vars */
|
||||
@ -47,21 +47,21 @@ module.exports = {
|
||||
send: (options, cb) => {
|
||||
return new Promise((resolve, reject) => {
|
||||
// Default values.
|
||||
options = _.isObject(options) ? options : {};
|
||||
options.from = options.from || config.mailgun_default_from;
|
||||
options.replyTo = options.replyTo || config.mailgun_default_replyto;
|
||||
options.text = options.text || options.html;
|
||||
options.html = options.html || options.text;
|
||||
options = isObject(options) ? options : {};
|
||||
|
||||
let msg = {
|
||||
from: options.from,
|
||||
from: options.from || config.mailgun_default_from,
|
||||
to: options.to,
|
||||
subject: options.subject,
|
||||
text: options.text,
|
||||
html: options.html,
|
||||
...(options.text && { text: options.text }),
|
||||
...(options.html && { html: options.html }),
|
||||
...(options.template && { template: options.template }),
|
||||
...(options['h:X-Mailgun-Variables'] && {
|
||||
'h:X-Mailgun-Variables': options['h:X-Mailgun-Variables'],
|
||||
}),
|
||||
...(options.attachment && { attachment: options.attachment }),
|
||||
};
|
||||
msg['h:Reply-To'] = options.replyTo;
|
||||
msg['h:Reply-To'] = options.replyTo || config.mailgun_default_replyto;
|
||||
|
||||
mailgun.messages().send(msg, function(err) {
|
||||
if (err) {
|
||||
|
@ -25,7 +25,7 @@ module.exports = ctx => {
|
||||
|
||||
if (fullPath.length <= 1 || fullPath[0] !== 'files') {
|
||||
throw strapi.errors.badRequest(
|
||||
`When using multipart/form-data you need to provide your files by prefixing them witht the 'files'.`
|
||||
`When using multipart/form-data you need to provide your files by prefixing them with the 'files'.`
|
||||
);
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user