diff --git a/docs/.vuepress/config.js b/docs/.vuepress/config.js index 3b3bccb928..07e7ebd63e 100644 --- a/docs/.vuepress/config.js +++ b/docs/.vuepress/config.js @@ -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', diff --git a/docs/3.0.0-beta.x/content-api/api-endpoints.md b/docs/3.0.0-beta.x/content-api/api-endpoints.md index d4144afbc2..cf5ff921d5 100644 --- a/docs/3.0.0-beta.x/content-api/api-endpoints.md +++ b/docs/3.0.0-beta.x/content-api/api-endpoints.md @@ -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 | ::: diff --git a/docs/3.0.0-beta.x/guides/auth-request.md b/docs/3.0.0-beta.x/guides/auth-request.md new file mode 100644 index 0000000000..dad2f7da93 --- /dev/null +++ b/docs/3.0.0-beta.x/guides/auth-request.md @@ -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**. diff --git a/docs/3.0.0-beta.x/guides/deployment.md b/docs/3.0.0-beta.x/guides/deployment.md index 0fd8a43834..392655e868 100644 --- a/docs/3.0.0-beta.x/guides/deployment.md +++ b/docs/3.0.0-beta.x/guides/deployment.md @@ -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', + }, }, - }], + ], }; ``` diff --git a/docs/3.0.0-beta.x/migration-guide/migration-guide-beta.17-to-beta.18.md b/docs/3.0.0-beta.x/migration-guide/migration-guide-beta.17-to-beta.18.md index e9190b14cd..85484fb607 100644 --- a/docs/3.0.0-beta.x/migration-guide/migration-guide-beta.17-to-beta.18.md +++ b/docs/3.0.0-beta.x/migration-guide/migration-guide-beta.17-to-beta.18.md @@ -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`. diff --git a/docs/3.0.0-beta.x/plugins/email.md b/docs/3.0.0-beta.x/plugins/email.md index 3900c5a480..859a94d309 100644 --- a/docs/3.0.0-beta.x/plugins/email.md +++ b/docs/3.0.0-beta.x/plugins/email.md @@ -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. diff --git a/packages/strapi-admin/admin/src/components/LeftMenuLinkContainer/Wrapper.js b/packages/strapi-admin/admin/src/components/LeftMenuLinkContainer/Wrapper.js index 0f6cdfa8d3..a350a0b4e2 100644 --- a/packages/strapi-admin/admin/src/components/LeftMenuLinkContainer/Wrapper.js +++ b/packages/strapi-admin/admin/src/components/LeftMenuLinkContainer/Wrapper.js @@ -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; diff --git a/packages/strapi-admin/admin/src/translations/zh-Hans.json b/packages/strapi-admin/admin/src/translations/zh-Hans.json index a6e8121c5d..ec4a7999df 100644 --- a/packages/strapi-admin/admin/src/translations/zh-Hans.json +++ b/packages/strapi-admin/admin/src/translations/zh-Hans.json @@ -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": "密码不匹配" } diff --git a/packages/strapi-connector-bookshelf/lib/relations.js b/packages/strapi-connector-bookshelf/lib/relations.js index 0473e7b143..ae4494db17 100644 --- a/packages/strapi-connector-bookshelf/lib/relations.js +++ b/packages/strapi-connector-bookshelf/lib/relations.js @@ -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( diff --git a/packages/strapi-plugin-content-manager/admin/src/containers/ListSettingsView/DragWrapper.js b/packages/strapi-plugin-content-manager/admin/src/containers/ListSettingsView/DragWrapper.js index e687d02b0b..213287ce66 100644 --- a/packages/strapi-plugin-content-manager/admin/src/containers/ListSettingsView/DragWrapper.js +++ b/packages/strapi-plugin-content-manager/admin/src/containers/ListSettingsView/DragWrapper.js @@ -14,7 +14,7 @@ const DragWrapper = styled.div` } > div > div { overflow-x: auto; - overflow-y: hidden; + overflow-y: scroll; } `; diff --git a/packages/strapi-plugin-content-type-builder/admin/src/containers/FormModal/utils/forms.js b/packages/strapi-plugin-content-type-builder/admin/src/containers/FormModal/utils/forms.js index 1d3e4a0f61..e4192ad038 100644 --- a/packages/strapi-plugin-content-type-builder/admin/src/containers/FormModal/utils/forms.js +++ b/packages/strapi-plugin-content-type-builder/admin/src/containers/FormModal/utils/forms.js @@ -343,6 +343,7 @@ const forms = { }, ], [fields.divider], + [fields.private], [fields.required], [fields.unique], ]; diff --git a/packages/strapi-plugin-content-type-builder/admin/src/containers/FormModal/utils/staticFields.js b/packages/strapi-plugin-content-type-builder/admin/src/containers/FormModal/utils/staticFields.js index 0c484f8b85..d9cf928c2a 100644 --- a/packages/strapi-plugin-content-type-builder/admin/src/containers/FormModal/utils/staticFields.js +++ b/packages/strapi-plugin-content-type-builder/admin/src/containers/FormModal/utils/staticFields.js @@ -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', diff --git a/packages/strapi-plugin-content-type-builder/admin/src/translations/en.json b/packages/strapi-plugin-content-type-builder/admin/src/translations/en.json index be3c9e5fca..3a9778f290 100644 --- a/packages/strapi-plugin-content-type-builder/admin/src/translations/en.json +++ b/packages/strapi-plugin-content-type-builder/admin/src/translations/en.json @@ -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", diff --git a/packages/strapi-plugin-content-type-builder/admin/src/translations/ru.json b/packages/strapi-plugin-content-type-builder/admin/src/translations/ru.json index 2b5c2cc205..357e95fbc6 100644 --- a/packages/strapi-plugin-content-type-builder/admin/src/translations/ru.json +++ b/packages/strapi-plugin-content-type-builder/admin/src/translations/ru.json @@ -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": "Вы уверены, что хотите выйти? Все изменения будут потеряны." } diff --git a/packages/strapi-plugin-upload/admin/src/translations/ar.json b/packages/strapi-plugin-upload/admin/src/translations/ar.json index 9bd4f7d527..36ef336ccc 100644 --- a/packages/strapi-plugin-upload/admin/src/translations/ar.json +++ b/packages/strapi-plugin-upload/admin/src/translations/ar.json @@ -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": "إدارة ملفات الوسائط المتعددة." } diff --git a/packages/strapi-plugin-upload/admin/src/translations/de.json b/packages/strapi-plugin-upload/admin/src/translations/de.json index 773bdfc2d2..197bddc551 100644 --- a/packages/strapi-plugin-upload/admin/src/translations/de.json +++ b/packages/strapi-plugin-upload/admin/src/translations/de.json @@ -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." } diff --git a/packages/strapi-plugin-upload/admin/src/translations/en.json b/packages/strapi-plugin-upload/admin/src/translations/en.json index 04094015eb..105c04892d 100644 --- a/packages/strapi-plugin-upload/admin/src/translations/en.json +++ b/packages/strapi-plugin-upload/admin/src/translations/en.json @@ -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." } diff --git a/packages/strapi-plugin-upload/admin/src/translations/es.json b/packages/strapi-plugin-upload/admin/src/translations/es.json index 86fd4ef16a..bac2a26940 100644 --- a/packages/strapi-plugin-upload/admin/src/translations/es.json +++ b/packages/strapi-plugin-upload/admin/src/translations/es.json @@ -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." } diff --git a/packages/strapi-plugin-upload/admin/src/translations/fr.json b/packages/strapi-plugin-upload/admin/src/translations/fr.json index 00012dc6f0..0eb9b6811c 100644 --- a/packages/strapi-plugin-upload/admin/src/translations/fr.json +++ b/packages/strapi-plugin-upload/admin/src/translations/fr.json @@ -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." } diff --git a/packages/strapi-plugin-upload/admin/src/translations/it.json b/packages/strapi-plugin-upload/admin/src/translations/it.json index 2ed81f53bf..a96f198e70 100644 --- a/packages/strapi-plugin-upload/admin/src/translations/it.json +++ b/packages/strapi-plugin-upload/admin/src/translations/it.json @@ -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." } diff --git a/packages/strapi-plugin-upload/admin/src/translations/ja.json b/packages/strapi-plugin-upload/admin/src/translations/ja.json index a7f14a98b3..b194032653 100644 --- a/packages/strapi-plugin-upload/admin/src/translations/ja.json +++ b/packages/strapi-plugin-upload/admin/src/translations/ja.json @@ -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": "マルチメディアファイル管理." } diff --git a/packages/strapi-plugin-upload/admin/src/translations/ko.json b/packages/strapi-plugin-upload/admin/src/translations/ko.json index 5a8efa23a1..45cb261bb6 100644 --- a/packages/strapi-plugin-upload/admin/src/translations/ko.json +++ b/packages/strapi-plugin-upload/admin/src/translations/ko.json @@ -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": "멀티미디어 파일 관리." } diff --git a/packages/strapi-plugin-upload/admin/src/translations/nl.json b/packages/strapi-plugin-upload/admin/src/translations/nl.json index ab93b6c898..5b98b96ec0 100644 --- a/packages/strapi-plugin-upload/admin/src/translations/nl.json +++ b/packages/strapi-plugin-upload/admin/src/translations/nl.json @@ -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." } diff --git a/packages/strapi-plugin-upload/admin/src/translations/pl.json b/packages/strapi-plugin-upload/admin/src/translations/pl.json index 33f3d9017b..520506e663 100644 --- a/packages/strapi-plugin-upload/admin/src/translations/pl.json +++ b/packages/strapi-plugin-upload/admin/src/translations/pl.json @@ -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." } diff --git a/packages/strapi-plugin-upload/admin/src/translations/pt-BR.json b/packages/strapi-plugin-upload/admin/src/translations/pt-BR.json index 9b9a886e8c..cb62ea21cc 100644 --- a/packages/strapi-plugin-upload/admin/src/translations/pt-BR.json +++ b/packages/strapi-plugin-upload/admin/src/translations/pt-BR.json @@ -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." } diff --git a/packages/strapi-plugin-upload/admin/src/translations/pt.json b/packages/strapi-plugin-upload/admin/src/translations/pt.json index a8522c1b25..a675d46174 100644 --- a/packages/strapi-plugin-upload/admin/src/translations/pt.json +++ b/packages/strapi-plugin-upload/admin/src/translations/pt.json @@ -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." } diff --git a/packages/strapi-plugin-upload/admin/src/translations/ru.json b/packages/strapi-plugin-upload/admin/src/translations/ru.json index 66e63b0e06..4b19e462d8 100644 --- a/packages/strapi-plugin-upload/admin/src/translations/ru.json +++ b/packages/strapi-plugin-upload/admin/src/translations/ru.json @@ -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": "Управление мультимедийными файлами." } diff --git a/packages/strapi-plugin-upload/admin/src/translations/tr.json b/packages/strapi-plugin-upload/admin/src/translations/tr.json index 6c426edab4..9412197859 100644 --- a/packages/strapi-plugin-upload/admin/src/translations/tr.json +++ b/packages/strapi-plugin-upload/admin/src/translations/tr.json @@ -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." } diff --git a/packages/strapi-plugin-upload/admin/src/translations/vi.json b/packages/strapi-plugin-upload/admin/src/translations/vi.json index bd18770440..5c061fc28d 100644 --- a/packages/strapi-plugin-upload/admin/src/translations/vi.json +++ b/packages/strapi-plugin-upload/admin/src/translations/vi.json @@ -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." } diff --git a/packages/strapi-plugin-upload/admin/src/translations/zh-Hans.json b/packages/strapi-plugin-upload/admin/src/translations/zh-Hans.json index 74e9bae7d2..e18a8f9bfe 100644 --- a/packages/strapi-plugin-upload/admin/src/translations/zh-Hans.json +++ b/packages/strapi-plugin-upload/admin/src/translations/zh-Hans.json @@ -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": "多媒体档案管理." } diff --git a/packages/strapi-plugin-upload/admin/src/translations/zh.json b/packages/strapi-plugin-upload/admin/src/translations/zh.json index e864eca7ab..83a02db58a 100644 --- a/packages/strapi-plugin-upload/admin/src/translations/zh.json +++ b/packages/strapi-plugin-upload/admin/src/translations/zh.json @@ -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": "多媒體檔案管理." } diff --git a/packages/strapi-plugin-upload/package.json b/packages/strapi-plugin-upload/package.json index 21cf7e6b1b..b4b223c845 100644 --- a/packages/strapi-plugin-upload/package.json +++ b/packages/strapi-plugin-upload/package.json @@ -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\"" diff --git a/packages/strapi-provider-email-mailgun/README.md b/packages/strapi-provider-email-mailgun/README.md index 6f219e1ac0..8e9970583e 100644 --- a/packages/strapi-provider-email-mailgun/README.md +++ b/packages/strapi-provider-email-mailgun/README.md @@ -1,4 +1,4 @@ -# strapi-provider-email-sendmail +# strapi-provider-email-mailgun ## Resources diff --git a/packages/strapi-provider-email-mailgun/lib/index.js b/packages/strapi-provider-email-mailgun/lib/index.js index 4be997a1eb..edce0f03f7 100644 --- a/packages/strapi-provider-email-mailgun/lib/index.js +++ b/packages/strapi-provider-email-mailgun/lib/index.js @@ -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) { diff --git a/packages/strapi-utils/lib/parse-multipart.js b/packages/strapi-utils/lib/parse-multipart.js index 883bb830fe..200d382cf5 100644 --- a/packages/strapi-utils/lib/parse-multipart.js +++ b/packages/strapi-utils/lib/parse-multipart.js @@ -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'.` ); }