Merge branch 'master' into fix/enumeration

This commit is contained in:
virginieky 2019-12-31 12:42:35 +01:00 committed by GitHub
commit e3af0c2ab2
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
66 changed files with 947 additions and 160 deletions

View File

@ -197,13 +197,16 @@ 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',
'/3.0.0-beta.x/guides/custom-data-response',
'/3.0.0-beta.x/guides/custom-admin',
'/3.0.0-beta.x/guides/client',
'/3.0.0-beta.x/guides/draft',
'/3.0.0-beta.x/guides/slug',
'/3.0.0-beta.x/guides/send-email',
'/3.0.0-beta.x/guides/webhooks',
],
},

View File

@ -349,7 +349,7 @@ xhr.send(
::: tab "Many-to-Many" id="many-to-many"
One-to-Many relationships are usefull when an entry can be liked to multiple entries of an other Content Type. And an entry of the other Content Type can be linked to many entries.
Many-to-Many relationships are usefull when an entry can be liked to multiple entries of an other Content Type. And an entry of the other Content Type can be linked to many entries.
#### Example

View 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**.

View File

@ -0,0 +1,153 @@
# Setup a third party client
This guide will explain how to setup a connection with a third party client and use it everywhere in your code.
In our example we will use the GitHub Node.JS client [OctoKit REST.js](https://github.com/octokit/rest.js/).
This guide could also be used to setup an Axios client instance.
## Installation
First you will have to install the client package in your application by running one of the following command.
:::: tabs
::: tab yarn
`yarn add @octokit/rest`
:::
::: tab npm
`npm install @octokit/rest`
:::
::::
## Create a hook
To init the client, we will use the [hooks system](../concepts/hooks.md). Hooks let you add new features in your Strapi application.
Hooks are loaded one time, at the server start.
Lets create our GitHub hook.
**Path —** `./hooks/github/index.js`
```js
module.exports = strapi => {
return {
async initialize() {
console.log('my hook is loaded');
},
};
};
```
When the hook is created, we have to enable it to say to Strapi to use this hook.
**Path —** `./config/hook.json`
```json
{
...
"github": {
"enabled": true
}
}
```
Now you can start your application, you should see a log `my hook is loaded` in your terminal.
## Initialize the client
First lets update the config file to add your [GitHub token](https://github.com/settings/tokens).
By following the [documentation](https://octokit.github.io/rest.js/#authentication) you will also find the way to use GitHub applications.
**Path —** `./config/hook.json`
```json
{
...
"github": {
"enabled": true,
"token": "bf78d4fc3c1767019870476d6d7cc8961383d80f"
}
}
```
Now we have to load the GitHub client.
**Path —** `./hooks/github/index.js`
```js
const GitHubAPI = require('@octokit/rest');
module.exports = strapi => {
return {
async initialize() {
const { token } = strapi.config.hook.github;
strapi.services.github = new GitHubAPI({
userAgent: `${strapi.config.info.name} v${strapi.config.info.version}`,
auth: `token ${token}`,
});
},
};
};
```
And here it is.
You can now use `strapi.github` everywhere in your code to use the GitHub client.
To simply test if it works, lets update the `bootstrap.js` function to log your GitHub profile.
**Path —** `./config/functions/bootstrap.js`
```js
module.exports = async () => {
const data = await strapi.services.github.users.getAuthenticated();
console.log(data);
};
```
Restart your server and you should see your GitHub profile data.
## Configs by environment
You would probably want specific configurations for development and production environment.
To do so, we will update some configurations.
You have to move your `github` configs from `./config/hook.json` to `./config/environments/development.json`, then remove it from the `hook.json` file.
And in your GitHub hook, you will have to replace `strapi.config.hook.github` by `strapi.config.currentEnvironment.github` to access to the configs.
**Path —** `./config/environments/development.json`
```json
{
"github": {
"enabled": true,
"token": "806506ab855a94e8608148315eeb39a44c29aee1"
}
}
```
**Path —** `./hooks/github/inde.js`
```js
const GitHubAPI = require('@octokit/rest');
module.exports = strapi => {
return {
async initialize() {
const { token } = strapi.config.currentEnvironment.github;
strapi.services.github = new GitHubAPI({
userAgent: `${strapi.config.info.name} v${strapi.config.info.version}`,
auth: `token ${token}`,
});
},
};
};
```

View File

@ -172,7 +172,7 @@ MongoDB must already be running in the background.
::: tab yarn
```
yarn create strapi-app new my-project
yarn create strapi-app my-project
```
:::

View File

@ -0,0 +1,127 @@
# Send email programmatically
In this guide we will see how to use the Email plugin to send email where you want in your app.
For this example we want to receive an email when a new article's comment is posted and if it contains bad words.
## Introduction
What we want here is to add some custom logic and call the email service when a `Comment` is created via the `POST /comments` endpoint.
To be able to do that, you have first to understand some concepts.
When you create a content type, it generates an API with the following list of [endpoints](../content-api/endpoint.md).
Each of these endpoint triggers a controller action. Here is the list of [controller actions](../concepts/controller.md) that exist by default when a content type is created.
If you check the controller file of your generated API `./api/{content-type}/controller/{Content-Type}.js`, you will see an empty file. It is because all the default logic is managed by Strapi. But you can override these actions with your own code.
And that is what we will do to add our custom code.
## Example
To keep the code example realy easy to follow, we will just have a `Comment` content type and omit the `Author` and `Article` relations.
So lets create a `Comment` content type with just one **Text** field named `content`.
When the content type is created, allow the create function for the Public role.
To check if bad words are in the comment we will use `bad-words` [node module](https://www.npmjs.com/package/bad-words). You will have to install it in your application.
## Override controller action
To customize the function that creates a comment we will have to override the `create` function.
First, to see the difference, let's request `POST /comment` with `that is fucking good!` for the `content` attribute.
You will see your comment is successfully created.
Now let's start the customization.
**Path —** `./api/comment/controller/Comment.js`
```js
module.exports = {
async create() {
return 'strapi';
},
};
```
After saving the new function, let's restart the `POST /comment` request. We will see `strapi` as response.
## Get the comment creation back
We now know the function we have to update. Let's get back to the original function.
In the [controller documentation](../concepts/controllers.html#extending-a-model-controller) you will find the default implementation of every actions. It will help you overwrite the create logic.
**Path —** `./api/comment/controller/Comment.js`
```js
const { parseMultipartData, sanitizeEntity } = require('strapi-utils');
module.exports = {
async create(ctx) {
let entity;
if (ctx.is('multipart')) {
const { data, files } = parseMultipartData(ctx);
entity = await strapi.services.comment.create(data, { files });
} else {
entity = await strapi.services.comment.create(ctx.request.body);
}
return sanitizeEntity(entity, { model: strapi.models.comment });
},
};
```
And now the comment creation is back.
## Apply our changes
We want to check if the content of the comment contains a bad words.
If it does, we want to send an email using the [Email plugin](../plugins/email.md)
**Path —** `./api/comment/controller/Comment.js`
```js
const { parseMultipartData, sanitizeEntity } = require('strapi-utils');
const Filter = require('bad-words');
const filter = new Filter();
module.exports = {
async create(ctx) {
let entity;
if (ctx.is('multipart')) {
const { data, files } = parseMultipartData(ctx);
entity = await strapi.services.comment.create(data, { files });
} else {
entity = await strapi.services.comment.create(ctx.request.body);
}
entry = sanitizeEntity(entity, { model: strapi.models.comment });
// check if the comment content contains a bad word
if (entry.content !== filter.clean(entry.content)) {
// send an email by using the email plugin
await strapi.plugins['email'].services.email.send({
to: 'paulbocuse@strapi.io',
from: 'admin@strapi.io'
subject: 'Comment posted that contains a bad words',
text: `
The comment #${entry.id} contain a bad words.
Comment:
${entry.content}
`,
});
}
return entry;
},
};
```
And tada, it works.

View File

@ -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
@ -380,10 +521,19 @@ _Repeat this query for every join table where you are using this component._
```sql
UPDATE restaurant_components
SET component_type = 'groups_old_table_name'
WHERE component_type = 'components_new_table_name';
SET component_type = 'components_new_table_name'
WHERE component_type = 'groups_old_table_name';
```
**4. If you store files in groups, update the `related_type` values**
```sql
UPDATE upload_file_morph
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.
@ -454,47 +604,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`.

View File

@ -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.

View File

@ -1,7 +1,7 @@
{
"name": "getstarted",
"private": true,
"version": "3.0.0-beta.18.2",
"version": "3.0.0-beta.18.3",
"description": "A Strapi application.",
"scripts": {
"develop": "strapi develop",
@ -15,21 +15,21 @@
"mysql": "^2.17.1",
"pg": "^7.10.0",
"sqlite3": "^4.0.6",
"strapi": "3.0.0-beta.18.2",
"strapi-admin": "3.0.0-beta.18.2",
"strapi-connector-bookshelf": "3.0.0-beta.18.2",
"strapi-connector-mongoose": "3.0.0-beta.18.2",
"strapi-middleware-views": "3.0.0-beta.18.2",
"strapi-plugin-content-manager": "3.0.0-beta.18.2",
"strapi-plugin-content-type-builder": "3.0.0-beta.18.2",
"strapi-plugin-documentation": "3.0.0-beta.18.2",
"strapi-plugin-email": "3.0.0-beta.18.2",
"strapi-plugin-graphql": "3.0.0-beta.18.2",
"strapi-plugin-upload": "3.0.0-beta.18.2",
"strapi-plugin-users-permissions": "3.0.0-beta.18.2",
"strapi-provider-email-mailgun": "3.0.0-beta.18.2",
"strapi-provider-upload-aws-s3": "3.0.0-beta.18.2",
"strapi-utils": "3.0.0-beta.18.2"
"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-connector-mongoose": "3.0.0-beta.18.3",
"strapi-middleware-views": "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-documentation": "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-provider-email-mailgun": "3.0.0-beta.18.3",
"strapi-provider-upload-aws-s3": "3.0.0-beta.18.3",
"strapi-utils": "3.0.0-beta.18.3"
},
"strapi": {
"uuid": "getstarted"

View File

@ -1,5 +1,5 @@
{
"version": "3.0.0-beta.18.2",
"version": "3.0.0-beta.18.3",
"packages": [
"packages/*",
"examples/*"

View File

@ -1,6 +1,6 @@
{
"name": "create-strapi-app",
"version": "3.0.0-beta.18.2",
"version": "3.0.0-beta.18.3",
"description": "Generate a new Strapi application.",
"license": "MIT",
"homepage": "http://strapi.io",
@ -21,7 +21,7 @@
],
"dependencies": {
"commander": "^2.20.0",
"strapi-generate-new": "3.0.0-beta.18.2"
"strapi-generate-new": "3.0.0-beta.18.3"
},
"scripts": {
"test": "echo \"no tests yet\""

View File

@ -1,6 +1,6 @@
{
"name": "strapi-admin",
"version": "3.0.0-beta.18.2",
"version": "3.0.0-beta.18.3",
"description": "Strapi Admin",
"repository": {
"type": "git",
@ -80,8 +80,8 @@
"reselect": "^3.0.1",
"sanitize.css": "^4.1.0",
"shelljs": "^0.7.8",
"strapi-helper-plugin": "3.0.0-beta.18.2",
"strapi-utils": "3.0.0-beta.18.2",
"strapi-helper-plugin": "3.0.0-beta.18.3",
"strapi-utils": "3.0.0-beta.18.3",
"style-loader": "^0.23.1",
"styled-components": "^4.2.0",
"terser-webpack-plugin": "^1.2.3",

View File

@ -54,8 +54,21 @@ const populateBareAssociations = (definition, { prefix = '' } = {}) => {
});
}
return `${prefix}${assoc.alias}`;
});
const path = `${prefix}${assoc.alias}`;
const assocModel = findModelByAssoc({ assoc });
const polyAssocs = assocModel.associations
.filter(assoc => isPolymorphic({ assoc }))
.map(assoc =>
formatPolymorphicPopulate({
assoc,
prefix: `${path}.`,
})
);
return [path, ...polyAssocs];
})
.reduce((acc, val) => acc.concat(val), []);
};
const formatAssociationPopulate = ({ assoc, prefix = '' }) => {

View File

@ -1,6 +1,6 @@
{
"name": "strapi-connector-bookshelf",
"version": "3.0.0-beta.18.2",
"version": "3.0.0-beta.18.3",
"description": "Bookshelf hook for the Strapi framework",
"homepage": "http://strapi.io",
"keywords": [
@ -22,7 +22,7 @@
"lodash": "^4.17.11",
"pluralize": "^7.0.0",
"rimraf": "^2.6.3",
"strapi-utils": "3.0.0-beta.18.2"
"strapi-utils": "3.0.0-beta.18.3"
},
"strapi": {
"dependencies": [

View File

@ -1,6 +1,6 @@
{
"name": "strapi-connector-mongoose",
"version": "3.0.0-beta.18.2",
"version": "3.0.0-beta.18.3",
"description": "Mongoose hook for the Strapi framework",
"homepage": "http://strapi.io",
"keywords": [
@ -20,7 +20,7 @@
"mongoose-float": "^1.0.4",
"mongoose-long": "^0.2.1",
"pluralize": "^7.0.0",
"strapi-utils": "3.0.0-beta.18.2"
"strapi-utils": "3.0.0-beta.18.3"
},
"author": {
"email": "hi@strapi.io",

View File

@ -1,6 +1,6 @@
{
"name": "strapi-database",
"version": "3.0.0-beta.18.2",
"version": "3.0.0-beta.18.3",
"description": "Strapi's database layer",
"homepage": "http://strapi.io",
"main": "./lib/index.js",

View File

@ -1,6 +1,6 @@
{
"name": "strapi-generate-api",
"version": "3.0.0-beta.18.2",
"version": "3.0.0-beta.18.3",
"description": "Generate an API for a Strapi application.",
"homepage": "http://strapi.io",
"keywords": [

View File

@ -1,6 +1,6 @@
{
"name": "strapi-generate-controller",
"version": "3.0.0-beta.18.2",
"version": "3.0.0-beta.18.3",
"description": "Generate a controller for a Strapi API.",
"homepage": "http://strapi.io",
"keywords": [

View File

@ -1,6 +1,6 @@
{
"name": "strapi-generate-model",
"version": "3.0.0-beta.18.2",
"version": "3.0.0-beta.18.3",
"description": "Generate a model for a Strapi API.",
"homepage": "http://strapi.io",
"keywords": [

View File

@ -164,7 +164,7 @@ async function askDatabaseInfos(scope) {
}
async function installDatabaseTestingDep({ scope, configuration }) {
let packageManager = scope.useYarn ? 'yarnpkg' : 'npm;';
let packageManager = scope.useYarn ? 'yarnpkg' : 'npm';
let cmd = scope.useYarn
? ['--cwd', scope.tmpPath, 'add']
: ['install', '--prefix', scope.tmpPath];

View File

@ -1,6 +1,6 @@
{
"name": "strapi-generate-new",
"version": "3.0.0-beta.18.2",
"version": "3.0.0-beta.18.3",
"description": "Generate a new Strapi application.",
"homepage": "http://strapi.io",
"keywords": [

View File

@ -1,6 +1,6 @@
{
"name": "strapi-generate-plugin",
"version": "3.0.0-beta.18.2",
"version": "3.0.0-beta.18.3",
"description": "Generate an plugin for a Strapi application.",
"homepage": "http://strapi.io",
"keywords": [

View File

@ -1,6 +1,6 @@
{
"name": "strapi-generate-policy",
"version": "3.0.0-beta.18.2",
"version": "3.0.0-beta.18.3",
"description": "Generate a policy for a Strapi API.",
"homepage": "http://strapi.io",
"keywords": [

View File

@ -1,6 +1,6 @@
{
"name": "strapi-generate-service",
"version": "3.0.0-beta.18.2",
"version": "3.0.0-beta.18.3",
"description": "Generate a service for a Strapi API.",
"homepage": "http://strapi.io",
"keywords": [

View File

@ -1,6 +1,6 @@
{
"name": "strapi-generate",
"version": "3.0.0-beta.18.2",
"version": "3.0.0-beta.18.3",
"description": "Master of ceremonies for the Strapi generators.",
"homepage": "http://strapi.io",
"keywords": [
@ -20,7 +20,7 @@
"fs-extra": "^8.0.1",
"lodash": "^4.17.11",
"reportback": "^2.0.2",
"strapi-utils": "3.0.0-beta.18.2"
"strapi-utils": "3.0.0-beta.18.3"
},
"author": {
"name": "Strapi team",

View File

@ -1,6 +1,6 @@
{
"name": "strapi-helper-plugin",
"version": "3.0.0-beta.18.2",
"version": "3.0.0-beta.18.3",
"description": "Helper for Strapi plugins development",
"files": [
"dist"

View File

@ -1,6 +1,6 @@
{
"name": "strapi-hook-ejs",
"version": "3.0.0-beta.18.2",
"version": "3.0.0-beta.18.3",
"description": "EJS hook for the Strapi framework",
"homepage": "http://strapi.io",
"keywords": [

View File

@ -1,6 +1,6 @@
{
"name": "strapi-hook-redis",
"version": "3.0.0-beta.18.2",
"version": "3.0.0-beta.18.3",
"description": "Redis hook for the Strapi framework",
"homepage": "http://strapi.io",
"keywords": [
@ -19,7 +19,7 @@
"lodash": "^4.17.11",
"rimraf": "^2.6.3",
"stack-trace": "0.0.10",
"strapi-utils": "3.0.0-beta.18.2"
"strapi-utils": "3.0.0-beta.18.3"
},
"author": {
"email": "hi@strapi.io",

View File

@ -1,6 +1,6 @@
{
"name": "strapi-middleware-views",
"version": "3.0.0-beta.18.2",
"version": "3.0.0-beta.18.3",
"description": "Views middleware to enable server-side rendering for the Strapi framework",
"homepage": "http://strapi.io",
"keywords": [

View File

@ -1,6 +1,6 @@
{
"name": "strapi-plugin-content-manager",
"version": "3.0.0-beta.18.2",
"version": "3.0.0-beta.18.3",
"description": "A powerful UI to easily manage your data.",
"strapi": {
"name": "Content Manager",
@ -32,8 +32,8 @@
"redux-immutable": "^4.0.0",
"reselect": "^3.0.1",
"showdown": "^1.9.0",
"strapi-helper-plugin": "3.0.0-beta.18.2",
"strapi-utils": "3.0.0-beta.18.2",
"strapi-helper-plugin": "3.0.0-beta.18.3",
"strapi-utils": "3.0.0-beta.18.3",
"styled-components": "^4.2.0",
"yup": "^0.27.0"
},

View File

@ -0,0 +1,12 @@
import styled from 'styled-components';
import { colors } from 'strapi-helper-plugin';
const Search = styled.input`
width: 100%;
padding: 0 21px;
outline: 0;
color: ${colors.leftMenu.black};
`;
export default Search;

View File

@ -0,0 +1,34 @@
import styled from 'styled-components';
import { colors } from 'strapi-helper-plugin';
const SearchWrapper = styled.div`
position: relative;
margin-top: -2px;
&::after {
display: block;
content: '';
height: 2px;
width: calc(100% - 20px);
background: ${colors.leftMenu.lightGrey};
}
> svg {
position: absolute;
bottom: 15px;
left: 0;
font-size: 11px;
}
button {
position: absolute;
top: 1px;
right: 0;
padding: 5px 0 0px 5px;
line-height: 11px;
outline: 0;
i,
svg {
font-size: 11px;
}
}
`;
export default SearchWrapper;

View File

@ -36,6 +36,17 @@ const Wrapper = styled.div`
font-size: 1em;
color: #bdbdbd;
}
.search {
display: flex;
padding-top: 2px;
color: #919bae;
> button {
margin-top: -8px;
font-size: 1.3rem;
outline: 0;
}
}
`;
Wrapper.defaultProps = {

View File

@ -1,9 +1,12 @@
import React, { useState } from 'react';
import React, { createRef, useEffect, useState } from 'react';
import { Label, ErrorMessage } from '@buffetjs/styles';
import { AutoSizer, Collection } from 'react-virtualized';
import PropTypes from 'prop-types';
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import useDataManager from '../../hooks/useDataManager';
import CellRenderer from './CellRenderer';
import Search from './Search';
import SearchWrapper from './SearchWrapper';
import Wrapper from './Wrapper';
const ComponentIconPicker = ({
@ -15,9 +18,7 @@ const ComponentIconPicker = ({
value,
}) => {
const { allIcons, allComponentsIconAlreadyTaken } = useDataManager();
const [originalIcon] = useState(value);
const icons = allIcons.filter(ico => {
const initialIcons = allIcons.filter(ico => {
if (isCreating) {
return !allComponentsIconAlreadyTaken.includes(ico);
}
@ -27,6 +28,18 @@ const ComponentIconPicker = ({
.filter(icon => icon !== originalIcon)
.includes(ico);
});
const ref = createRef();
const [originalIcon] = useState(value);
const [showSearch, setShowSearch] = useState(false);
const [search, setSearch] = useState('');
const [icons, setIcons] = useState(initialIcons);
const toggleSearch = () => setShowSearch(prev => !prev);
useEffect(() => {
if (showSearch && ref.current) {
ref.current.focus();
}
}, [ref, showSearch]);
const cellCount = icons.length;
@ -54,9 +67,42 @@ const ComponentIconPicker = ({
return (
<Wrapper error={error !== null}>
<Label htmlFor={name} style={{ marginBottom: 12 }}>
{label}
</Label>
<div className="search">
<Label htmlFor={name} style={{ marginBottom: 12 }}>
{label}
</Label>
{!showSearch ? (
<button onClick={toggleSearch} type="button">
<FontAwesomeIcon icon="search" />
</button>
) : (
<SearchWrapper>
<FontAwesomeIcon icon="search" />
<button onClick={toggleSearch}></button>
<Search
ref={ref}
onChange={({ target: { value } }) => {
setSearch(value);
setIcons(() =>
initialIcons.filter(icon => icon.includes(value))
);
}}
value={search}
placeholder="search…"
/>
<button
onClick={() => {
setSearch('');
setIcons(initialIcons);
toggleSearch();
}}
type="button"
>
<FontAwesomeIcon icon="times" />
</button>
</SearchWrapper>
)}
</div>
<AutoSizer disableHeight>
{({ width }) => {
return (

View File

@ -12,6 +12,7 @@ import UpperFirst from '../UpperFirst';
import SubUl from './SubUl';
import Ul from './Ul';
import hasSubArray from './utils/hasSubArray';
import hasSomeSubArray from './utils/HasSomeSubArray';
const MultipleMenuList = ({
selectProps: { name, addComponentsToDynamicZone, inputValue, value },
@ -118,6 +119,12 @@ const MultipleMenuList = ({
return hasSubArray(value.value, componentsCategory);
};
const doesCategoryHasSomeElements = categoryName => {
const componentsCategory = allComponentsCategory[categoryName];
return hasSomeSubArray(value.value, componentsCategory);
};
const handleChangeCategory = ({ target }) => {
// refState.current.select.blur();
const dataTarget = {
@ -158,6 +165,8 @@ const MultipleMenuList = ({
)}
{Object.keys(options).map(categoryName => {
const isChecked = getCategoryValue(categoryName);
const someChecked =
!isChecked && doesCategoryHasSomeElements(categoryName);
const target = { name: categoryName, value: !isChecked };
return (
@ -172,9 +181,10 @@ const MultipleMenuList = ({
>
<Checkbox
id="checkCategory"
checked={isChecked}
name={categoryName}
onChange={() => {}}
checked={getCategoryValue(categoryName)}
someChecked={someChecked}
style={{ marginRight: 10 }}
/>
<UpperFirst content={categoryName} />

View File

@ -0,0 +1,5 @@
const hasSomeSubArray = (master, sub) => {
return sub.some(v => master.indexOf(v) !== -1);
};
export default hasSomeSubArray;

View File

@ -114,6 +114,7 @@ const reducer = (state, action) => {
'componentToCreate',
]);
const modifiedData = fromJS({
name: componentToCreate.get('name'),
type: 'component',
repeatable: false,
component: createComponentUid(

View File

@ -354,6 +354,7 @@ const forms = {
},
],
[fields.divider],
[fields.private],
[fields.required],
[fields.unique],
];

View File

@ -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',

View File

@ -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",

View File

@ -1,6 +1,6 @@
{
"name": "strapi-plugin-content-type-builder",
"version": "3.0.0-beta.18.2",
"version": "3.0.0-beta.18.3",
"description": "Strapi plugin to create content type (API).",
"strapi": {
"name": "Content Type Builder",
@ -29,9 +29,9 @@
"redux": "^4.0.1",
"redux-immutable": "^4.0.0",
"reselect": "^3.0.1",
"strapi-generate": "3.0.0-beta.18.2",
"strapi-generate-api": "3.0.0-beta.18.2",
"strapi-helper-plugin": "3.0.0-beta.18.2",
"strapi-generate": "3.0.0-beta.18.3",
"strapi-generate-api": "3.0.0-beta.18.3",
"strapi-helper-plugin": "3.0.0-beta.18.3",
"yup": "^0.27.0"
},
"author": {

View File

@ -10,12 +10,13 @@ const createSchemaHandler = require('./schema-handler');
module.exports = function createComponentBuilder() {
return {
setRelation({ key, modelName, attribute }) {
setRelation({ key, modelName, plugin, attribute }) {
this.contentTypes.get(attribute.target).setAttribute(
attribute.targetAttribute,
generateRelation({
key,
attribute,
plugin,
modelName,
})
);
@ -93,6 +94,7 @@ module.exports = function createComponentBuilder() {
this.setRelation({
key,
modelName: contentType.modelName,
plugin: contentType.plugin,
attribute,
});
}
@ -153,6 +155,7 @@ module.exports = function createComponentBuilder() {
return this.setRelation({
key,
modelName: contentType.modelName,
plugin: contentType.plugin,
attribute: newAttributes[key],
});
}
@ -172,6 +175,7 @@ module.exports = function createComponentBuilder() {
return this.setRelation({
key,
modelName: contentType.modelName,
plugin: contentType.plugin,
attribute: newAttribute,
});
}
@ -185,6 +189,7 @@ module.exports = function createComponentBuilder() {
this.setRelation({
key,
modelName: contentType.modelName,
plugin: contentType.plugin,
attribute,
});
}
@ -227,9 +232,10 @@ module.exports = function createComponentBuilder() {
const createContentTypeUID = ({ name }) =>
`application::${nameToSlug(name)}.${nameToSlug(name)}`;
const generateRelation = ({ key, attribute, modelName }) => {
const generateRelation = ({ key, attribute, plugin, modelName }) => {
const opts = {
via: key,
plugin,
columnName: attribute.targetColumnName || undefined,
};

View File

@ -1,6 +1,6 @@
{
"name": "strapi-plugin-documentation",
"version": "3.0.0-beta.18.2",
"version": "3.0.0-beta.18.3",
"description": "This is the description of the plugin.",
"strapi": {
"name": "Documentation",
@ -32,7 +32,7 @@
"redux": "^4.0.1",
"redux-immutable": "^4.0.0",
"reselect": "^4.0.0",
"strapi-helper-plugin": "3.0.0-beta.18.2",
"strapi-helper-plugin": "3.0.0-beta.18.3",
"swagger-ui-dist": "3.24.3"
},
"author": {

View File

@ -471,7 +471,7 @@ module.exports = {
current.handler,
key,
endPoint.split('/')[1],
current.config.description
_.get(current, 'config.description')
),
responses: this.generateResponses(verb, current, key),
summary: '',

View File

@ -1,6 +1,6 @@
{
"name": "strapi-plugin-email",
"version": "3.0.0-beta.18.2",
"version": "3.0.0-beta.18.3",
"description": "This is the description of the plugin.",
"strapi": {
"name": "Email",
@ -12,13 +12,13 @@
"test": "echo \"no tests yet\""
},
"dependencies": {
"strapi-provider-email-sendmail": "3.0.0-beta.18.2",
"strapi-utils": "3.0.0-beta.18.2"
"strapi-provider-email-sendmail": "3.0.0-beta.18.3",
"strapi-utils": "3.0.0-beta.18.3"
},
"devDependencies": {
"react-copy-to-clipboard": "5.0.1",
"rimraf": "^2.6.3",
"strapi-helper-plugin": "3.0.0-beta.18.2"
"strapi-helper-plugin": "3.0.0-beta.18.3"
},
"author": {
"name": "Strapi team",

View File

@ -1,6 +1,6 @@
{
"name": "strapi-plugin-graphql",
"version": "3.0.0-beta.18.2",
"version": "3.0.0-beta.18.3",
"description": "This is the description of the plugin.",
"strapi": {
"name": "graphql",
@ -23,7 +23,7 @@
"graphql-type-long": "^0.1.1",
"koa-compose": "^4.1.0",
"pluralize": "^7.0.0",
"strapi-utils": "3.0.0-beta.18.2"
"strapi-utils": "3.0.0-beta.18.3"
},
"devDependencies": {
"cross-env": "^5.2.0",

View File

@ -1,6 +1,6 @@
{
"name": "strapi-plugin-upload",
"version": "3.0.0-beta.18.2",
"version": "3.0.0-beta.18.3",
"description": "This is the description of the plugin.",
"strapi": {
"name": "Files Upload",
@ -23,9 +23,9 @@
"react-router-dom": "^5.0.0",
"react-transition-group": "^2.5.0",
"reactstrap": "^5.0.0",
"strapi-helper-plugin": "3.0.0-beta.18.2",
"strapi-provider-upload-local": "3.0.0-beta.18.2",
"strapi-utils": "3.0.0-beta.18.2",
"strapi-helper-plugin": "3.0.0-beta.18.3",
"strapi-provider-upload-local": "3.0.0-beta.18.3",
"strapi-utils": "3.0.0-beta.18.3",
"stream-to-array": "^2.3.0",
"uuid": "^3.2.1"
},

View File

@ -70,6 +70,8 @@ class PopUpForm extends React.Component {
return `${strapi.backendURL}/connect/twitter/callback`;
case 'instagram':
return `${strapi.backendURL}/connect/instagram/callback`;
case 'vk':
return `${strapi.backendURL}/connect/vk/callback`;
default: {
const value = get(this.props.values, 'callback', '');

View File

@ -85,6 +85,7 @@
"PopUpForm.Providers.github.providerConfig.redirectURL": "The redirect URL to add in your GitHub application configurations",
"PopUpForm.Providers.google.providerConfig.redirectURL": "The redirect URL to add in your Google application configurations",
"PopUpForm.Providers.instagram.providerConfig.redirectURL": "The redirect URL to add in your Instagram application configurations",
"PopUpForm.Providers.vk.providerConfig.redirectURL": "The redirect URL to add in your VK application configurations",
"PopUpForm.Providers.key.label": "Client ID",
"PopUpForm.Providers.key.placeholder": "TEXT",
"PopUpForm.Providers.linkedin2.providerConfig.redirectURL": "The redirect URL to add in your Linkedin application configurations",

View File

@ -84,6 +84,7 @@
"PopUpForm.Providers.github.providerConfig.redirectURL": "URL-адрес перенаправления, который необходимо добавить в настройки GitHub приложения",
"PopUpForm.Providers.google.providerConfig.redirectURL": "URL-адрес перенаправления, который необходимо добавить в настройки Google приложения",
"PopUpForm.Providers.instagram.providerConfig.redirectURL": "URL-адрес перенаправления, который необходимо добавить в настройки Instagram приложения",
"PopUpForm.Providers.vk.providerConfig.redirectURL": "URL-адрес перенаправления, который необходимо добавить в настройки VK приложения",
"PopUpForm.Providers.key.label": "Client ID",
"PopUpForm.Providers.key.placeholder": "TEXT",
"PopUpForm.Providers.linkedin2.providerConfig.redirectURL": "URL-адрес перенаправления, который необходимо добавить в настройки Linkedin приложения",

View File

@ -89,6 +89,14 @@ module.exports = async () => {
secret: '',
callback: '/auth/instagram/callback',
},
vk: {
enabled: false,
icon: 'vk',
key: '',
secret: '',
callback: '/auth/vk/callback',
scope: ['email'],
},
};
const prevGrantConfig = (await pluginStore.get({ key: 'grant' })) || {};
// store grant auth config to db

View File

@ -43,7 +43,7 @@ module.exports = {
type UsersPermissionsLoginPayload {
jwt: String!
user: UsersPermissionsUser!
user: UsersPermissionsMe!
}
`,
query: `

View File

@ -1,6 +1,6 @@
{
"name": "strapi-plugin-users-permissions",
"version": "3.0.0-beta.18.2",
"version": "3.0.0-beta.18.3",
"description": "Protect your API with a full-authentication process based on JWT",
"strapi": {
"name": "Roles & Permissions",
@ -31,8 +31,8 @@
"reactstrap": "^5.0.0",
"redux-saga": "^0.16.0",
"request": "^2.83.0",
"strapi-helper-plugin": "3.0.0-beta.18.2",
"strapi-utils": "3.0.0-beta.18.2",
"strapi-helper-plugin": "3.0.0-beta.18.3",
"strapi-utils": "3.0.0-beta.18.3",
"uuid": "^3.1.0"
},
"devDependencies": {

View File

@ -370,6 +370,25 @@ const getProfile = async (provider, query, callback) => {
});
break;
}
case 'vk': {
const vk = new Purest({ provider: 'vk' });
vk.query()
.get('users.get')
.auth(access_token)
.qs({ id: query.raw.user_id, v: '5.013' })
.request((err, res, body) => {
if (err) {
callback(err);
} else {
callback(null, {
username: `${body.response[0].last_name} ${body.response[0].first_name}`,
email: query.raw.email,
});
}
});
break;
}
default:
callback({
message: 'Unknown provider.',

View File

@ -45,8 +45,8 @@ module.exports = {
* Promise to fetch a/an user.
* @return {Promise}
*/
fetch(params) {
return strapi.query('user', 'users-permissions').findOne(params);
fetch(params, populate) {
return strapi.query('user', 'users-permissions').findOne(params, populate);
},
/**

View File

@ -1,6 +1,6 @@
{
"name": "strapi-provider-email-amazon-ses",
"version": "3.0.0-beta.18.2",
"version": "3.0.0-beta.18.3",
"description": "Amazon SES provider for strapi email",
"homepage": "http://strapi.io",
"keywords": [

View File

@ -1,6 +1,6 @@
{
"name": "strapi-provider-email-mailgun",
"version": "3.0.0-beta.18.2",
"version": "3.0.0-beta.18.3",
"description": "Mailgun provider for strapi email plugin",
"homepage": "http://strapi.io",
"keywords": [

View File

@ -1,6 +1,6 @@
{
"name": "strapi-provider-email-sendgrid",
"version": "3.0.0-beta.18.2",
"version": "3.0.0-beta.18.3",
"description": "Sendgrid provider for strapi email",
"homepage": "http://strapi.io",
"keywords": [

View File

@ -1,6 +1,6 @@
{
"name": "strapi-provider-email-sendmail",
"version": "3.0.0-beta.18.2",
"version": "3.0.0-beta.18.3",
"description": "Sendmail provider for strapi email",
"homepage": "http://strapi.io",
"keywords": [

View File

@ -1,6 +1,6 @@
{
"name": "strapi-provider-upload-aws-s3",
"version": "3.0.0-beta.18.2",
"version": "3.0.0-beta.18.3",
"description": "AWS S3 provider for strapi upload",
"homepage": "http://strapi.io",
"keywords": [

View File

@ -1,6 +1,6 @@
{
"name": "strapi-provider-upload-cloudinary",
"version": "3.0.0-beta.18.2",
"version": "3.0.0-beta.18.3",
"description": "Cloudinary provider for strapi upload",
"homepage": "http://strapi.io",
"keywords": [

View File

@ -1,6 +1,6 @@
{
"name": "strapi-provider-upload-local",
"version": "3.0.0-beta.18.2",
"version": "3.0.0-beta.18.3",
"description": "Local provider for strapi upload",
"homepage": "http://strapi.io",
"keywords": [

View File

@ -1,6 +1,6 @@
{
"name": "strapi-provider-upload-rackspace",
"version": "3.0.0-beta.18.2",
"version": "3.0.0-beta.18.3",
"description": "Rackspace provider for strapi upload",
"main": "./lib",
"keywords": [],

View File

@ -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'.`
);
}

View File

@ -1,6 +1,6 @@
{
"name": "strapi-utils",
"version": "3.0.0-beta.18.2",
"version": "3.0.0-beta.18.3",
"description": "Shared utilities for the Strapi packages",
"homepage": "http://strapi.io",
"keywords": [

View File

@ -1,6 +1,6 @@
{
"name": "strapi",
"version": "3.0.0-beta.18.2",
"version": "3.0.0-beta.18.3",
"description": "An open source headless CMS solution to create and manage your own API. It provides a powerful dashboard and features to make your life easier. Databases supported: MongoDB, MySQL, MariaDB, PostgreSQL, SQLite",
"homepage": "http://strapi.io",
"directories": {
@ -49,16 +49,16 @@
"resolve-cwd": "^3.0.0",
"rimraf": "^2.6.2",
"shelljs": "^0.8.3",
"strapi-database": "3.0.0-beta.18.2",
"strapi-generate": "3.0.0-beta.18.2",
"strapi-generate-api": "3.0.0-beta.18.2",
"strapi-generate-controller": "3.0.0-beta.18.2",
"strapi-generate-model": "3.0.0-beta.18.2",
"strapi-generate-new": "3.0.0-beta.18.2",
"strapi-generate-plugin": "3.0.0-beta.18.2",
"strapi-generate-policy": "3.0.0-beta.18.2",
"strapi-generate-service": "3.0.0-beta.18.2",
"strapi-utils": "3.0.0-beta.18.2"
"strapi-database": "3.0.0-beta.18.3",
"strapi-generate": "3.0.0-beta.18.3",
"strapi-generate-api": "3.0.0-beta.18.3",
"strapi-generate-controller": "3.0.0-beta.18.3",
"strapi-generate-model": "3.0.0-beta.18.3",
"strapi-generate-new": "3.0.0-beta.18.3",
"strapi-generate-plugin": "3.0.0-beta.18.3",
"strapi-generate-policy": "3.0.0-beta.18.3",
"strapi-generate-service": "3.0.0-beta.18.3",
"strapi-utils": "3.0.0-beta.18.3"
},
"scripts": {
"test": "jest --verbose",