mirror of
https://github.com/strapi/strapi.git
synced 2025-12-09 14:03:52 +00:00
Merge branch 'front/global-improvements' of github.com:strapi/strapi into front/global-improvements
This commit is contained in:
commit
6b85cb28fa
@ -132,6 +132,12 @@ Additional settings can be set on models:
|
||||
|
||||
In this example, the model `Restaurant` will be accessible through the `Restaurants` global variable. The data will be stored in the `Restaurants_v1` collection or table and the model will use the `mongo` connection defined in `./config/environments/**/database.json`
|
||||
|
||||
::: warning
|
||||
If not set manually in the JSON file, Strapi will adopt the filename as `globalId`.
|
||||
The `globalId` serves as a reference to your model within relations and Strapi APIs. If you chose to rename it (either by renaming your file or by changing the value of the `globalId`), you'd have to migrate your tables manually and update the references.
|
||||
Please note that you should not alter Strapi's models `globalId` (plugins and core ones) since it is used directly within Strapi APIs and other models' relations.
|
||||
:::
|
||||
|
||||
::: tip
|
||||
The `connection` value can be changed whenever you want, but you should be aware that there is no automatic data migration process. Also if the new connection doesn't use the same ORM you will have to rewrite your queries.
|
||||
:::
|
||||
@ -159,10 +165,7 @@ The info key on the model-json states information about the model. This informat
|
||||
|
||||
The options key on the model-json states.
|
||||
|
||||
- `idAttribute`: This tells the model which attribute to expect as the unique identifier for each database row (typically an auto-incrementing primary key named 'id'). _Only valid for bookshelf._
|
||||
- `idAttributeType`: Data type of `idAttribute`, accepted list of value below. _Only valid for bookshelf._
|
||||
- `timestamps`: This tells the model which attributes to use for timestamps. Accepts either `boolean` or `Array` of strings where first element is create date and second element is update date. Default value when set to `true` for Bookshelf is `["created_at", "updated_at"]` and for MongoDB is `["createdAt", "updatedAt"]`.
|
||||
- `uuid` : Boolean to enable UUID support on MySQL, you will need to set the `idAttributeType` to `uuid` as well and install the `bookshelf-uuid` package. To load the package you can see [this example](./configurations.md#bookshelf-mongoose).
|
||||
|
||||
**Path —** `User.settings.json`.
|
||||
|
||||
|
||||
@ -137,12 +137,13 @@ module.exports = {
|
||||
*/
|
||||
|
||||
async create(data, { files } = {}) {
|
||||
const entry = await strapi.query(model).create(data);
|
||||
const entry = await strapi.query('restaurant').create(data);
|
||||
|
||||
if (files) {
|
||||
// automatically uploads the files based on the entry and the model
|
||||
await strapi.entityService.uploadFiles(entry, files, {
|
||||
model: strapi.models.restaurant,
|
||||
model: 'restaurant',
|
||||
// if you are using a plugin's model you will have to add the `plugin` key (plugin: 'users-permissions')
|
||||
});
|
||||
return this.findOne({ id: entry.id });
|
||||
}
|
||||
@ -167,12 +168,13 @@ module.exports = {
|
||||
*/
|
||||
|
||||
async update(params, data, { files } = {}) {
|
||||
const entry = await strapi.query(model).update(params, data);
|
||||
const entry = await strapi.query('restaurant').update(params, data);
|
||||
|
||||
if (files) {
|
||||
// automatically uploads the files based on the entry and the model
|
||||
await strapi.entityService.uploadFiles(entry, files, {
|
||||
model: strapi.models.restaurant,
|
||||
model: 'restaurant',
|
||||
// if you are using a plugin's model you will have to add the `plugin` key (plugin: 'users-permissions')
|
||||
});
|
||||
return this.findOne({ id: entry.id });
|
||||
}
|
||||
|
||||
307
docs/3.0.0-beta.x/deployment/google-app-engine.md
Normal file
307
docs/3.0.0-beta.x/deployment/google-app-engine.md
Normal file
@ -0,0 +1,307 @@
|
||||
# Google App Engine
|
||||
|
||||
In this guide we are going to:
|
||||
|
||||
- Create a new Strapi project
|
||||
- Configure PostgreSQL for the production enviroment
|
||||
- Deploy the app to Google App Engine
|
||||
- Add the [Google Cloud Storage file uploading plugin](https://github.com/Lith/strapi-provider-upload-google-cloud-storage) by [@Lith](https://github.com/Lith)
|
||||
|
||||
### New Strapi project
|
||||
|
||||
:::: tabs
|
||||
|
||||
::: tab yarn
|
||||
|
||||
Use **yarn** to install the Strapi project (**recommended**). [Install yarn with these docs](https://yarnpkg.com/lang/en/docs/install/)
|
||||
|
||||
```bash
|
||||
yarn create strapi-app my-project --quickstart
|
||||
```
|
||||
|
||||
:::
|
||||
|
||||
::: tab npx
|
||||
|
||||
Use **npm/npx** to install the Strapi project
|
||||
|
||||
```bash
|
||||
npx create-strapi-app my-project --quickstart
|
||||
```
|
||||
|
||||
:::
|
||||
|
||||
::::
|
||||
|
||||
When the setup completes, register an admin user using the form which opens in the browser. This user will be only relevant in local development.
|
||||
|
||||
The `sqlite` database is created at `.tmp/data.db`.
|
||||
|
||||
Login, but don't add content types yet. Close the browser. Quit the running app.
|
||||
|
||||
### Initial commit
|
||||
|
||||
This may be a good point to commit the files in their initial state.
|
||||
|
||||
```bash
|
||||
cd my-project
|
||||
git init
|
||||
git add .
|
||||
git commit -m first
|
||||
```
|
||||
|
||||
### Install the Cloud SDK CLI tool
|
||||
|
||||
[Cloud SDK: Command Line Interface](https://cloud.google.com/sdk/)
|
||||
|
||||
### New App Engine project
|
||||
|
||||
Create a new [App Engine](https://console.cloud.google.com/appengine/) project.
|
||||
|
||||
Select the region, such as `europe-west`.
|
||||
|
||||
- Language: Node JS
|
||||
- Environment: Standard (or Flexible)
|
||||
|
||||
(_A note on performance and cost_: the `Standard Environment` is sufficient for development, but it may not be for production. Review the resources your application will need to determine the cost. When you sign up for Google App Engine, it offers a certain amount of free credits which will not be billed.)
|
||||
|
||||
Create the project. Take note of the instance identifier, which is in the form of `<instance_id>:<region>:<instance_name>`.
|
||||
|
||||
Check if `gcloud` lists the project:
|
||||
|
||||
```bash
|
||||
gcloud projects list
|
||||
```
|
||||
|
||||
Run `init` to authenticate the cli, and select current cloud project.
|
||||
|
||||
```bash
|
||||
gcloud init
|
||||
```
|
||||
|
||||
### Create the database (PostgreSQL)
|
||||
|
||||
Create the [Cloud SQL database](https://cloud.google.com/sql/docs/postgres/create-manage-databases) which the app is going to use.
|
||||
|
||||
Take note of the user name (default is `postgres`) and password.
|
||||
|
||||
The first database will be created with the name `postgres`. This cannot be deleted.
|
||||
|
||||
Create another database, named `strapi` for example. It may be useful to delete and and re-create this while you are experimenting with the application setup.
|
||||
|
||||
### Create app.yaml and .gcloudignore
|
||||
|
||||
Create the `app.yaml` file in the project root.
|
||||
|
||||
Add `app.yaml` to `.gitignore`.
|
||||
|
||||
The instance identifier looks like `myapi-123456:europe-west1:myapi`.
|
||||
|
||||
The `myapi-123456` part is the project identifier. (The number is automatically added to short project names).
|
||||
|
||||
The following is an example config for `Standard Environment` or `Flexible Environment`.
|
||||
|
||||
:::: tabs
|
||||
|
||||
::: tab Standard Environment
|
||||
|
||||
```yaml
|
||||
runtime: nodejs10
|
||||
|
||||
instance_class: F2
|
||||
|
||||
env_variables:
|
||||
HOST: '<project_id>.appspot.com'
|
||||
NODE_ENV: 'production'
|
||||
DATABASE_NAME: 'strapi'
|
||||
DATABASE_USERNAME: 'postgres'
|
||||
DATABASE_PASSWORD: '<password>'
|
||||
INSTANCE_CONNECTION_NAME: '<instance_identifier>'
|
||||
|
||||
beta_settings:
|
||||
cloud_sql_instances: '<instance_identifier>'
|
||||
```
|
||||
|
||||
:::
|
||||
|
||||
::: tab Flexible Environment
|
||||
|
||||
```yaml
|
||||
runtime: nodejs10
|
||||
|
||||
env: flex
|
||||
|
||||
env_variables:
|
||||
HOST: '<project_id>.appspot.com'
|
||||
NODE_ENV: 'production'
|
||||
DATABASE_NAME: 'strapi'
|
||||
DATABASE_USERNAME: 'postgres'
|
||||
DATABASE_PASSWORD: '<password>'
|
||||
INSTANCE_CONNECTION_NAME: '<instance_identifier>'
|
||||
|
||||
beta_settings:
|
||||
cloud_sql_instances: '<instance_identifier>'
|
||||
```
|
||||
|
||||
:::
|
||||
|
||||
::::
|
||||
|
||||
Create `.gcloudignore` in the project root, include `app.yaml` here as well.
|
||||
|
||||
```
|
||||
app.yaml
|
||||
.gcloudignore
|
||||
.git
|
||||
.gitignore
|
||||
node_modules/
|
||||
#!include:.gitignore
|
||||
```
|
||||
|
||||
In the case of Strapi, the admin UI will have to be re-built after every deploy,
|
||||
and so we don't deploy local build artifacts, cache files and so on by including
|
||||
the `.gitignore` entries.
|
||||
|
||||
### Configure the database
|
||||
|
||||
The `PostgreSQL` database will need the `pg` package.
|
||||
|
||||
```bash
|
||||
yarn add pg
|
||||
```
|
||||
|
||||
[Google App Engine requires](https://cloud.google.com/sql/docs/postgres/connect-app-engine) to connect to the database using the unix socket path, not an IP and port.
|
||||
|
||||
Edit `database.json`, and use the socket path as `host`.
|
||||
|
||||
```
|
||||
config/environments/production/database.json
|
||||
```
|
||||
|
||||
```json
|
||||
{
|
||||
"defaultConnection": "default",
|
||||
"connections": {
|
||||
"default": {
|
||||
"connector": "bookshelf",
|
||||
"settings": {
|
||||
"client": "postgres",
|
||||
"host": "/cloudsql/${process.env.INSTANCE_CONNECTION_NAME}",
|
||||
"database": "${process.env.DATABASE_NAME}",
|
||||
"username": "${process.env.DATABASE_USERNAME}",
|
||||
"password": "${process.env.DATABASE_PASSWORD}"
|
||||
},
|
||||
"options": {}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Edit `server.json` to pick up the deployed hostname from the `HOST` variable in `app.yaml`.
|
||||
|
||||
```
|
||||
config/environments/production/server.json
|
||||
```
|
||||
|
||||
```json
|
||||
{
|
||||
"host": "${process.env.HOST}",
|
||||
"port": "${process.env.PORT || 1337}",
|
||||
"production": true,
|
||||
"proxy": {
|
||||
"enabled": false
|
||||
},
|
||||
"cron": {
|
||||
"enabled": false
|
||||
},
|
||||
"admin": {
|
||||
"autoOpen": false
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Auto-build after deploy
|
||||
|
||||
After deployment, the admin UI has to be re-built. This generates the contents of the `build` folder on the server.
|
||||
|
||||
In `package.json`, add the `gcp-build` command to `scripts`:
|
||||
|
||||
```json
|
||||
{
|
||||
"scripts": {
|
||||
"gcp-build": "strapi build"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Deploy
|
||||
|
||||
```bash
|
||||
gcloud app deploy app.yaml --project myapi-123456
|
||||
```
|
||||
|
||||
Watch the logs:
|
||||
|
||||
```bash
|
||||
gcloud app logs tail --project=myapi-123456 -s default
|
||||
```
|
||||
|
||||
Open the admin page and register and admin user.
|
||||
|
||||
```
|
||||
https://myapp-123456.appspot.com/admin/
|
||||
```
|
||||
|
||||
### File uploading to Google Cloud Storage
|
||||
|
||||
[Lith/strapi-provider-upload-google-cloud-storage](https://github.com/Lith/strapi-provider-upload-google-cloud-storage)
|
||||
|
||||
```bash
|
||||
yarn add strapi-provider-upload-google-cloud-storage
|
||||
```
|
||||
|
||||
Deploy so that the server app includes the dependency from `package.json`.
|
||||
|
||||
Create a Google service account key.
|
||||
|
||||
<https://console.cloud.google.com/apis/credentials/serviceaccountkey>
|
||||
|
||||
Save the JSON credentials file.
|
||||
|
||||
Plugins > File Upload > Settings > Production tab
|
||||
|
||||
By default `localhost` is selected. Select the `Google Cloud Storage` plugin.
|
||||
|
||||
Copy the JSON key and set the regions.
|
||||
|
||||
Open the `Cloud Console > Storage > Browser` menu.
|
||||
|
||||
Copy the bucket name to the plugin settings, the default is the app ID, such as `myapi-123456.appspot.com`.
|
||||
|
||||
(Note that the `Access control` setting of the bucket has to be `Fine-grained`, which is the default.)
|
||||
|
||||
Click `Save`, and it's ready to go!
|
||||
|
||||
### Post-setup configuration
|
||||
|
||||
**CORS**
|
||||
|
||||
CORS is enabled by default, allowing `*` origin. You may want to limit the allowed origins.
|
||||
|
||||
```
|
||||
config/environments/production/security.json
|
||||
```
|
||||
|
||||
**Changing the admin url**
|
||||
|
||||
```
|
||||
config/environments/production/server.json
|
||||
```
|
||||
|
||||
```json
|
||||
{
|
||||
"admin": {
|
||||
"path": "/dashboard"
|
||||
}
|
||||
}
|
||||
```
|
||||
@ -46,6 +46,18 @@ Manual guides for deployment on various platforms, for One-click and docker plea
|
||||
</InstallLink>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<InstallLink link="../deployment/google-app-engine">
|
||||
<template #icon>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 24 24" version="1.1"><path d="M6.969 3L4.094 8.188l1.468 2.624L8.438 6h10.25L17 3zm8.75 4l2.969 4.906L13.625 21H17l5-9-2.781-5zM12 8c-2.207 0-4 1.793-4 4s1.793 4 4 4 4-1.793 4-4-1.793-4-4-4zM3.531 9.219L2 12l4.969 9H12.5l1.656-3h-5.75zM12 10c1.102 0 2 .898 2 2 0 1.102-.898 2-2 2-1.102 0-2-.898-2-2 0-1.102.898-2 2-2z" fill="#fff"/></svg>
|
||||
</template>
|
||||
<template #title>Google App Engine</template>
|
||||
<template #description>
|
||||
Manual step by step guide for deploying on GCP's App Engine
|
||||
</template>
|
||||
</InstallLink>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<InstallLink link="../deployment/heroku">
|
||||
<template #icon>
|
||||
|
||||
@ -19,7 +19,7 @@ yarn create strapi-app my-app --quickstart --no-run
|
||||
2. Generate a plugin:
|
||||
|
||||
```bash
|
||||
strapi generate:plugin wysiwyg
|
||||
yarn run strapi generate:plugin wysiwyg
|
||||
```
|
||||
|
||||
3. Install the needed dependencies:
|
||||
@ -126,7 +126,7 @@ export default MediaLib;
|
||||
**Path —** `./plugins/wysiwyg/admin/src/components/Wysiwyg/index.js`
|
||||
|
||||
```js
|
||||
iimport React, { useState } from 'react';
|
||||
import React, { useState } from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import { isEmpty } from 'lodash';
|
||||
import { Button } from '@buffetjs/core';
|
||||
@ -332,4 +332,4 @@ export default strapi => {
|
||||
};
|
||||
```
|
||||
|
||||
And VOILA, if you create a new `collectionType` or a `singleType` with a `richtext` field you will see the implementation of [CKEditor]((https://ckeditor.com/ckeditor-5/) instead of the default WYSIWYG.
|
||||
And VOILA, if you create a new `collectionType` or a `singleType` with a `richtext` field you will see the implementation of [CKEditor](https://ckeditor.com/ckeditor-5/) instead of the default WYSIWYG.
|
||||
|
||||
@ -74,7 +74,7 @@ In some cases (with Heroku, Docker...), listening to `localhost` won't work. In
|
||||
|
||||
### Example
|
||||
|
||||
**After -** `./config/environments/**/server.js`
|
||||
**Before -** `./config/environments/**/server.js`
|
||||
|
||||
```json
|
||||
{
|
||||
|
||||
@ -48,6 +48,10 @@ This means that you now have to configure your provider directly in the files. Y
|
||||
|
||||
## MongoDB Media relation changes
|
||||
|
||||
::: tip
|
||||
The guide below only applies if you are using MongoDB/Mongoose, if you are using a Bookshelf database you can simply skip to the [rebuilding step](#rebuilding-your-administration-panel)
|
||||
:::
|
||||
|
||||
In the media library features, We wanted to make sure media would keep their ordering. To implement this in mongo we had to change the way the media relation was built.
|
||||
|
||||
Previously, the `upload_file` collection was the one keeping track of the relations and the entity related to the file had not reference to it.
|
||||
|
||||
@ -3,53 +3,30 @@
|
||||
The logic of a plugin is located at its root directory `./plugins/**`. The admin panel related parts of each plugin are contained in the `/admin` folder.
|
||||
The folders and files structure are the following:
|
||||
|
||||
<!-- ```
|
||||
/plugin
|
||||
└─── admin // Contains the plugin's front-end
|
||||
| └─── src // Source code directory
|
||||
| └─── index.js // Entry point of the plugin
|
||||
| └─── pluginId.js // Name of the plugin
|
||||
| └─── lifecycles.js // File in which the plugin sets the hooks to be ran in another plugin.
|
||||
| |
|
||||
| └─── components // Contains the list of React components used by the plugin
|
||||
| └─── containers
|
||||
| | └─── App // Container used by every others containers
|
||||
| | └─── Initializer // This container is required, it is used to executed logic right after the plugin is mounted.
|
||||
| | └─── HomePage
|
||||
| | └─── action.js // List of Redux actions used by the current container
|
||||
| | └─── constants.js // List of actions constants
|
||||
| | └─── index.js // React component of the current container
|
||||
| | └─── reducer.js // Redux reducer used by the current container
|
||||
| | └─── sagas.js // List of sagas functions
|
||||
| | └─── selectors.js // List of selectors
|
||||
| | └─── styles.scss // Style of the current container
|
||||
| |
|
||||
| └─── translations // Contains the translations to make the plugin internationalized
|
||||
| └─── en.json
|
||||
| └─── index.js // File that exports all the plugin's translations.
|
||||
| └─── fr.json
|
||||
└─── config // Contains the configurations of the plugin
|
||||
| └─── functions
|
||||
| | └─── bootstrap.js // Asynchronous bootstrap function that runs before the app gets started
|
||||
| └─── policies // Folder containing the plugin's policies
|
||||
| └─── queries // Folder containing the plugin's models queries
|
||||
| └─── routes.json // Contains the plugin's API routes
|
||||
└─── controllers // Contains the plugin's API controllers
|
||||
└─── middlewares // Contains the plugin's middlewares
|
||||
└─── models // Contains the plugin's API models
|
||||
└─── services // Contains the plugin's API services
|
||||
``` -->
|
||||
|
||||
```bash
|
||||
plugin/
|
||||
├── config/ # Contains the configurations of the plugin
|
||||
│ ├── functions/
|
||||
│ │ └── bootstrap.js # Asynchronous bootstrap function that runs before the app gets started
|
||||
│ ├── policies/ # Folder containing the plugin's policies
|
||||
│ ├── queries/ # Folder containing the plugin's models queries
|
||||
│ └── routes.json # Contains the plugin's API routes
|
||||
├── controllers/ # Contains the plugin's API controllers
|
||||
├── middlewares/ # Contains the plugin's middlewares
|
||||
├── models/ # Contains the plugin's API models
|
||||
└── services/ # Contains the plugin's API services
|
||||
```
|
||||
plugin/
|
||||
└─── admin/ # Contains the plugin's front-end
|
||||
| └─── src/ # Source code directory
|
||||
| └─── index.js # Entry point of the plugin
|
||||
| └─── pluginId.js # Name of the plugin
|
||||
| └─── lifecycles.js # File in which the plugin sets the hooks to be ran in another plugin.
|
||||
| |
|
||||
| └─── components/ # Contains the list of React components used by the plugin
|
||||
| └─── containers/
|
||||
| | └─── App/ # Container used by every others containers
|
||||
| | └─── Initializer/ # This container is required, it is used to executed logic right after the plugin is mounted.
|
||||
| └─── translations/ # Contains the translations to make the plugin internationalized
|
||||
| └─── en.json
|
||||
| └─── index.js # File that exports all the plugin's translations.
|
||||
| └─── fr.json
|
||||
└─── config/ # Contains the configurations of the plugin
|
||||
| └─── functions/
|
||||
| | └─── bootstrap.js # Asynchronous bootstrap function that runs before the app gets started
|
||||
| └─── policies/ # Folder containing the plugin's policies
|
||||
| └─── queries/ # Folder containing the plugin's models queries
|
||||
| └─── routes.json # Contains the plugin's API routes
|
||||
└─── controllers/ # Contains the plugin's API controllers
|
||||
└─── middlewares/ # Contains the plugin's middlewares
|
||||
└─── models/ # Contains the plugin's API models
|
||||
└─── services/ # Contains the plugin's API services
|
||||
```
|
||||
|
||||
@ -14,7 +14,3 @@ Create a development project
|
||||
In a new terminal window:
|
||||
|
||||
1. Generate a new plugin: `cd /path/to/myDevelopmentProject && strapi generate:plugin my-plugin`
|
||||
|
||||
::: tip
|
||||
The admin panel integration is currently not available. You can still add backend features.
|
||||
:::
|
||||
|
||||
@ -712,6 +712,10 @@ Add the language translation in `packages/strapi-plugin-users-permissions/admin/
|
||||
|
||||
These two change will set up the popup message that appears in the UI. That's it, now you should be able to use your new provider.
|
||||
|
||||
### Rebuild the Admin Panel
|
||||
|
||||
Please see the following [documentation](../admin-panel/customization.md#build) on rebuilding the admin panel.
|
||||
|
||||
## Templating emails
|
||||
|
||||
By default, this plugin comes with only two templates (reset password and email address confirmation) at the moment. More templates will come later. The templates use Lodash's template() method to populate the variables.
|
||||
|
||||
@ -20,7 +20,7 @@
|
||||
"model": "file",
|
||||
"via": "related",
|
||||
"allowedTypes": [
|
||||
"images",
|
||||
"images",
|
||||
"files",
|
||||
"videos"
|
||||
],
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "getstarted",
|
||||
"private": true,
|
||||
"version": "3.0.0-beta.19.5",
|
||||
"version": "3.0.0-beta.20",
|
||||
"description": "A Strapi application.",
|
||||
"scripts": {
|
||||
"develop": "strapi develop",
|
||||
@ -15,22 +15,22 @@
|
||||
"mysql": "^2.17.1",
|
||||
"pg": "^7.10.0",
|
||||
"sqlite3": "^4.0.6",
|
||||
"strapi": "3.0.0-beta.19.5",
|
||||
"strapi-admin": "3.0.0-beta.19.5",
|
||||
"strapi-connector-bookshelf": "3.0.0-beta.19.5",
|
||||
"strapi-connector-mongoose": "3.0.0-beta.19.5",
|
||||
"strapi-middleware-views": "3.0.0-beta.19.5",
|
||||
"strapi-plugin-content-manager": "3.0.0-beta.19.5",
|
||||
"strapi-plugin-content-type-builder": "3.0.0-beta.19.5",
|
||||
"strapi-plugin-documentation": "3.0.0-beta.19.5",
|
||||
"strapi-plugin-email": "3.0.0-beta.19.5",
|
||||
"strapi-plugin-graphql": "3.0.0-beta.19.5",
|
||||
"strapi-plugin-upload": "3.0.0-beta.19.5",
|
||||
"strapi-plugin-users-permissions": "3.0.0-beta.19.5",
|
||||
"strapi-provider-email-mailgun": "3.0.0-beta.19.5",
|
||||
"strapi-provider-upload-aws-s3": "3.0.0-beta.19.5",
|
||||
"strapi-provider-upload-cloudinary": "3.0.0-beta.19.5",
|
||||
"strapi-utils": "3.0.0-beta.19.5"
|
||||
"strapi": "3.0.0-beta.20",
|
||||
"strapi-admin": "3.0.0-beta.20",
|
||||
"strapi-connector-bookshelf": "3.0.0-beta.20",
|
||||
"strapi-connector-mongoose": "3.0.0-beta.20",
|
||||
"strapi-middleware-views": "3.0.0-beta.20",
|
||||
"strapi-plugin-content-manager": "3.0.0-beta.20",
|
||||
"strapi-plugin-content-type-builder": "3.0.0-beta.20",
|
||||
"strapi-plugin-documentation": "3.0.0-beta.20",
|
||||
"strapi-plugin-email": "3.0.0-beta.20",
|
||||
"strapi-plugin-graphql": "3.0.0-beta.20",
|
||||
"strapi-plugin-upload": "3.0.0-beta.20",
|
||||
"strapi-plugin-users-permissions": "3.0.0-beta.20",
|
||||
"strapi-provider-email-mailgun": "3.0.0-beta.20",
|
||||
"strapi-provider-upload-aws-s3": "3.0.0-beta.20",
|
||||
"strapi-provider-upload-cloudinary": "3.0.0-beta.20",
|
||||
"strapi-utils": "3.0.0-beta.20"
|
||||
},
|
||||
"strapi": {
|
||||
"uuid": "getstarted"
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
{
|
||||
"version": "3.0.0-beta.19.5",
|
||||
"version": "3.0.0-beta.20",
|
||||
"packages": [
|
||||
"packages/*",
|
||||
"examples/*"
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "create-strapi-app",
|
||||
"version": "3.0.0-beta.19.5",
|
||||
"version": "3.0.0-beta.20",
|
||||
"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.19.5"
|
||||
"strapi-generate-new": "3.0.0-beta.20"
|
||||
},
|
||||
"scripts": {
|
||||
"test": "echo \"no tests yet\""
|
||||
|
||||
@ -60,6 +60,72 @@ exports[`<EventInput /> should match the snapshot 1`] = `
|
||||
font-size: 1.3rem;
|
||||
}
|
||||
|
||||
.c4 {
|
||||
cursor: pointer;
|
||||
margin: 0;
|
||||
position: relative;
|
||||
width: 14px;
|
||||
font-weight: 100;
|
||||
}
|
||||
|
||||
.c4:focus,
|
||||
.c4:active {
|
||||
outline: 0;
|
||||
}
|
||||
|
||||
.c4:before {
|
||||
content: '';
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: 50%;
|
||||
margin-top: calc(-14px / 2);
|
||||
width: 14px;
|
||||
height: 14px;
|
||||
border: 1px solid rgba(16,22,34,0.15);
|
||||
background-color: #fdfdfd;
|
||||
border-radius: 3px;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.c4:after {
|
||||
display: none;
|
||||
content: '\\f00c';
|
||||
font-family: 'FontAwesome';
|
||||
position: absolute;
|
||||
left: 0px;
|
||||
top: 55%;
|
||||
margin-top: calc(-14px / 2);
|
||||
width: 14px;
|
||||
height: 14px;
|
||||
text-align: center;
|
||||
font-size: 9px;
|
||||
font-weight: 400;
|
||||
color: #1C5DE7;
|
||||
line-height: 14px;
|
||||
}
|
||||
|
||||
.c4:checked:after {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.c4:after {
|
||||
content: '\\f068';
|
||||
display: block;
|
||||
top: 50%;
|
||||
font-size: 10px;
|
||||
}
|
||||
|
||||
.c4:disabled {
|
||||
background-color: #FAFAFB;
|
||||
cursor: initial;
|
||||
}
|
||||
|
||||
.c4 + label {
|
||||
display: inline-block;
|
||||
font-weight: 400;
|
||||
font-size: 1.3rem;
|
||||
}
|
||||
|
||||
.c1 {
|
||||
display: -webkit-box;
|
||||
display: -webkit-flex;
|
||||
@ -299,8 +365,8 @@ exports[`<EventInput /> should match the snapshot 1`] = `
|
||||
<input
|
||||
autoComplete="off"
|
||||
autoFocus={false}
|
||||
checked={true}
|
||||
className="c2"
|
||||
checked={false}
|
||||
className="c4"
|
||||
id="media"
|
||||
name="media"
|
||||
onChange={[Function]}
|
||||
@ -348,7 +414,7 @@ exports[`<EventInput /> should match the snapshot 1`] = `
|
||||
autoFocus={false}
|
||||
checked={false}
|
||||
className="c2"
|
||||
disabled={true}
|
||||
disabled={false}
|
||||
id="media.update"
|
||||
name="media.update"
|
||||
onChange={[Function]}
|
||||
|
||||
@ -15,7 +15,7 @@ const Wrapper = styled.div`
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
> p {
|
||||
width 100%;
|
||||
width: 100%;
|
||||
margin-bottom: -8px;
|
||||
padding-top: 10px;
|
||||
font-size: 13px;
|
||||
|
||||
@ -448,7 +448,7 @@ exports[`<Inputs /> should match the snapshot if type is events 1`] = `
|
||||
autoFocus={false}
|
||||
checked={false}
|
||||
className="c4"
|
||||
disabled={true}
|
||||
disabled={false}
|
||||
id="media.update"
|
||||
name="media.update"
|
||||
onChange={[Function]}
|
||||
|
||||
@ -22,8 +22,7 @@ const Logout = ({ history: { push } }) => {
|
||||
|
||||
push({
|
||||
pathname: `/plugins/content-manager/collectionType/strapi::administrator/${id}`,
|
||||
search:
|
||||
'?redirectUrl=/plugins/content-manager/collectionType/strapi::administrator/&_page=0&_limit=0&_sort=id',
|
||||
search: '?redirectUrl=/plugins/content-manager/collectionType/strapi::administrator',
|
||||
});
|
||||
};
|
||||
const handleGoToAdministrator = () => {
|
||||
|
||||
@ -86,8 +86,7 @@ const Wrapper = styled.div`
|
||||
}
|
||||
|
||||
.bordered {
|
||||
border-top: 2px solid
|
||||
${({ withSucessBorder }) => (withSucessBorder ? '#5a9e06' : '#1c5de7')};
|
||||
border-top: 2px solid ${({ withSuccessBorder }) => (withSuccessBorder ? '#5a9e06' : '#1c5de7')};
|
||||
}
|
||||
|
||||
.borderedSuccess {
|
||||
|
||||
@ -3,13 +3,7 @@ import PropTypes from 'prop-types';
|
||||
import { get, isEmpty, omit, set, upperFirst } from 'lodash';
|
||||
import { FormattedMessage } from 'react-intl';
|
||||
import { Link, Redirect } from 'react-router-dom';
|
||||
import {
|
||||
auth,
|
||||
Button,
|
||||
getQueryParameters,
|
||||
getYupInnerErrors,
|
||||
request,
|
||||
} from 'strapi-helper-plugin';
|
||||
import { auth, Button, getQueryParameters, getYupInnerErrors, request } from 'strapi-helper-plugin';
|
||||
import NavTopRightWrapper from '../../components/NavTopRightWrapper';
|
||||
import LogoStrapi from '../../assets/images/logo_strapi.png';
|
||||
import PageTitle from '../../components/PageTitle';
|
||||
@ -29,9 +23,9 @@ const AuthPage = ({
|
||||
}) => {
|
||||
const [reducerState, dispatch] = useReducer(reducer, initialState);
|
||||
const codeRef = useRef();
|
||||
const aborController = new AbortController();
|
||||
const abortController = new AbortController();
|
||||
|
||||
const { signal } = aborController;
|
||||
const { signal } = abortController;
|
||||
codeRef.current = getQueryParameters(search, 'code');
|
||||
useEffect(() => {
|
||||
// Set the reset code provided by the url
|
||||
@ -49,17 +43,11 @@ const AuthPage = ({
|
||||
}
|
||||
|
||||
return () => {
|
||||
aborController.abort();
|
||||
abortController.abort();
|
||||
};
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [authType, codeRef]);
|
||||
const {
|
||||
didCheckErrors,
|
||||
errors,
|
||||
modifiedData,
|
||||
submitSuccess,
|
||||
userEmail,
|
||||
} = reducerState.toJS();
|
||||
const { didCheckErrors, errors, modifiedData, submitSuccess, userEmail } = reducerState.toJS();
|
||||
const handleChange = ({ target: { name, value } }) => {
|
||||
dispatch({
|
||||
type: 'ON_CHANGE',
|
||||
@ -124,9 +112,7 @@ const AuthPage = ({
|
||||
} else if (authType === 'forgot-password') {
|
||||
formErrors = { email: formattedError[0] };
|
||||
} else {
|
||||
strapi.notification.error(
|
||||
get(formattedError, '0.id', 'notification.error')
|
||||
);
|
||||
strapi.notification.error(get(formattedError, '0.id', 'notification.error'));
|
||||
}
|
||||
}
|
||||
} catch (err) {
|
||||
@ -164,7 +150,7 @@ const AuthPage = ({
|
||||
return (
|
||||
<>
|
||||
<PageTitle title={upperFirst(authType)} />
|
||||
<Wrapper authType={authType} withSucessBorder={submitSuccess}>
|
||||
<Wrapper authType={authType} withSuccessBorder={submitSuccess}>
|
||||
<NavTopRightWrapper>
|
||||
<LocaleToggle isLogged className="localeDropdownMenuNotLogged" />
|
||||
</NavTopRightWrapper>
|
||||
@ -177,9 +163,7 @@ const AuthPage = ({
|
||||
)}
|
||||
</div>
|
||||
<div className="headerDescription">
|
||||
{authType === 'register' && (
|
||||
<FormattedMessage id="Auth.header.register.description" />
|
||||
)}
|
||||
{authType === 'register' && <FormattedMessage id="Auth.header.register.description" />}
|
||||
</div>
|
||||
{/* TODO Forgot success style */}
|
||||
<div className="formContainer bordered">
|
||||
@ -217,9 +201,7 @@ const AuthPage = ({
|
||||
})}
|
||||
<div
|
||||
className={`${
|
||||
authType === 'login'
|
||||
? 'col-6 loginButton'
|
||||
: 'col-12 buttonContainer'
|
||||
authType === 'login' ? 'col-6 loginButton' : 'col-12 buttonContainer'
|
||||
}`}
|
||||
>
|
||||
<Button
|
||||
@ -238,15 +220,9 @@ const AuthPage = ({
|
||||
</div>
|
||||
<div className="linkContainer">
|
||||
{authType !== 'register' && authType !== 'reset-password' && (
|
||||
<Link
|
||||
to={`/auth/${
|
||||
authType === 'login' ? 'forgot-password' : 'login'
|
||||
}`}
|
||||
>
|
||||
<Link to={`/auth/${authType === 'login' ? 'forgot-password' : 'login'}`}>
|
||||
<FormattedMessage
|
||||
id={`Auth.link.${
|
||||
authType === 'login' ? 'forgot-password' : 'ready'
|
||||
}`}
|
||||
id={`Auth.link.${authType === 'login' ? 'forgot-password' : 'ready'}`}
|
||||
/>
|
||||
</Link>
|
||||
)}
|
||||
|
||||
@ -9,7 +9,7 @@ const Block = styled.div`
|
||||
padding: 19px 30px 30px 30px;
|
||||
box-shadow: 0 2px 4px 0 #e3e9f3;
|
||||
border-radius: 3px;
|
||||
line-heigth: 18px;
|
||||
line-height: 18px;
|
||||
|
||||
a {
|
||||
position: relative;
|
||||
@ -213,12 +213,12 @@ const LinkWrapper = styled.a`
|
||||
&:first-child {
|
||||
font-size: 16px;
|
||||
}
|
||||
color: #919BAE;
|
||||
color: #919bae;
|
||||
text-overflow: ellipsis;
|
||||
overflow: hidden;
|
||||
}
|
||||
.bold {
|
||||
color: #333740
|
||||
color: #333740;
|
||||
font-weight: 600;
|
||||
}
|
||||
`;
|
||||
@ -257,13 +257,4 @@ const SocialLinkWrapper = styled.div`
|
||||
}
|
||||
`;
|
||||
|
||||
export {
|
||||
ALink,
|
||||
Block,
|
||||
Container,
|
||||
LinkWrapper,
|
||||
P,
|
||||
Separator,
|
||||
SocialLinkWrapper,
|
||||
Wave,
|
||||
};
|
||||
export { ALink, Block, Container, LinkWrapper, P, Separator, SocialLinkWrapper, Wave };
|
||||
|
||||
@ -5,7 +5,7 @@
|
||||
*
|
||||
* NOTE: while this component should technically be a stateless functional
|
||||
* component (SFC), hot reloading does not currently support SFCs. If hot
|
||||
* reloading is not a neccessity for you then you can refactor it and remove
|
||||
* reloading is not a necessity for you then you can refactor it and remove
|
||||
* the linting exception.
|
||||
*/
|
||||
|
||||
|
||||
@ -1258,7 +1258,6 @@ exports[`Admin | containers | EditView should match the snapshot 1`] = `
|
||||
<input
|
||||
autocomplete="off"
|
||||
class="c18"
|
||||
disabled=""
|
||||
id="media.update"
|
||||
name="media.update"
|
||||
tabindex="0"
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "strapi-admin",
|
||||
"version": "3.0.0-beta.19.5",
|
||||
"version": "3.0.0-beta.20",
|
||||
"description": "Strapi Admin",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
@ -77,7 +77,7 @@
|
||||
"react-router-dom": "^5.0.0",
|
||||
"react-transition-group": "^2.9.0",
|
||||
"react-virtualized": "^9.21.2",
|
||||
"reactstrap": "^5.0.0",
|
||||
"reactstrap": "8.4.1",
|
||||
"redux": "^4.0.1",
|
||||
"redux-immutable": "^4.0.0",
|
||||
"redux-saga": "^0.16.0",
|
||||
@ -85,8 +85,8 @@
|
||||
"reselect": "^3.0.1",
|
||||
"sanitize.css": "^4.1.0",
|
||||
"shelljs": "^0.7.8",
|
||||
"strapi-helper-plugin": "3.0.0-beta.19.5",
|
||||
"strapi-utils": "3.0.0-beta.19.5",
|
||||
"strapi-helper-plugin": "3.0.0-beta.20",
|
||||
"strapi-utils": "3.0.0-beta.20",
|
||||
"style-loader": "^0.23.1",
|
||||
"styled-components": "^5.0.0",
|
||||
"terser-webpack-plugin": "^1.2.3",
|
||||
@ -116,4 +116,4 @@
|
||||
},
|
||||
"license": "MIT",
|
||||
"gitHead": "c85658a19b8fef0f3164c19693a45db305dc07a9"
|
||||
}
|
||||
}
|
||||
|
||||
@ -71,7 +71,10 @@ module.exports = function createQueryBuilder({ model, modelKey, strapi }) {
|
||||
function count(params = {}) {
|
||||
const { where } = convertRestQueryParams(params);
|
||||
|
||||
return model.query(buildQuery({ model, filters: { where } })).count();
|
||||
return model
|
||||
.query(buildQuery({ model, filters: { where } }))
|
||||
.count()
|
||||
.then(Number);
|
||||
}
|
||||
|
||||
async function create(values, { transacting } = {}) {
|
||||
@ -187,7 +190,8 @@ module.exports = function createQueryBuilder({ model, modelKey, strapi }) {
|
||||
.query(qb => {
|
||||
buildSearchQuery(qb, model, params);
|
||||
})
|
||||
.count();
|
||||
.count()
|
||||
.then(Number);
|
||||
}
|
||||
|
||||
async function createComponents(entry, values, { transacting }) {
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "strapi-connector-bookshelf",
|
||||
"version": "3.0.0-beta.19.5",
|
||||
"version": "3.0.0-beta.20",
|
||||
"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": "3.0.0",
|
||||
"strapi-utils": "3.0.0-beta.19.5"
|
||||
"strapi-utils": "3.0.0-beta.20"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"knex": "^0.20.0"
|
||||
|
||||
@ -316,7 +316,7 @@ module.exports = ({ model, modelKey, strapi }) => {
|
||||
|
||||
// verify the provided ids are related to this entity.
|
||||
idsToKeep.forEach(id => {
|
||||
if (allIds.findIndex(currentId => currentId.toString() === id) === -1) {
|
||||
if (allIds.findIndex(currentId => currentId.toString() === id.toString()) === -1) {
|
||||
const err = new Error(
|
||||
`Some of the provided components in ${key} are not related to the entity`
|
||||
);
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "strapi-connector-mongoose",
|
||||
"version": "3.0.0-beta.19.5",
|
||||
"version": "3.0.0-beta.20",
|
||||
"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.19.5"
|
||||
"strapi-utils": "3.0.0-beta.20"
|
||||
},
|
||||
"author": {
|
||||
"email": "hi@strapi.io",
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "strapi-database",
|
||||
"version": "3.0.0-beta.19.5",
|
||||
"version": "3.0.0-beta.20",
|
||||
"description": "Strapi's database layer",
|
||||
"homepage": "http://strapi.io",
|
||||
"main": "./lib/index.js",
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "strapi-generate-api",
|
||||
"version": "3.0.0-beta.19.5",
|
||||
"version": "3.0.0-beta.20",
|
||||
"description": "Generate an API for a Strapi application.",
|
||||
"homepage": "http://strapi.io",
|
||||
"keywords": [
|
||||
@ -15,7 +15,7 @@
|
||||
"dependencies": {
|
||||
"lodash": "^4.17.11",
|
||||
"pluralize": "^7.0.0",
|
||||
"strapi-utils": "3.0.0-beta.19.5"
|
||||
"strapi-utils": "3.0.0-beta.20"
|
||||
},
|
||||
"scripts": {
|
||||
"test": "echo \"no tests yet\""
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "strapi-generate-controller",
|
||||
"version": "3.0.0-beta.19.5",
|
||||
"version": "3.0.0-beta.20",
|
||||
"description": "Generate a controller for a Strapi API.",
|
||||
"homepage": "http://strapi.io",
|
||||
"keywords": [
|
||||
@ -15,7 +15,7 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"lodash": "^4.17.11",
|
||||
"strapi-utils": "3.0.0-beta.19.5"
|
||||
"strapi-utils": "3.0.0-beta.20"
|
||||
},
|
||||
"scripts": {
|
||||
"test": "echo \"no tests yet\""
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "strapi-generate-model",
|
||||
"version": "3.0.0-beta.19.5",
|
||||
"version": "3.0.0-beta.20",
|
||||
"description": "Generate a model for a Strapi API.",
|
||||
"homepage": "http://strapi.io",
|
||||
"keywords": [
|
||||
@ -16,7 +16,7 @@
|
||||
"dependencies": {
|
||||
"lodash": "^4.17.11",
|
||||
"pluralize": "^7.0.0",
|
||||
"strapi-utils": "3.0.0-beta.19.5"
|
||||
"strapi-utils": "3.0.0-beta.20"
|
||||
},
|
||||
"scripts": {
|
||||
"test": "echo \"no tests yet\""
|
||||
|
||||
@ -12,10 +12,7 @@ const { trackUsage, captureStderr } = require('./utils/usage');
|
||||
const packageJSON = require('./resources/json/package.json');
|
||||
const databaseJSON = require('./resources/json/database.json.js');
|
||||
|
||||
module.exports = async function createProject(
|
||||
scope,
|
||||
{ connection, dependencies }
|
||||
) {
|
||||
module.exports = async function createProject(scope, { connection, dependencies }) {
|
||||
console.log('Creating files.');
|
||||
|
||||
const { rootPath } = scope;
|
||||
@ -29,13 +26,12 @@ module.exports = async function createProject(
|
||||
const dotFiles = await fse.readdir(join(resources, 'dot-files'));
|
||||
await Promise.all(
|
||||
dotFiles.map(name => {
|
||||
return fse.copy(
|
||||
join(resources, 'dot-files', name),
|
||||
join(rootPath, `.${name}`)
|
||||
);
|
||||
return fse.copy(join(resources, 'dot-files', name), join(rootPath, `.${name}`));
|
||||
})
|
||||
);
|
||||
|
||||
await trackUsage({ event: 'didCopyProjectFiles', scope });
|
||||
|
||||
// copy templates
|
||||
await fse.writeJSON(
|
||||
join(rootPath, 'package.json'),
|
||||
@ -51,6 +47,8 @@ module.exports = async function createProject(
|
||||
}
|
||||
);
|
||||
|
||||
await trackUsage({ event: 'didWritePackageJSON', scope });
|
||||
|
||||
// ensure node_modules is created
|
||||
await fse.ensureDir(join(rootPath, 'node_modules'));
|
||||
|
||||
@ -66,11 +64,15 @@ module.exports = async function createProject(
|
||||
);
|
||||
})
|
||||
);
|
||||
|
||||
await trackUsage({ event: 'didCopyConfigurationFiles', scope });
|
||||
} catch (err) {
|
||||
await fse.remove(scope.rootPath);
|
||||
throw err;
|
||||
}
|
||||
|
||||
await trackUsage({ event: 'willInstallProjectDependencies', scope });
|
||||
|
||||
const installPrefix = chalk.yellow('Installing dependencies:');
|
||||
const loader = ora(installPrefix).start();
|
||||
|
||||
@ -93,6 +95,8 @@ module.exports = async function createProject(
|
||||
|
||||
loader.stop();
|
||||
console.log(`Dependencies installed ${chalk.green('successfully')}.`);
|
||||
|
||||
await trackUsage({ event: 'didInstallProjectDependencies', scope });
|
||||
} catch (error) {
|
||||
loader.stop();
|
||||
await trackUsage({
|
||||
@ -119,9 +123,7 @@ module.exports = async function createProject(
|
||||
);
|
||||
console.log();
|
||||
console.log(
|
||||
`cd ${chalk.green(rootPath)} && ${chalk.cyan(
|
||||
scope.useYarn ? 'yarn' : 'npm'
|
||||
)} install`
|
||||
`cd ${chalk.green(rootPath)} && ${chalk.cyan(scope.useYarn ? 'yarn' : 'npm')} install`
|
||||
);
|
||||
console.log();
|
||||
|
||||
|
||||
@ -71,6 +71,7 @@ function trackError({ scope, error }) {
|
||||
version: scope.strapiVersion,
|
||||
nodeVersion: process.version,
|
||||
docker: scope.docker,
|
||||
useYarn: scope.useYarn,
|
||||
},
|
||||
});
|
||||
} catch (err) {
|
||||
@ -92,6 +93,7 @@ function trackUsage({ event, scope, error }) {
|
||||
node_version: process.version,
|
||||
version: scope.strapiVersion,
|
||||
docker: scope.docker,
|
||||
useYarn: scope.useYarn,
|
||||
},
|
||||
});
|
||||
} catch (err) {
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "strapi-generate-new",
|
||||
"version": "3.0.0-beta.19.5",
|
||||
"version": "3.0.0-beta.20",
|
||||
"description": "Generate a new Strapi application.",
|
||||
"homepage": "http://strapi.io",
|
||||
"keywords": [
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "strapi-generate-plugin",
|
||||
"version": "3.0.0-beta.19.5",
|
||||
"version": "3.0.0-beta.20",
|
||||
"description": "Generate an plugin for a Strapi application.",
|
||||
"homepage": "http://strapi.io",
|
||||
"keywords": [
|
||||
@ -15,7 +15,7 @@
|
||||
"dependencies": {
|
||||
"fs-extra": "^8.0.1",
|
||||
"lodash": "^4.17.11",
|
||||
"strapi-utils": "3.0.0-beta.19.5"
|
||||
"strapi-utils": "3.0.0-beta.20"
|
||||
},
|
||||
"scripts": {
|
||||
"test": "echo \"no tests yet\""
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "strapi-generate-policy",
|
||||
"version": "3.0.0-beta.19.5",
|
||||
"version": "3.0.0-beta.20",
|
||||
"description": "Generate a policy for a Strapi API.",
|
||||
"homepage": "http://strapi.io",
|
||||
"keywords": [
|
||||
@ -15,7 +15,7 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"lodash": "^4.17.11",
|
||||
"strapi-utils": "3.0.0-beta.19.5"
|
||||
"strapi-utils": "3.0.0-beta.20"
|
||||
},
|
||||
"scripts": {
|
||||
"test": "echo \"no tests yet\""
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "strapi-generate-service",
|
||||
"version": "3.0.0-beta.19.5",
|
||||
"version": "3.0.0-beta.20",
|
||||
"description": "Generate a service for a Strapi API.",
|
||||
"homepage": "http://strapi.io",
|
||||
"keywords": [
|
||||
@ -15,7 +15,7 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"lodash": "^4.17.11",
|
||||
"strapi-utils": "3.0.0-beta.19.5"
|
||||
"strapi-utils": "3.0.0-beta.20"
|
||||
},
|
||||
"scripts": {
|
||||
"test": "echo \"no tests yet\""
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "strapi-generate",
|
||||
"version": "3.0.0-beta.19.5",
|
||||
"version": "3.0.0-beta.20",
|
||||
"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.19.5"
|
||||
"strapi-utils": "3.0.0-beta.20"
|
||||
},
|
||||
"author": {
|
||||
"name": "Strapi team",
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "strapi-helper-plugin",
|
||||
"version": "3.0.0-beta.19.5",
|
||||
"version": "3.0.0-beta.20",
|
||||
"description": "Helper for Strapi plugins development",
|
||||
"files": [
|
||||
"dist"
|
||||
@ -62,7 +62,7 @@
|
||||
"react-intl": "^2.8.0",
|
||||
"react-router": "^5.0.0",
|
||||
"react-router-dom": "^5.0.0",
|
||||
"reactstrap": "^8.0.1",
|
||||
"reactstrap": "8.4.1",
|
||||
"styled-components": "^5.0.0",
|
||||
"whatwg-fetch": "^2.0.3"
|
||||
},
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "strapi-hook-ejs",
|
||||
"version": "3.0.0-beta.19.5",
|
||||
"version": "3.0.0-beta.20",
|
||||
"description": "EJS hook for the Strapi framework",
|
||||
"homepage": "http://strapi.io",
|
||||
"keywords": [
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "strapi-hook-redis",
|
||||
"version": "3.0.0-beta.19.5",
|
||||
"version": "3.0.0-beta.20",
|
||||
"description": "Redis hook for the Strapi framework",
|
||||
"homepage": "http://strapi.io",
|
||||
"keywords": [
|
||||
@ -19,7 +19,7 @@
|
||||
"lodash": "^4.17.11",
|
||||
"rimraf": "3.0.0",
|
||||
"stack-trace": "0.0.10",
|
||||
"strapi-utils": "3.0.0-beta.19.5"
|
||||
"strapi-utils": "3.0.0-beta.20"
|
||||
},
|
||||
"author": {
|
||||
"email": "hi@strapi.io",
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "strapi-middleware-views",
|
||||
"version": "3.0.0-beta.19.5",
|
||||
"version": "3.0.0-beta.20",
|
||||
"description": "Views middleware to enable server-side rendering for the Strapi framework",
|
||||
"homepage": "http://strapi.io",
|
||||
"keywords": [
|
||||
|
||||
@ -3,7 +3,7 @@ import { withRouter } from 'react-router';
|
||||
import PropTypes from 'prop-types';
|
||||
import { get, isEmpty, isNull, isObject, toLower, toString } from 'lodash';
|
||||
import moment from 'moment';
|
||||
import { dateToUtcTime, IcoContainer, useGlobalContext } from 'strapi-helper-plugin';
|
||||
import { IcoContainer, useGlobalContext } from 'strapi-helper-plugin';
|
||||
import useListView from '../../hooks/useListView';
|
||||
import dateFormats from '../../utils/dateFormats';
|
||||
import CustomInputCheckbox from '../CustomInputCheckbox';
|
||||
@ -37,7 +37,7 @@ const getDisplayedValue = (type, value, name) => {
|
||||
const date =
|
||||
value && isObject(value) && value._isAMomentObject === true ? JSON.stringify(value) : value;
|
||||
|
||||
return dateToUtcTime(date).format(dateFormats[type]);
|
||||
return moment(date).format(dateFormats[type]);
|
||||
}
|
||||
case 'password':
|
||||
return '••••••••';
|
||||
|
||||
@ -46,7 +46,7 @@ const getInputType = (type = '') => {
|
||||
case 'uid':
|
||||
return 'uid';
|
||||
default:
|
||||
return 'text';
|
||||
return type || 'text';
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@ -5,6 +5,7 @@ import { Link } from 'react-router-dom';
|
||||
import { FormattedMessage } from 'react-intl';
|
||||
import pluginId from '../../pluginId';
|
||||
import IconRemove from '../../assets/images/icon_remove.svg';
|
||||
import { Span } from './components';
|
||||
|
||||
/* eslint-disable jsx-a11y/no-noninteractive-element-interactions */
|
||||
|
||||
@ -18,7 +19,7 @@ const Relation = ({ data, mainField, onRemove, to }) => {
|
||||
<FormattedMessage id={`${pluginId}.containers.Edit.clickToJump`}>
|
||||
{title => (
|
||||
<Link to={to} title={title}>
|
||||
<span>{data[mainField]}</span>
|
||||
<Span>{data[mainField]}</Span>
|
||||
</Link>
|
||||
)}
|
||||
</FormattedMessage>
|
||||
|
||||
@ -97,10 +97,8 @@ const Li = styled.li`
|
||||
> a:hover {
|
||||
text-decoration: none;
|
||||
}
|
||||
span {
|
||||
overflow: hidden;
|
||||
white-space: nowrap;
|
||||
text-overflow: ellipsis;
|
||||
> a {
|
||||
max-width: 100%;
|
||||
}
|
||||
|
||||
&:first-of-type {
|
||||
@ -145,4 +143,12 @@ const Li = styled.li`
|
||||
}
|
||||
`;
|
||||
|
||||
export { ListShadow, ListWrapper, Li };
|
||||
const Span = styled.span`
|
||||
display: block;
|
||||
max-width: 100%;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
`;
|
||||
|
||||
export { ListShadow, ListWrapper, Li, Span };
|
||||
|
||||
@ -23,6 +23,7 @@ function SelectMany({
|
||||
onRemove,
|
||||
options,
|
||||
placeholder,
|
||||
styles,
|
||||
targetModel,
|
||||
value,
|
||||
}) {
|
||||
@ -62,8 +63,7 @@ function SelectMany({
|
||||
id={name}
|
||||
filterOption={(candidate, input) => {
|
||||
if (!isEmpty(value)) {
|
||||
const isSelected =
|
||||
value.findIndex(item => item.id === candidate.value.id) !== -1;
|
||||
const isSelected = value.findIndex(item => item.id === candidate.value.id) !== -1;
|
||||
|
||||
if (isSelected) {
|
||||
return false;
|
||||
@ -85,6 +85,7 @@ function SelectMany({
|
||||
onMenuClose={onMenuClose}
|
||||
onMenuScrollToBottom={onMenuScrollToBottom}
|
||||
placeholder={placeholder}
|
||||
styles={styles}
|
||||
value={[]}
|
||||
/>
|
||||
|
||||
@ -130,6 +131,7 @@ SelectMany.propTypes = {
|
||||
onRemove: PropTypes.func.isRequired,
|
||||
options: PropTypes.array.isRequired,
|
||||
placeholder: PropTypes.node.isRequired,
|
||||
styles: PropTypes.object.isRequired,
|
||||
targetModel: PropTypes.string.isRequired,
|
||||
value: PropTypes.array,
|
||||
};
|
||||
|
||||
@ -15,6 +15,7 @@ function SelectOne({
|
||||
onMenuScrollToBottom,
|
||||
options,
|
||||
placeholder,
|
||||
styles,
|
||||
value,
|
||||
}) {
|
||||
return (
|
||||
@ -29,9 +30,8 @@ function SelectOne({
|
||||
onMenuClose={onMenuClose}
|
||||
onMenuScrollToBottom={onMenuScrollToBottom}
|
||||
placeholder={placeholder}
|
||||
value={
|
||||
isNull(value) ? null : { label: get(value, [mainField], ''), value }
|
||||
}
|
||||
styles={styles}
|
||||
value={isNull(value) ? null : { label: get(value, [mainField], ''), value }}
|
||||
/>
|
||||
);
|
||||
}
|
||||
@ -51,6 +51,7 @@ SelectOne.propTypes = {
|
||||
onMenuScrollToBottom: PropTypes.func.isRequired,
|
||||
options: PropTypes.array.isRequired,
|
||||
placeholder: PropTypes.node.isRequired,
|
||||
styles: PropTypes.object.isRequired,
|
||||
value: PropTypes.object,
|
||||
};
|
||||
|
||||
|
||||
@ -155,6 +155,18 @@ function SelectWrapper({
|
||||
const Component = isSingle ? SelectOne : SelectMany;
|
||||
const associationsLength = isArray(value) ? value.length : 0;
|
||||
|
||||
const customStyles = {
|
||||
option: provided => {
|
||||
return {
|
||||
...provided,
|
||||
maxWidth: '100% !important',
|
||||
overflow: 'hidden',
|
||||
textOverflow: 'ellipsis',
|
||||
whiteSpace: 'nowrap',
|
||||
};
|
||||
},
|
||||
};
|
||||
|
||||
return (
|
||||
<Wrapper className="form-group">
|
||||
<Nav>
|
||||
@ -198,6 +210,7 @@ function SelectWrapper({
|
||||
placeholder
|
||||
)
|
||||
}
|
||||
styles={customStyles}
|
||||
targetModel={targetModel}
|
||||
value={value}
|
||||
/>
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "strapi-plugin-content-manager",
|
||||
"version": "3.0.0-beta.19.5",
|
||||
"version": "3.0.0-beta.20",
|
||||
"description": "A powerful UI to easily manage your data.",
|
||||
"strapi": {
|
||||
"name": "Content Manager",
|
||||
@ -25,13 +25,13 @@
|
||||
"react-router-dom": "^5.0.0",
|
||||
"react-select": "^3.0.4",
|
||||
"react-transition-group": "^2.5.0",
|
||||
"reactstrap": "^5.0.0",
|
||||
"reactstrap": "8.4.1",
|
||||
"redux": "^4.0.1",
|
||||
"redux-immutable": "^4.0.0",
|
||||
"reselect": "^3.0.1",
|
||||
"showdown": "^1.9.0",
|
||||
"strapi-helper-plugin": "3.0.0-beta.19.5",
|
||||
"strapi-utils": "3.0.0-beta.19.5",
|
||||
"strapi-helper-plugin": "3.0.0-beta.20",
|
||||
"strapi-utils": "3.0.0-beta.20",
|
||||
"yup": "^0.27.0"
|
||||
},
|
||||
"author": {
|
||||
|
||||
@ -1,4 +1,5 @@
|
||||
import React, { createRef, useEffect, useState } from 'react';
|
||||
import React, { useEffect, useState, useRef } from 'react';
|
||||
import { useClickAwayListener } from '@buffetjs/hooks';
|
||||
import { Label, ErrorMessage } from '@buffetjs/styles';
|
||||
import { AutoSizer, Collection } from 'react-virtualized';
|
||||
import PropTypes from 'prop-types';
|
||||
@ -21,13 +22,18 @@ const ComponentIconPicker = ({ error, isCreating, label, name, onChange, value }
|
||||
// Edition
|
||||
return !allComponentsIconAlreadyTaken.filter(icon => icon !== originalIcon).includes(ico);
|
||||
});
|
||||
const ref = createRef();
|
||||
const ref = useRef();
|
||||
const searchWrapperRef = useRef();
|
||||
const [originalIcon] = useState(value);
|
||||
const [showSearch, setShowSearch] = useState(false);
|
||||
const [search, setSearch] = useState('');
|
||||
const [icons, setIcons] = useState(initialIcons);
|
||||
const toggleSearch = () => setShowSearch(prev => !prev);
|
||||
|
||||
useClickAwayListener(searchWrapperRef, () => {
|
||||
setShowSearch(false);
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
if (showSearch && ref.current) {
|
||||
ref.current.focus();
|
||||
@ -58,6 +64,11 @@ const ComponentIconPicker = ({ error, isCreating, label, name, onChange, value }
|
||||
};
|
||||
};
|
||||
|
||||
const handleChangeSearch = ({ target: { value } }) => {
|
||||
setSearch(value);
|
||||
setIcons(() => initialIcons.filter(icon => icon.includes(value)));
|
||||
};
|
||||
|
||||
return (
|
||||
<Wrapper error={error !== null}>
|
||||
<div className="search">
|
||||
@ -69,18 +80,10 @@ const ComponentIconPicker = ({ error, isCreating, label, name, onChange, value }
|
||||
<FontAwesomeIcon icon="search" />
|
||||
</button>
|
||||
) : (
|
||||
<SearchWrapper>
|
||||
<SearchWrapper ref={searchWrapperRef}>
|
||||
<FontAwesomeIcon icon="search" />
|
||||
<button onClick={toggleSearch} type="button" />
|
||||
<Search
|
||||
ref={ref}
|
||||
onChange={({ target: { value } }) => {
|
||||
setSearch(value);
|
||||
setIcons(() => initialIcons.filter(icon => icon.includes(value)));
|
||||
}}
|
||||
value={search}
|
||||
placeholder="Search…"
|
||||
/>
|
||||
<Search ref={ref} onChange={handleChangeSearch} value={search} placeholder="Search…" />
|
||||
<button
|
||||
onClick={() => {
|
||||
setSearch('');
|
||||
|
||||
@ -503,6 +503,8 @@ const forms = {
|
||||
];
|
||||
|
||||
items = uidItems;
|
||||
} else if (type === 'json') {
|
||||
items.splice(0, 1);
|
||||
}
|
||||
|
||||
if (!ATTRIBUTES_THAT_DONT_HAVE_MIN_MAX_SETTINGS.includes(type)) {
|
||||
|
||||
@ -1,6 +1,7 @@
|
||||
'use strict';
|
||||
|
||||
const yup = require('yup');
|
||||
const _ = require('lodash');
|
||||
|
||||
const validators = {
|
||||
required: yup.boolean(),
|
||||
@ -80,11 +81,34 @@ const isValidRegExpPattern = {
|
||||
test: val => val === '' || new RegExp(val),
|
||||
};
|
||||
|
||||
const isValidDefaultJSON = {
|
||||
name: 'isValidDefaultJSON',
|
||||
message: '${path} is not a valid JSON',
|
||||
test: val => {
|
||||
if (val === undefined) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (_.isNumber(val) || _.isNull(val) || _.isObject(val) || _.isArray(val)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
try {
|
||||
JSON.parse(val);
|
||||
|
||||
return true;
|
||||
} catch (err) {
|
||||
return false;
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
module.exports = {
|
||||
validators,
|
||||
areEnumValuesUnique,
|
||||
isValidCollectionName,
|
||||
isValidCategoryName,
|
||||
isValidDefaultJSON,
|
||||
isValidName,
|
||||
isValidIcon,
|
||||
isValidKey,
|
||||
|
||||
@ -6,6 +6,7 @@ const yup = require('yup');
|
||||
const {
|
||||
validators,
|
||||
areEnumValuesUnique,
|
||||
isValidDefaultJSON,
|
||||
isValidName,
|
||||
isValidEnum,
|
||||
isValidUID,
|
||||
@ -112,6 +113,7 @@ const getTypeShape = (attribute, { modelType, attributes } = {}) => {
|
||||
}
|
||||
case 'json': {
|
||||
return {
|
||||
default: yup.mixed().test(isValidDefaultJSON),
|
||||
required: validators.required,
|
||||
unique: validators.unique,
|
||||
};
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "strapi-plugin-content-type-builder",
|
||||
"version": "3.0.0-beta.19.5",
|
||||
"version": "3.0.0-beta.20",
|
||||
"description": "Strapi plugin to create content type (API).",
|
||||
"strapi": {
|
||||
"name": "Content Type Builder",
|
||||
@ -22,14 +22,14 @@
|
||||
"react-router": "^5.0.0",
|
||||
"react-router-dom": "^5.0.0",
|
||||
"react-transition-group": "^2.5.0",
|
||||
"reactstrap": "^5.0.0",
|
||||
"reactstrap": "8.4.1",
|
||||
"redux": "^4.0.1",
|
||||
"redux-immutable": "^4.0.0",
|
||||
"reselect": "^3.0.1",
|
||||
"strapi-generate": "3.0.0-beta.19.5",
|
||||
"strapi-generate-api": "3.0.0-beta.19.5",
|
||||
"strapi-helper-plugin": "3.0.0-beta.19.5",
|
||||
"strapi-utils": "3.0.0-beta.19.5",
|
||||
"strapi-generate": "3.0.0-beta.20",
|
||||
"strapi-generate-api": "3.0.0-beta.20",
|
||||
"strapi-helper-plugin": "3.0.0-beta.20",
|
||||
"strapi-utils": "3.0.0-beta.20",
|
||||
"yup": "^0.27.0"
|
||||
},
|
||||
"author": {
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "strapi-plugin-documentation",
|
||||
"version": "3.0.0-beta.19.5",
|
||||
"version": "3.0.0-beta.20",
|
||||
"description": "This is the description of the plugin.",
|
||||
"strapi": {
|
||||
"name": "Documentation",
|
||||
@ -28,11 +28,11 @@
|
||||
"react-router": "^5.0.0",
|
||||
"react-router-dom": "^5.0.0",
|
||||
"react-transition-group": "^4.0.1",
|
||||
"reactstrap": "^8.0.0",
|
||||
"reactstrap": "8.4.1",
|
||||
"redux": "^4.0.1",
|
||||
"redux-immutable": "^4.0.0",
|
||||
"reselect": "^4.0.0",
|
||||
"strapi-helper-plugin": "3.0.0-beta.19.5",
|
||||
"strapi-helper-plugin": "3.0.0-beta.20",
|
||||
"swagger-ui-dist": "3.24.3"
|
||||
},
|
||||
"author": {
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "strapi-plugin-email",
|
||||
"version": "3.0.0-beta.19.5",
|
||||
"version": "3.0.0-beta.20",
|
||||
"description": "This is the description of the plugin.",
|
||||
"strapi": {
|
||||
"name": "Email",
|
||||
@ -13,13 +13,13 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"lodash": "^4.17.11",
|
||||
"strapi-provider-email-sendmail": "3.0.0-beta.19.5",
|
||||
"strapi-utils": "3.0.0-beta.19.5"
|
||||
"strapi-provider-email-sendmail": "3.0.0-beta.20",
|
||||
"strapi-utils": "3.0.0-beta.20"
|
||||
},
|
||||
"devDependencies": {
|
||||
"react-copy-to-clipboard": "5.0.1",
|
||||
"rimraf": "3.0.0",
|
||||
"strapi-helper-plugin": "3.0.0-beta.19.5"
|
||||
"strapi-helper-plugin": "3.0.0-beta.20"
|
||||
},
|
||||
"author": {
|
||||
"name": "Strapi team",
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "strapi-plugin-graphql",
|
||||
"version": "3.0.0-beta.19.5",
|
||||
"version": "3.0.0-beta.20",
|
||||
"description": "This is the description of the plugin.",
|
||||
"strapi": {
|
||||
"name": "graphql",
|
||||
@ -24,7 +24,7 @@
|
||||
"koa-compose": "^4.1.0",
|
||||
"lodash": "4.17.11",
|
||||
"pluralize": "^7.0.0",
|
||||
"strapi-utils": "3.0.0-beta.19.5"
|
||||
"strapi-utils": "3.0.0-beta.20"
|
||||
},
|
||||
"devDependencies": {
|
||||
"cross-env": "^5.2.0",
|
||||
|
||||
@ -44,7 +44,7 @@ const Card = ({
|
||||
: getFileExtension(ext);
|
||||
|
||||
const handleClick = () => {
|
||||
if (!isDisabled) {
|
||||
if (!isDisabled || checked) {
|
||||
onClick(id);
|
||||
}
|
||||
};
|
||||
|
||||
@ -8,7 +8,7 @@ import Flex from '../Flex';
|
||||
import Chevron from './Chevron';
|
||||
|
||||
const InputFilePreview = ({ file, onClick, isSlider }) => {
|
||||
const fileUrl = prefixFileUrlWithBackendUrl(get(file, ['formats', 'thumbnail', 'url'], file.url));
|
||||
const fileUrl = prefixFileUrlWithBackendUrl(get(file, ['formats', 'small', 'url'], file.url));
|
||||
|
||||
return (
|
||||
<Flex
|
||||
|
||||
@ -57,7 +57,7 @@ const List = ({
|
||||
>
|
||||
{(checked || canSelect) && (
|
||||
<>
|
||||
{isAllowed && (
|
||||
{(checked || isAllowed) && (
|
||||
<CardControlsWrapper leftAlign className="card-control-wrapper">
|
||||
<Checkbox
|
||||
name={`${id}`}
|
||||
|
||||
@ -5,9 +5,11 @@ import {
|
||||
createNewFilesToDownloadArray,
|
||||
createNewFilesToUploadArray,
|
||||
formatFileForEditing,
|
||||
getType,
|
||||
} from '../../utils';
|
||||
|
||||
const initialState = {
|
||||
allowedTypes: [],
|
||||
selectedFiles: [],
|
||||
files: [],
|
||||
filesToUpload: [],
|
||||
@ -264,17 +266,21 @@ const reducer = (state, action) =>
|
||||
break;
|
||||
}
|
||||
case 'TOGGLE_SELECT_ALL': {
|
||||
const allowedFiles =
|
||||
state.allowedTypes.length > 0
|
||||
? state.files.filter(file => state.allowedTypes.includes(getType(file.mime)))
|
||||
: state.files;
|
||||
const comparator = (first, second) => first.id === second.id;
|
||||
const isSelected =
|
||||
intersectionWith(state.selectedFiles, state.files, comparator).length ===
|
||||
state.files.length;
|
||||
intersectionWith(state.selectedFiles, allowedFiles, comparator).length ===
|
||||
allowedFiles.length;
|
||||
|
||||
if (isSelected) {
|
||||
draftState.selectedFiles = differenceWith(state.selectedFiles, state.files, comparator);
|
||||
break;
|
||||
}
|
||||
|
||||
draftState.selectedFiles = unionWith(state.selectedFiles, state.files, comparator);
|
||||
draftState.selectedFiles = unionWith(state.selectedFiles, allowedFiles, comparator);
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
@ -725,6 +725,7 @@ describe('UPLOAD | containers | ModalStepper | reducer', () => {
|
||||
type: 'TOGGLE_SELECT_ALL',
|
||||
};
|
||||
const state = {
|
||||
allowedTypes: [],
|
||||
selectedFiles: [],
|
||||
files: [
|
||||
{
|
||||
@ -750,6 +751,7 @@ describe('UPLOAD | containers | ModalStepper | reducer', () => {
|
||||
],
|
||||
};
|
||||
const expected = {
|
||||
allowedTypes: [],
|
||||
selectedFiles: [
|
||||
{
|
||||
id: 1,
|
||||
@ -802,6 +804,7 @@ describe('UPLOAD | containers | ModalStepper | reducer', () => {
|
||||
type: 'TOGGLE_SELECT_ALL',
|
||||
};
|
||||
const state = {
|
||||
allowedTypes: [],
|
||||
selectedFiles: [
|
||||
{
|
||||
id: 1,
|
||||
@ -848,6 +851,7 @@ describe('UPLOAD | containers | ModalStepper | reducer', () => {
|
||||
],
|
||||
};
|
||||
const expected = {
|
||||
allowedTypes: [],
|
||||
selectedFiles: [],
|
||||
files: [
|
||||
{
|
||||
@ -879,6 +883,7 @@ describe('UPLOAD | containers | ModalStepper | reducer', () => {
|
||||
type: 'TOGGLE_SELECT_ALL',
|
||||
};
|
||||
const state = {
|
||||
allowedTypes: [],
|
||||
selectedFiles: [
|
||||
{
|
||||
id: 1,
|
||||
@ -915,6 +920,7 @@ describe('UPLOAD | containers | ModalStepper | reducer', () => {
|
||||
],
|
||||
};
|
||||
const expected = {
|
||||
allowedTypes: [],
|
||||
selectedFiles: [
|
||||
{
|
||||
id: 1,
|
||||
@ -967,6 +973,7 @@ describe('UPLOAD | containers | ModalStepper | reducer', () => {
|
||||
type: 'TOGGLE_SELECT_ALL',
|
||||
};
|
||||
const state = {
|
||||
allowedTypes: [],
|
||||
selectedFiles: [
|
||||
{
|
||||
id: 1,
|
||||
@ -1013,6 +1020,7 @@ describe('UPLOAD | containers | ModalStepper | reducer', () => {
|
||||
],
|
||||
};
|
||||
const expected = {
|
||||
allowedTypes: [],
|
||||
selectedFiles: [
|
||||
{
|
||||
id: 1,
|
||||
@ -1080,11 +1088,12 @@ describe('UPLOAD | containers | ModalStepper | reducer', () => {
|
||||
};
|
||||
expect(reducer(state, action)).toEqual(expected);
|
||||
});
|
||||
it('should deselect all files of the current page only', () => {
|
||||
it('should deselect all files of the current page only event if not allowed', () => {
|
||||
const action = {
|
||||
type: 'TOGGLE_SELECT_ALL',
|
||||
};
|
||||
const state = {
|
||||
allowedTypes: ['video'],
|
||||
selectedFiles: [
|
||||
{
|
||||
id: 1,
|
||||
@ -1151,6 +1160,7 @@ describe('UPLOAD | containers | ModalStepper | reducer', () => {
|
||||
],
|
||||
};
|
||||
const expected = {
|
||||
allowedTypes: ['video'],
|
||||
selectedFiles: [
|
||||
{
|
||||
id: 1,
|
||||
@ -1198,6 +1208,135 @@ describe('UPLOAD | containers | ModalStepper | reducer', () => {
|
||||
};
|
||||
expect(reducer(state, action)).toEqual(expected);
|
||||
});
|
||||
it('should select the allowed files', () => {
|
||||
const action = {
|
||||
type: 'TOGGLE_SELECT_ALL',
|
||||
};
|
||||
const state = {
|
||||
allowedTypes: ['image', 'file'],
|
||||
selectedFiles: [],
|
||||
files: [
|
||||
{
|
||||
id: 1,
|
||||
name: 'myImage',
|
||||
ext: '.png',
|
||||
mime: 'image/png',
|
||||
size: 146.25,
|
||||
url: '/uploads/ba0c3352c4b14132aed3fcf3110b481c.png',
|
||||
created_at: '2020-03-04T09:45:32.444Z',
|
||||
updated_at: '2020-03-04T09:45:32.444Z',
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
name: 'myFile',
|
||||
ext: '.png',
|
||||
mime: 'application/pdf',
|
||||
size: 2.24,
|
||||
url: '/uploads/ba0c3352c4b14132aed3fcf3110b481c.png',
|
||||
created_at: '2020-03-04T09:45:32.444Z',
|
||||
updated_at: '2020-03-04T09:45:32.444Z',
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
name: 'myVideo',
|
||||
ext: '.png',
|
||||
mime: 'video/mp4',
|
||||
size: 146.25,
|
||||
url: '/uploads/ba0c3352c4b14132aed3fcf3110b481c.png',
|
||||
created_at: '2020-03-04T09:45:32.444Z',
|
||||
updated_at: '2020-03-04T09:45:32.444Z',
|
||||
},
|
||||
{
|
||||
id: 4,
|
||||
name: 'mySecondImage',
|
||||
ext: '.png',
|
||||
mime: 'image/jpg',
|
||||
size: 146.25,
|
||||
url: '/uploads/ba0c3352c4b14132aed3fcf3110b481c.png',
|
||||
created_at: '2020-03-04T09:45:32.444Z',
|
||||
updated_at: '2020-03-04T09:45:32.444Z',
|
||||
},
|
||||
],
|
||||
};
|
||||
const expected = {
|
||||
selectedFiles: [
|
||||
{
|
||||
id: 1,
|
||||
name: 'myImage',
|
||||
ext: '.png',
|
||||
mime: 'image/png',
|
||||
size: 146.25,
|
||||
url: '/uploads/ba0c3352c4b14132aed3fcf3110b481c.png',
|
||||
created_at: '2020-03-04T09:45:32.444Z',
|
||||
updated_at: '2020-03-04T09:45:32.444Z',
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
name: 'myFile',
|
||||
ext: '.png',
|
||||
mime: 'application/pdf',
|
||||
size: 2.24,
|
||||
url: '/uploads/ba0c3352c4b14132aed3fcf3110b481c.png',
|
||||
created_at: '2020-03-04T09:45:32.444Z',
|
||||
updated_at: '2020-03-04T09:45:32.444Z',
|
||||
},
|
||||
{
|
||||
id: 4,
|
||||
name: 'mySecondImage',
|
||||
ext: '.png',
|
||||
mime: 'image/jpg',
|
||||
size: 146.25,
|
||||
url: '/uploads/ba0c3352c4b14132aed3fcf3110b481c.png',
|
||||
created_at: '2020-03-04T09:45:32.444Z',
|
||||
updated_at: '2020-03-04T09:45:32.444Z',
|
||||
},
|
||||
],
|
||||
allowedTypes: ['image', 'file'],
|
||||
files: [
|
||||
{
|
||||
id: 1,
|
||||
name: 'myImage',
|
||||
ext: '.png',
|
||||
mime: 'image/png',
|
||||
size: 146.25,
|
||||
url: '/uploads/ba0c3352c4b14132aed3fcf3110b481c.png',
|
||||
created_at: '2020-03-04T09:45:32.444Z',
|
||||
updated_at: '2020-03-04T09:45:32.444Z',
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
name: 'myFile',
|
||||
ext: '.png',
|
||||
mime: 'application/pdf',
|
||||
size: 2.24,
|
||||
url: '/uploads/ba0c3352c4b14132aed3fcf3110b481c.png',
|
||||
created_at: '2020-03-04T09:45:32.444Z',
|
||||
updated_at: '2020-03-04T09:45:32.444Z',
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
name: 'myVideo',
|
||||
ext: '.png',
|
||||
mime: 'video/mp4',
|
||||
size: 146.25,
|
||||
url: '/uploads/ba0c3352c4b14132aed3fcf3110b481c.png',
|
||||
created_at: '2020-03-04T09:45:32.444Z',
|
||||
updated_at: '2020-03-04T09:45:32.444Z',
|
||||
},
|
||||
{
|
||||
id: 4,
|
||||
name: 'mySecondImage',
|
||||
ext: '.png',
|
||||
mime: 'image/jpg',
|
||||
size: 146.25,
|
||||
url: '/uploads/ba0c3352c4b14132aed3fcf3110b481c.png',
|
||||
created_at: '2020-03-04T09:45:32.444Z',
|
||||
updated_at: '2020-03-04T09:45:32.444Z',
|
||||
},
|
||||
],
|
||||
};
|
||||
expect(reducer(state, action)).toEqual(expected);
|
||||
});
|
||||
});
|
||||
|
||||
describe('GO_TO', () => {
|
||||
@ -1574,6 +1713,7 @@ describe('UPLOAD | containers | ModalStepper | reducer', () => {
|
||||
const action = { type: 'RESET_PROPS' };
|
||||
const state = { test: true };
|
||||
const expected = {
|
||||
allowedTypes: [],
|
||||
selectedFiles: [],
|
||||
files: [],
|
||||
filesToDownload: [],
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "strapi-plugin-upload",
|
||||
"version": "3.0.0-beta.19.5",
|
||||
"version": "3.0.0-beta.20",
|
||||
"description": "This is the description of the plugin.",
|
||||
"strapi": {
|
||||
"name": "Media Library",
|
||||
@ -31,11 +31,11 @@
|
||||
"react-router": "^5.0.0",
|
||||
"react-router-dom": "^5.0.0",
|
||||
"react-transition-group": "^2.5.0",
|
||||
"reactstrap": "^5.0.0",
|
||||
"reactstrap": "8.4.1",
|
||||
"sharp": "0.24.1",
|
||||
"strapi-helper-plugin": "3.0.0-beta.19.5",
|
||||
"strapi-provider-upload-local": "3.0.0-beta.19.5",
|
||||
"strapi-utils": "3.0.0-beta.19.5",
|
||||
"strapi-helper-plugin": "3.0.0-beta.20",
|
||||
"strapi-provider-upload-local": "3.0.0-beta.20",
|
||||
"strapi-utils": "3.0.0-beta.20",
|
||||
"stream-to-array": "^2.3.0",
|
||||
"uuid": "^3.2.1"
|
||||
},
|
||||
|
||||
@ -33,7 +33,7 @@ const combineFilters = params => {
|
||||
|
||||
module.exports = {
|
||||
formatFileInfo({ filename, type, size }, fileInfo = {}, metas = {}) {
|
||||
const ext = '.' + mime.extension(type);
|
||||
const ext = '.' + mime.extension(type) || path.extname(filename);
|
||||
const baseName = path.basename(filename, path.extname(filename));
|
||||
|
||||
const usedName = fileInfo.name || baseName;
|
||||
|
||||
@ -249,6 +249,7 @@ module.exports = {
|
||||
|
||||
await strapi.plugins['users-permissions'].controllers.auth.emailConfirmation(
|
||||
context,
|
||||
null,
|
||||
true
|
||||
);
|
||||
let output = context.body.toJSON ? context.body.toJSON() : context.body;
|
||||
|
||||
@ -568,7 +568,7 @@ module.exports = {
|
||||
}
|
||||
},
|
||||
|
||||
async emailConfirmation(ctx, returnUser) {
|
||||
async emailConfirmation(ctx, next, returnUser) {
|
||||
const params = ctx.query;
|
||||
|
||||
const decodedToken = await strapi.plugins['users-permissions'].services.jwt.verify(
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "strapi-plugin-users-permissions",
|
||||
"version": "3.0.0-beta.19.5",
|
||||
"version": "3.0.0-beta.20",
|
||||
"description": "Protect your API with a full-authentication process based on JWT",
|
||||
"strapi": {
|
||||
"name": "Roles & Permissions",
|
||||
@ -29,11 +29,11 @@
|
||||
"react-router": "^5.0.0",
|
||||
"react-router-dom": "^5.0.0",
|
||||
"react-transition-group": "^2.5.0",
|
||||
"reactstrap": "^5.0.0",
|
||||
"reactstrap": "8.4.1",
|
||||
"redux-saga": "^0.16.0",
|
||||
"request": "^2.83.0",
|
||||
"strapi-helper-plugin": "3.0.0-beta.19.5",
|
||||
"strapi-utils": "3.0.0-beta.19.5",
|
||||
"strapi-helper-plugin": "3.0.0-beta.20",
|
||||
"strapi-utils": "3.0.0-beta.20",
|
||||
"uuid": "^3.1.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
|
||||
@ -9,6 +9,34 @@ const request = require('request');
|
||||
* @description: A set of functions similar to controller's actions to avoid code duplication.
|
||||
*/
|
||||
|
||||
const DEFAULT_PERMISSIONS = [
|
||||
{ action: 'admincallback', controller: 'auth', type: 'users-permissions', roleType: 'public' },
|
||||
{ action: 'adminregister', controller: 'auth', type: 'users-permissions', roleType: 'public' },
|
||||
{ action: 'callback', controller: 'auth', type: 'users-permissions', roleType: 'public' },
|
||||
{ action: 'connect', controller: 'auth', type: 'users-permissions', roleType: null },
|
||||
{ action: 'forgotpassword', controller: 'auth', type: 'users-permissions', roleType: 'public' },
|
||||
{ action: 'register', controller: 'auth', type: 'users-permissions', roleType: 'public' },
|
||||
{
|
||||
action: 'emailconfirmation',
|
||||
controller: 'auth',
|
||||
type: 'users-permissions',
|
||||
roleType: 'public',
|
||||
},
|
||||
{ action: 'changepassword', controller: 'auth', type: 'users-permissions', roleType: 'public' },
|
||||
{ action: 'init', controller: 'userspermissions', type: null, roleType: null },
|
||||
{ action: 'me', controller: 'user', type: 'users-permissions', roleType: null },
|
||||
{ action: 'autoreload', controller: null, type: null, roleType: null },
|
||||
];
|
||||
|
||||
const isPermissionEnabled = (permission, role) =>
|
||||
DEFAULT_PERMISSIONS.some(
|
||||
defaultPerm =>
|
||||
(defaultPerm.action === null || permission.action === defaultPerm.action) &&
|
||||
(defaultPerm.controller === null || permission.controller === defaultPerm.controller) &&
|
||||
(defaultPerm.type === null || permission.type === defaultPerm.type) &&
|
||||
(defaultPerm.roleType === null || role.type === defaultPerm.roleType)
|
||||
);
|
||||
|
||||
module.exports = {
|
||||
async createRole(params) {
|
||||
if (!params.type) {
|
||||
@ -228,16 +256,17 @@ module.exports = {
|
||||
},
|
||||
|
||||
async updatePermissions() {
|
||||
// fetch all the current permissions from the database, and format them into an array of actions.
|
||||
const databasePermissions = await strapi
|
||||
const { primaryKey } = strapi.query('permission', 'users-permissions');
|
||||
const roles = await strapi.query('role', 'users-permissions').find({}, []);
|
||||
const rolesMap = roles.reduce((map, role) => ({ ...map, [role[primaryKey]]: role }), {});
|
||||
|
||||
const dbPermissions = await strapi
|
||||
.query('permission', 'users-permissions')
|
||||
.find({ _limit: -1 });
|
||||
|
||||
const actionsMap = databasePermissions.reduce((acc, permission) => {
|
||||
acc[`${permission.type}.${permission.controller}.${permission.action}`] = permission.id;
|
||||
return acc;
|
||||
}, {});
|
||||
const stringActions = Object.keys(actionsMap);
|
||||
let permissionsFoundInDB = dbPermissions.map(
|
||||
p => `${p.type}.${p.controller}.${p.action}.${p.role[primaryKey]}`
|
||||
);
|
||||
permissionsFoundInDB = _.uniq(permissionsFoundInDB);
|
||||
|
||||
// Aggregate first level actions.
|
||||
const appActions = Object.keys(strapi.api || {}).reduce((acc, api) => {
|
||||
@ -265,170 +294,70 @@ module.exports = {
|
||||
return acc;
|
||||
}, []);
|
||||
|
||||
// Merge array into one.
|
||||
const currentActions = appActions.concat(pluginsActions);
|
||||
// Count permissions available.
|
||||
const permissions = databasePermissions.length;
|
||||
const actionsFoundInFiles = appActions.concat(pluginsActions);
|
||||
|
||||
// create permissions for each role
|
||||
let permissionsFoundInFiles = actionsFoundInFiles.reduce(
|
||||
(acc, action) => [...acc, ...roles.map(role => `${action}.${role[primaryKey]}`)],
|
||||
[]
|
||||
);
|
||||
permissionsFoundInFiles = _.uniq(permissionsFoundInFiles);
|
||||
|
||||
// Compare to know if actions have been added or removed from controllers.
|
||||
if (!_.isEqual(stringActions, currentActions) || permissions < 1) {
|
||||
if (!_.isEqual(permissionsFoundInDB.sort(), permissionsFoundInFiles.sort())) {
|
||||
const splitted = str => {
|
||||
const [type, controller, action] = str.split('.');
|
||||
const [type, controller, action, roleId] = str.split('.');
|
||||
|
||||
return { type, controller, action };
|
||||
return { type, controller, action, roleId };
|
||||
};
|
||||
|
||||
const defaultPolicy = (obj, role) => {
|
||||
const isAdminCallback =
|
||||
obj.action === 'admincallback' &&
|
||||
obj.controller === 'auth' &&
|
||||
obj.type === 'users-permissions' &&
|
||||
role.type === 'public';
|
||||
const isAdminRegister =
|
||||
obj.action === 'adminregister' &&
|
||||
obj.controller === 'auth' &&
|
||||
obj.type === 'users-permissions' &&
|
||||
role.type === 'public';
|
||||
const isCallback =
|
||||
obj.action === 'callback' &&
|
||||
obj.controller === 'auth' &&
|
||||
obj.type === 'users-permissions' &&
|
||||
role.type === 'public';
|
||||
const isConnect =
|
||||
obj.action === 'connect' && obj.controller === 'auth' && obj.type === 'users-permissions';
|
||||
const isPassword =
|
||||
obj.action === 'forgotpassword' &&
|
||||
obj.controller === 'auth' &&
|
||||
obj.type === 'users-permissions' &&
|
||||
role.type === 'public';
|
||||
const isRegister =
|
||||
obj.action === 'register' &&
|
||||
obj.controller === 'auth' &&
|
||||
obj.type === 'users-permissions' &&
|
||||
role.type === 'public';
|
||||
const isConfirmation =
|
||||
obj.action === 'emailconfirmation' &&
|
||||
obj.controller === 'auth' &&
|
||||
obj.type === 'users-permissions' &&
|
||||
role.type === 'public';
|
||||
const isNewPassword =
|
||||
obj.action === 'changepassword' &&
|
||||
obj.controller === 'auth' &&
|
||||
obj.type === 'users-permissions' &&
|
||||
role.type === 'public';
|
||||
const isInit = obj.action === 'init' && obj.controller === 'userspermissions';
|
||||
const isMe =
|
||||
obj.action === 'me' && obj.controller === 'user' && obj.type === 'users-permissions';
|
||||
const isReload = obj.action === 'autoreload';
|
||||
const enabled =
|
||||
isCallback ||
|
||||
isRegister ||
|
||||
isInit ||
|
||||
isPassword ||
|
||||
isNewPassword ||
|
||||
isMe ||
|
||||
isReload ||
|
||||
isConnect ||
|
||||
isConfirmation ||
|
||||
isAdminCallback ||
|
||||
isAdminRegister;
|
||||
|
||||
return Object.assign(obj, { enabled, policy: '' });
|
||||
};
|
||||
|
||||
// Retrieve roles
|
||||
const roles = await strapi.query('role', 'users-permissions').find({}, []);
|
||||
|
||||
// We have to know the difference to add or remove
|
||||
// the permissions entries in the database.
|
||||
const toRemove = _.difference(stringActions, currentActions).map(splitted);
|
||||
|
||||
const toAdd = (permissions < 1
|
||||
? currentActions
|
||||
: _.difference(currentActions, stringActions)
|
||||
).map(splitted);
|
||||
// We have to know the difference to add or remove the permissions entries in the database.
|
||||
const toRemove = _.difference(permissionsFoundInDB, permissionsFoundInFiles).map(splitted);
|
||||
const toAdd = _.difference(permissionsFoundInFiles, permissionsFoundInDB).map(splitted);
|
||||
|
||||
const query = strapi.query('permission', 'users-permissions');
|
||||
|
||||
const createActions = role =>
|
||||
Promise.all(
|
||||
toAdd.map(action => {
|
||||
const data = {
|
||||
...defaultPolicy(action, role),
|
||||
role: role.id,
|
||||
};
|
||||
|
||||
return query.create(data);
|
||||
})
|
||||
);
|
||||
|
||||
// Execute request to update entries in database for each role.
|
||||
await Promise.all([
|
||||
Promise.all(roles.map(createActions)),
|
||||
Promise.all(toRemove.map(action => query.delete(action))),
|
||||
Promise.all(
|
||||
toAdd.map(permission =>
|
||||
query.create({
|
||||
type: permission.type,
|
||||
controller: permission.controller,
|
||||
action: permission.action,
|
||||
enabled: isPermissionEnabled(permission, rolesMap[permission.roleId]),
|
||||
policy: '',
|
||||
role: permission.roleId,
|
||||
})
|
||||
)
|
||||
),
|
||||
Promise.all(
|
||||
toRemove.map(permission => {
|
||||
const { type, controller, action, roleId: role } = permission;
|
||||
return query.delete({ type, controller, action, role });
|
||||
})
|
||||
),
|
||||
]);
|
||||
}
|
||||
},
|
||||
|
||||
async removeDuplicate() {
|
||||
const { primaryKey } = strapi.query('permission', 'users-permissions');
|
||||
|
||||
// Retrieve permissions by creation date (ID or ObjectID).
|
||||
const permissions = await strapi
|
||||
.query('permission', 'users-permissions')
|
||||
.find({ _sort: `${primaryKey}`, _limit: -1 });
|
||||
|
||||
const value = permissions.reduce(
|
||||
(acc, permission) => {
|
||||
const key = `${permission.type}.controllers.${permission.controller}.${permission.action}.${permission.role[primaryKey]}`;
|
||||
|
||||
const index = acc.toKeep.findIndex(element => element === key);
|
||||
|
||||
if (index === -1) {
|
||||
acc.toKeep.push(key);
|
||||
} else {
|
||||
acc.toRemove.push(permission[primaryKey]);
|
||||
}
|
||||
|
||||
return acc;
|
||||
},
|
||||
{
|
||||
toKeep: [],
|
||||
toRemove: [],
|
||||
}
|
||||
);
|
||||
|
||||
if (value.toRemove.length > 0) {
|
||||
return strapi.query('permission', 'users-permissions').delete({
|
||||
[`${primaryKey}_in`]: value.toRemove,
|
||||
});
|
||||
}
|
||||
return Promise.resolve();
|
||||
},
|
||||
|
||||
async initialize() {
|
||||
const roleCount = await strapi.query('role', 'users-permissions').count();
|
||||
|
||||
// It has already been initialized.
|
||||
if (roleCount > 0) {
|
||||
await this.updatePermissions();
|
||||
await this.removeDuplicate();
|
||||
return;
|
||||
if (roleCount === 0) {
|
||||
await strapi.query('role', 'users-permissions').create({
|
||||
name: 'Authenticated',
|
||||
description: 'Default role given to authenticated user.',
|
||||
type: 'authenticated',
|
||||
});
|
||||
|
||||
await strapi.query('role', 'users-permissions').create({
|
||||
name: 'Public',
|
||||
description: 'Default role given to unauthenticated user.',
|
||||
type: 'public',
|
||||
});
|
||||
}
|
||||
|
||||
// Create two first default roles.
|
||||
await strapi.query('role', 'users-permissions').create({
|
||||
name: 'Authenticated',
|
||||
description: 'Default role given to authenticated user.',
|
||||
type: 'authenticated',
|
||||
});
|
||||
|
||||
await strapi.query('role', 'users-permissions').create({
|
||||
name: 'Public',
|
||||
description: 'Default role given to unauthenticated user.',
|
||||
type: 'public',
|
||||
});
|
||||
|
||||
return this.updatePermissions();
|
||||
},
|
||||
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "strapi-provider-email-amazon-ses",
|
||||
"version": "3.0.0-beta.19.5",
|
||||
"version": "3.0.0-beta.20",
|
||||
"description": "Amazon SES provider for strapi email",
|
||||
"homepage": "http://strapi.io",
|
||||
"keywords": [
|
||||
@ -15,7 +15,7 @@
|
||||
"main": "./lib",
|
||||
"dependencies": {
|
||||
"lodash": "^4.17.11",
|
||||
"node-ses": "^2.2.0"
|
||||
"node-ses": "^3.0.0"
|
||||
},
|
||||
"author": {
|
||||
"email": "nikolay@tsenkov.net",
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "strapi-provider-email-mailgun",
|
||||
"version": "3.0.0-beta.19.5",
|
||||
"version": "3.0.0-beta.20",
|
||||
"description": "Mailgun provider for strapi email plugin",
|
||||
"homepage": "http://strapi.io",
|
||||
"keywords": [
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "strapi-provider-email-sendgrid",
|
||||
"version": "3.0.0-beta.19.5",
|
||||
"version": "3.0.0-beta.20",
|
||||
"description": "Sendgrid provider for strapi email",
|
||||
"homepage": "http://strapi.io",
|
||||
"keywords": [
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "strapi-provider-email-sendmail",
|
||||
"version": "3.0.0-beta.19.5",
|
||||
"version": "3.0.0-beta.20",
|
||||
"description": "Sendmail provider for strapi email",
|
||||
"homepage": "http://strapi.io",
|
||||
"keywords": [
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "strapi-provider-upload-aws-s3",
|
||||
"version": "3.0.0-beta.19.5",
|
||||
"version": "3.0.0-beta.20",
|
||||
"description": "AWS S3 provider for strapi upload",
|
||||
"homepage": "http://strapi.io",
|
||||
"keywords": [
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "strapi-provider-upload-cloudinary",
|
||||
"version": "3.0.0-beta.19.5",
|
||||
"version": "3.0.0-beta.20",
|
||||
"description": "Cloudinary provider for strapi upload",
|
||||
"homepage": "http://strapi.io",
|
||||
"keywords": [
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "strapi-provider-upload-local",
|
||||
"version": "3.0.0-beta.19.5",
|
||||
"version": "3.0.0-beta.20",
|
||||
"description": "Local provider for strapi upload",
|
||||
"homepage": "http://strapi.io",
|
||||
"keywords": [
|
||||
|
||||
@ -29,7 +29,7 @@ module.exports = {
|
||||
const readStream = streamifier.createReadStream(file.buffer);
|
||||
const writeStream = client.upload({
|
||||
...options,
|
||||
remote: file.name,
|
||||
remote: file.hash,
|
||||
contentType: file.mime,
|
||||
});
|
||||
|
||||
@ -38,22 +38,21 @@ module.exports = {
|
||||
writeStream.on('error', error => error && reject(error));
|
||||
writeStream.on('success', result => {
|
||||
remoteURL()
|
||||
.then(data =>
|
||||
.then(data => {
|
||||
resolve(
|
||||
Object.assign(file, {
|
||||
name: result.name,
|
||||
mime: result.contentType,
|
||||
url: `${data.cdnSslUri}/${result.name}`,
|
||||
})
|
||||
)
|
||||
)
|
||||
);
|
||||
})
|
||||
.catch(err => console.error(err) && reject(err));
|
||||
});
|
||||
});
|
||||
},
|
||||
delete(file) {
|
||||
return new Promise((resolve, reject) => {
|
||||
client.removeFile(config.container, file.name, error => {
|
||||
client.removeFile(config.container, file.hash, error => {
|
||||
if (error) return reject(error);
|
||||
return resolve();
|
||||
});
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "strapi-provider-upload-rackspace",
|
||||
"version": "3.0.0-beta.19.5",
|
||||
"version": "3.0.0-beta.20",
|
||||
"description": "Rackspace provider for strapi upload",
|
||||
"main": "./lib",
|
||||
"keywords": [],
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "strapi-utils",
|
||||
"version": "3.0.0-beta.19.5",
|
||||
"version": "3.0.0-beta.20",
|
||||
"description": "Shared utilities for the Strapi packages",
|
||||
"homepage": "http://strapi.io",
|
||||
"keywords": [
|
||||
|
||||
@ -154,8 +154,6 @@ describe('Deep Filtering API', () => {
|
||||
},
|
||||
});
|
||||
|
||||
console.log('res', JSON.stringify(res.body, null, 2));
|
||||
|
||||
expect(Array.isArray(res.body)).toBe(true);
|
||||
expect(res.body.length).toBe(1);
|
||||
expect(res.body[0]).toMatchObject(data.collectors[1]);
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "strapi",
|
||||
"version": "3.0.0-beta.19.5",
|
||||
"version": "3.0.0-beta.20",
|
||||
"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": {
|
||||
@ -52,16 +52,16 @@
|
||||
"resolve-cwd": "^3.0.0",
|
||||
"rimraf": "^2.6.2",
|
||||
"shelljs": "^0.8.3",
|
||||
"strapi-database": "3.0.0-beta.19.5",
|
||||
"strapi-generate": "3.0.0-beta.19.5",
|
||||
"strapi-generate-api": "3.0.0-beta.19.5",
|
||||
"strapi-generate-controller": "3.0.0-beta.19.5",
|
||||
"strapi-generate-model": "3.0.0-beta.19.5",
|
||||
"strapi-generate-new": "3.0.0-beta.19.5",
|
||||
"strapi-generate-plugin": "3.0.0-beta.19.5",
|
||||
"strapi-generate-policy": "3.0.0-beta.19.5",
|
||||
"strapi-generate-service": "3.0.0-beta.19.5",
|
||||
"strapi-utils": "3.0.0-beta.19.5"
|
||||
"strapi-database": "3.0.0-beta.20",
|
||||
"strapi-generate": "3.0.0-beta.20",
|
||||
"strapi-generate-api": "3.0.0-beta.20",
|
||||
"strapi-generate-controller": "3.0.0-beta.20",
|
||||
"strapi-generate-model": "3.0.0-beta.20",
|
||||
"strapi-generate-new": "3.0.0-beta.20",
|
||||
"strapi-generate-plugin": "3.0.0-beta.20",
|
||||
"strapi-generate-policy": "3.0.0-beta.20",
|
||||
"strapi-generate-service": "3.0.0-beta.20",
|
||||
"strapi-utils": "3.0.0-beta.20"
|
||||
},
|
||||
"scripts": {
|
||||
"postinstall": "node lib/utils/success.js"
|
||||
|
||||
57
yarn.lock
57
yarn.lock
@ -4046,7 +4046,7 @@ aws-sign2@~0.7.0:
|
||||
resolved "https://registry.yarnpkg.com/aws-sign2/-/aws-sign2-0.7.0.tgz#b46e890934a9591f2d2f6f86d7e6a9f1b3fe76a8"
|
||||
integrity sha1-tG6JCTSpWR8tL2+G1+ap8bP+dqg=
|
||||
|
||||
aws4@^1.6.0, aws4@^1.8.0:
|
||||
aws4@1.9.1, aws4@^1.6.0, aws4@^1.8.0:
|
||||
version "1.9.1"
|
||||
resolved "https://registry.yarnpkg.com/aws4/-/aws4-1.9.1.tgz#7e33d8f7d449b3f673cd72deb9abdc552dbe528e"
|
||||
integrity sha512-wMHVg2EOHaMRxbzgFJ9gtjOOCrI80OHLG14rxi28XwOW8ux6IiEbRCGGGqCtdAIg4FQCbW20k9RsT4y3gJlFug==
|
||||
@ -11352,11 +11352,6 @@ lodash.isequal@^4.5.0:
|
||||
resolved "https://registry.yarnpkg.com/lodash.isequal/-/lodash.isequal-4.5.0.tgz#415c4478f2bcc30120c22ce10ed3226f7d3e18e0"
|
||||
integrity sha1-QVxEePK8wwEgwizhDtMib30+GOA=
|
||||
|
||||
lodash.isfunction@^3.0.9:
|
||||
version "3.0.9"
|
||||
resolved "https://registry.yarnpkg.com/lodash.isfunction/-/lodash.isfunction-3.0.9.tgz#06de25df4db327ac931981d1bdb067e5af68d051"
|
||||
integrity sha512-AirXNj15uRIMMPihnkInB4i3NHeb4iBtNg9WRWuK2o31S+ePwwNmDPaTL3o7dTJ+VXNZim7rFs4rxN4YU1oUJw==
|
||||
|
||||
lodash.isinteger@^4.0.4:
|
||||
version "4.0.4"
|
||||
resolved "https://registry.yarnpkg.com/lodash.isinteger/-/lodash.isinteger-4.0.4.tgz#619c0af3d03f8b04c31f5882840b77b11cd68343"
|
||||
@ -11372,11 +11367,6 @@ lodash.isnumber@^3.0.3:
|
||||
resolved "https://registry.yarnpkg.com/lodash.isnumber/-/lodash.isnumber-3.0.3.tgz#3ce76810c5928d03352301ac287317f11c0b1ffc"
|
||||
integrity sha1-POdoEMWSjQM1IwGsKHMX8RwLH/w=
|
||||
|
||||
lodash.isobject@^3.0.2:
|
||||
version "3.0.2"
|
||||
resolved "https://registry.yarnpkg.com/lodash.isobject/-/lodash.isobject-3.0.2.tgz#3c8fb8d5b5bf4bf90ae06e14f2a530a4ed935e1d"
|
||||
integrity sha1-PI+41bW/S/kK4G4U8qUwpO2TXh0=
|
||||
|
||||
lodash.isplainobject@4.0.6, lodash.isplainobject@^4.0.6:
|
||||
version "4.0.6"
|
||||
resolved "https://registry.yarnpkg.com/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz#7c526a52d89b45c45cc690b88163be0497f550cb"
|
||||
@ -11432,11 +11422,6 @@ lodash.throttle@^4.1.1:
|
||||
resolved "https://registry.yarnpkg.com/lodash.throttle/-/lodash.throttle-4.1.1.tgz#c23e91b710242ac70c37f1e1cda9274cc39bf2f4"
|
||||
integrity sha1-wj6RtxAkKscMN/HhzaknTMOb8vQ=
|
||||
|
||||
lodash.tonumber@^4.0.3:
|
||||
version "4.0.3"
|
||||
resolved "https://registry.yarnpkg.com/lodash.tonumber/-/lodash.tonumber-4.0.3.tgz#0b96b31b35672793eb7f5a63ee791f1b9e9025d9"
|
||||
integrity sha1-C5azGzVnJ5Prf1pj7nkfG56QJdk=
|
||||
|
||||
lodash.uniq@^4.5.0:
|
||||
version "4.5.0"
|
||||
resolved "https://registry.yarnpkg.com/lodash.uniq/-/lodash.uniq-4.5.0.tgz#d0225373aeb652adc1bc82e4945339a842754773"
|
||||
@ -12504,15 +12489,14 @@ node-schedule@1.3.2:
|
||||
long-timeout "0.1.1"
|
||||
sorted-array-functions "^1.0.0"
|
||||
|
||||
node-ses@^2.2.0:
|
||||
version "2.2.1"
|
||||
resolved "https://registry.yarnpkg.com/node-ses/-/node-ses-2.2.1.tgz#41b113b2a4561fc0e9ede1f72705821a172b73b0"
|
||||
integrity sha512-+vfOKdvb99LgbEKmL7rTw9GbNZ71fetJ4vseYsoHkfdzRXWsBalepf7LEn5Wsg/swoLM3dzxvWfOigm9KtkYgQ==
|
||||
node-ses@^3.0.0:
|
||||
version "3.0.0"
|
||||
resolved "https://registry.yarnpkg.com/node-ses/-/node-ses-3.0.0.tgz#c228e114a434974750582721f9a120ebc3f090a7"
|
||||
integrity sha512-8YJ0Gxgk77ZaOWQRqasZOyxIAOIV8T66toF0uxFEMjP/LFK6ZFxWszQoTME0tvDL0HIjk8Jx38aXYfS2HneK2Q==
|
||||
dependencies:
|
||||
aws4 "^1.8.0"
|
||||
aws4 "1.9.1"
|
||||
debug "^2.6.9"
|
||||
request "^2.88.0"
|
||||
xml2js "^0.4.19"
|
||||
request "2.88.2"
|
||||
|
||||
nodemailer-fetch@1.6.0:
|
||||
version "1.6.0"
|
||||
@ -13615,7 +13599,7 @@ pn@^1.1.0:
|
||||
resolved "https://registry.yarnpkg.com/pn/-/pn-1.1.0.tgz#e2f4cef0e219f463c179ab37463e4e1ecdccbafb"
|
||||
integrity sha512-2qHaIQr2VLRFoxe2nASzsV6ef4yOOH+Fi9FBOVH6cqeSgUnoyySPZkxzLuzd+RYOQTRpROA0ztTMqxROKSb/nA==
|
||||
|
||||
popper.js@^1.12.9, popper.js@^1.14.4:
|
||||
popper.js@^1.14.4:
|
||||
version "1.16.1"
|
||||
resolved "https://registry.yarnpkg.com/popper.js/-/popper.js-1.16.1.tgz#2a223cb3dc7b6213d740e40372be40de43e65b1b"
|
||||
integrity sha512-Wb4p1J4zyFTbM+u6WuO4XstYx4Ky9Cewe4DWrel7B0w6VVICvPwdOpotjzcf6eD8TsckVnIMNONQyPIUFOUbCQ==
|
||||
@ -14638,14 +14622,6 @@ react-outside-click-handler@^1.2.4:
|
||||
object.values "^1.1.0"
|
||||
prop-types "^15.7.2"
|
||||
|
||||
react-popper@^0.8.3:
|
||||
version "0.8.3"
|
||||
resolved "https://registry.yarnpkg.com/react-popper/-/react-popper-0.8.3.tgz#0f73333137c9fb0af6ec4074d2d0585a0a0461e1"
|
||||
integrity sha1-D3MzMTfJ+wr27EB00tBYWgoEYeE=
|
||||
dependencies:
|
||||
popper.js "^1.12.9"
|
||||
prop-types "^15.6.0"
|
||||
|
||||
react-popper@^1.3.6:
|
||||
version "1.3.7"
|
||||
resolved "https://registry.yarnpkg.com/react-popper/-/react-popper-1.3.7.tgz#f6a3471362ef1f0d10a4963673789de1baca2324"
|
||||
@ -14823,20 +14799,7 @@ react@^16.9.0:
|
||||
object-assign "^4.1.1"
|
||||
prop-types "^15.6.2"
|
||||
|
||||
reactstrap@^5.0.0:
|
||||
version "5.0.0"
|
||||
resolved "https://registry.yarnpkg.com/reactstrap/-/reactstrap-5.0.0.tgz#d8948534df4816eddfb162a51643a499388e9228"
|
||||
integrity sha512-y0eju/LAK7gbEaTFfq2iW92MF7/5Qh0tc1LgYr2mg92IX8NodGc03a+I+cp7bJ0VXHAiLy0bFL9UP89oSm4cBg==
|
||||
dependencies:
|
||||
classnames "^2.2.3"
|
||||
lodash.isfunction "^3.0.9"
|
||||
lodash.isobject "^3.0.2"
|
||||
lodash.tonumber "^4.0.3"
|
||||
prop-types "^15.5.8"
|
||||
react-popper "^0.8.3"
|
||||
react-transition-group "^2.2.1"
|
||||
|
||||
reactstrap@^8.0.0, reactstrap@^8.0.1:
|
||||
reactstrap@8.4.1:
|
||||
version "8.4.1"
|
||||
resolved "https://registry.yarnpkg.com/reactstrap/-/reactstrap-8.4.1.tgz#c7f63b9057f58b52833061711ebe235b9ec4e3e5"
|
||||
integrity sha512-oAjp9PYYUGKl7SLXwrQ1oRIrYw0MqfO2mUqYgGapFKHG2uwjEtLip5rYxtMujkGx3COjH5FX1WtcfNU4oqpH0Q==
|
||||
@ -15347,7 +15310,7 @@ request@2.87.0:
|
||||
tunnel-agent "^0.6.0"
|
||||
uuid "^3.1.0"
|
||||
|
||||
request@^2.74.0, request@^2.83.0, request@^2.87.0, request@^2.88.0:
|
||||
request@2.88.2, request@^2.74.0, request@^2.83.0, request@^2.87.0, request@^2.88.0:
|
||||
version "2.88.2"
|
||||
resolved "https://registry.yarnpkg.com/request/-/request-2.88.2.tgz#d73c918731cb5a87da047e207234146f664d12b3"
|
||||
integrity sha512-MsvtOrfG9ZcrOwAW+Qi+F6HbD0CWXEh9ou77uOb7FM2WPhwT7smM833PzanhJLsgXjN89Ir6V2PczXNnMpwKhw==
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user