Merge branch 'master' into master

This commit is contained in:
Luca 2018-01-23 14:02:31 +01:00 committed by GitHub
commit 202d5d97c4
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
62 changed files with 725 additions and 417 deletions

View File

@ -17,7 +17,7 @@ before_install:
- rm -rf node_modules/
install:
- npm run setup
- npm run setup --debug
script:
- npm run doc

View File

@ -16,7 +16,7 @@
* [Table of contents](concepts/concepts.md)
### Guides
* [Authentification](guides/authentification.md)
* [Authentication](guides/authentication.md)
* [Configurations](configurations/configurations.md)
* [Controllers](guides/controllers.md)
* [Deployment](guides/deployment.md)

View File

@ -176,7 +176,7 @@ The `gzip` middleware will be loaded after the `p3p` middleware. All the others
],
"order": [],
"after": [
"parser"
"parser",
"router"
]
}
@ -216,7 +216,7 @@ We assume that we set the `./config/middleware.json` file like this:
"gzip"
],
"after": [
"parser"
"parser",
"router"
]
}

View File

@ -11,7 +11,7 @@ $.ajax({
type: 'POST',
url: 'http://localhost:1337/auth/local/register',
data: {
username: 'Strapi user'
username: 'Strapi user',
email: 'user@strapi.io',
password: 'strapiPassword'
},
@ -30,7 +30,7 @@ $.ajax({
This route lets you log your users in by getting an authentication token.
#### Usage
#### Local
- The `identifier` param can either be an email or a username.
@ -53,6 +53,32 @@ $.ajax({
});
```
## Providers
Thanks to [Grant](https://github.com/simov/grant) and [Purest](https://github.com/simov/purest), you can easily use OAuth and OAuth2
providers to enable authentication in your application. By default,
Strapi comes with four providers:
- Facebook
- Google
- Github
- Linkedin2 (Oauth2 Provider for Linkedin)
To use the providers authentication, set your credentials in
`./plugins/users-permissions/config/environments/development/grant.json`.
Redirect your user to: `GET /connect/:provider`. eg: `GET /connect/facebook`
After his approval, he will be redirected to `/auth/:provider/callback`. The `jwt` and `user` data will be available in the body response.
Response payload:
```js
{
"user": {},
"jwt": ""
}
```
## Use your token to be identified as a user.
By default, each API request is identified as `guest` role (see permissions of `guest`'s role in your admin dashboard). To make a request as a user, you have to set the `Authorization` token in your request headers. You receive a 401 error if you are not authorized to make this request or if your authorization header is not correct.
@ -91,7 +117,7 @@ $.ajax({
type: 'POST',
url: 'http://localhost:1337/auth/forgot-password',
data: {
email: 'user@strapi.io'
email: 'user@strapi.io',
url: 'http://mon-site.com/rest-password'
},
done: function() {
@ -118,8 +144,8 @@ $.ajax({
type: 'POST',
url: 'http://localhost:1337/auth/reset-password',
data: {
code: 'privateCode'
password: 'myNewPassword'
code: 'privateCode',
password: 'myNewPassword',
passwordConfirmation: 'myNewPassword'
},
done: function() {

View File

@ -48,14 +48,14 @@ You need to define the english and french translation for this key.
**Path —** `./config/locales/en_US.json`.
```json
{
"Hello %s": "Hello %s"
"Hello %s": "Hello %s"
}
```
**Path —** `./config/locales/fr_FR.json`.
```json
{
"Hello %s": "Bonjour %s"
"Hello %s": "Bonjour %s"
}
```

View File

@ -137,8 +137,8 @@ For example "color=blue&size=small":
```js
{
color: 'blue',
size: 'small'
color: 'blue',
size: 'small'
}
```
@ -163,8 +163,8 @@ ctx.set('ETag', '123');
// cache is ok
if (ctx.fresh) {
ctx.status = 304;
return;
ctx.status = 304;
return;
}
// cache is stale
@ -238,7 +238,7 @@ only images are sent to a given route:
if (ctx.is('image/*')) {
// process
} else {
ctx.throw(415, 'images only!');
ctx.throw(415, 'images only!');
}
```
@ -300,10 +300,10 @@ or use a switch:
```js
switch (ctx.accepts('json', 'html', 'text')) {
case 'json': break;
case 'html': break;
case 'text': break;
default: ctx.throw(406, 'json, html, or text only');
case 'json': break;
case 'html': break;
case 'text': break;
default: ctx.throw(406, 'json, html, or text only');
}
```

View File

@ -155,7 +155,7 @@ Here's an example of stream error handling without automatically destroying the
const PassThrough = require('stream').PassThrough;
app.use(async ctx => {
ctx.body = someHTTPStream.on('error', ctx.onerror).pipe(PassThrough());
ctx.body = someHTTPStream.on('error', ctx.onerror).pipe(PassThrough());
});
```
@ -192,8 +192,8 @@ Set several response header `fields` with an object:
```js
ctx.set({
'Etag': '1234',
'Last-Modified': date
'Etag': '1234',
'Last-Modified': date
});
```
@ -247,7 +247,7 @@ let body = ctx.body;
if (!body || body.pipe) return;
if (Buffer.isBuffer(body)) body = body.toString();
ctx.body = minify(body);
ctx.body = minify(body);
});
```
@ -468,7 +468,7 @@ Here's an example of stream error handling without automatically destroying the
const PassThrough = require('stream').PassThrough;
app.use(async ctx => {
ctx.body = someHTTPStream.on('error', ctx.onerror).pipe(PassThrough());
ctx.body = someHTTPStream.on('error', ctx.onerror).pipe(PassThrough());
});
```
@ -505,8 +505,8 @@ Set several response header `fields` with an object:
```js
ctx.set({
'Etag': '1234',
'Last-Modified': date
'Etag': '1234',
'Last-Modified': date
});
```
@ -560,7 +560,7 @@ let body = ctx.body;
if (!body || body.pipe) return;
if (Buffer.isBuffer(body)) body = body.toString();
ctx.body = minify(body);
ctx.body = minify(body);
});
```
@ -693,9 +693,9 @@ Generates the following response payload:
```json
{
"statusCode": 400,
"error": "Bad Request",
"message": "invalid query"
"statusCode": 400,
"error": "Bad Request",
"message": "invalid query"
}
```
@ -723,9 +723,9 @@ Generates the following response:
```json
"payload": {
"statusCode": 401,
"error": "Unauthorized",
"message": "invalid password"
"statusCode": 401,
"error": "Unauthorized",
"message": "invalid password"
},
"headers" {}
```
@ -738,12 +738,12 @@ Generates the following response:
```json
"payload": {
"statusCode": 401,
"error": "Unauthorized",
"message": "invalid password",
"attributes": {
"error": "invalid password"
}
"statusCode": 401,
"error": "Unauthorized",
"message": "invalid password",
"attributes": {
"error": "invalid password"
}
},
"headers" {
"WWW-Authenticate": "sample error=\"invalid password\""
@ -758,9 +758,9 @@ Generates the following response:
```json
"payload": {
"statusCode": 401,
"error": "Unauthorized",
"attributes": "VGhpcyBpcyBhIHRlc3QgdG9rZW4="
"statusCode": 401,
"error": "Unauthorized",
"attributes": "VGhpcyBpcyBhIHRlc3QgdG9rZW4="
},
"headers" {
"WWW-Authenticate": "Negotiate VGhpcyBpcyBhIHRlc3QgdG9rZW4="
@ -775,15 +775,15 @@ Generates the following response:
```json
"payload": {
"statusCode": 401,
"error": "Unauthorized",
"message": "invalid password",
"attributes": {
"error": "invalid password",
"ttl": 0,
"cache": "",
"foo": "bar"
}
"statusCode": 401,
"error": "Unauthorized",
"message": "invalid password",
"attributes": {
"error": "invalid password",
"ttl": 0,
"cache": "",
"foo": "bar"
}
},
"headers" {
"WWW-Authenticate": "sample ttl=\"0\", cache=\"\", foo=\"bar\", error=\"invalid password\""
@ -804,9 +804,9 @@ Generates the following response payload:
```json
{
"statusCode": 402,
"error": "Payment Required",
"message": "bandwidth used"
"statusCode": 402,
"error": "Payment Required",
"message": "bandwidth used"
}
```
@ -824,9 +824,9 @@ Generates the following response payload:
```json
{
"statusCode": 403,
"error": "Forbidden",
"message": "try again some time"
"statusCode": 403,
"error": "Forbidden",
"message": "try again some time"
}
```
@ -844,9 +844,9 @@ Generates the following response payload:
```json
{
"statusCode": 404,
"error": "Not Found",
"message": "missing"
"statusCode": 404,
"error": "Not Found",
"message": "missing"
}
```
@ -865,9 +865,9 @@ Generates the following response payload:
```json
{
"statusCode": 405,
"error": "Method Not Allowed",
"message": "that method is not allowed"
"statusCode": 405,
"error": "Method Not Allowed",
"message": "that method is not allowed"
}
```
@ -885,9 +885,9 @@ Generates the following response payload:
```json
{
"statusCode": 406,
"error": "Not Acceptable",
"message": "unacceptable"
"statusCode": 406,
"error": "Not Acceptable",
"message": "unacceptable"
}
```
@ -905,9 +905,9 @@ Generates the following response payload:
```json
{
"statusCode": 407,
"error": "Proxy Authentication Required",
"message": "auth missing"
"statusCode": 407,
"error": "Proxy Authentication Required",
"message": "auth missing"
}
```
@ -925,9 +925,9 @@ Generates the following response payload:
```json
{
"statusCode": 408,
"error": "Request Time-out",
"message": "timed out"
"statusCode": 408,
"error": "Request Time-out",
"message": "timed out"
}
```
@ -945,9 +945,9 @@ Generates the following response payload:
```json
{
"statusCode": 409,
"error": "Conflict",
"message": "there was a conflict"
"statusCode": 409,
"error": "Conflict",
"message": "there was a conflict"
}
```
@ -965,9 +965,9 @@ Generates the following response payload:
```json
{
"statusCode": 410,
"error": "Gone",
"message": "it is gone"
"statusCode": 410,
"error": "Gone",
"message": "it is gone"
}
```
@ -985,9 +985,9 @@ Generates the following response payload:
```json
{
"statusCode": 411,
"error": "Length Required",
"message": "length needed"
"statusCode": 411,
"error": "Length Required",
"message": "length needed"
}
```
@ -1005,8 +1005,8 @@ Generates the following response payload:
```json
{
"statusCode": 412,
"error": "Precondition Failed"
"statusCode": 412,
"error": "Precondition Failed"
}
```
@ -1024,9 +1024,9 @@ Generates the following response payload:
```json
{
"statusCode": 413,
"error": "Request Entity Too Large",
"message": "too big"
"statusCode": 413,
"error": "Request Entity Too Large",
"message": "too big"
}
```
@ -1044,9 +1044,9 @@ Generates the following response payload:
```json
{
"statusCode": 414,
"error": "Request-URI Too Large",
"message": "uri is too long"
"statusCode": 414,
"error": "Request-URI Too Large",
"message": "uri is too long"
}
```
@ -1064,9 +1064,9 @@ Generates the following response payload:
```json
{
"statusCode": 415,
"error": "Unsupported Media Type",
"message": "that media is not supported"
"statusCode": 415,
"error": "Unsupported Media Type",
"message": "that media is not supported"
}
```
@ -1084,8 +1084,8 @@ Generates the following response payload:
```json
{
"statusCode": 416,
"error": "Requested Range Not Satisfiable"
"statusCode": 416,
"error": "Requested Range Not Satisfiable"
}
```
@ -1103,9 +1103,9 @@ Generates the following response payload:
```json
{
"statusCode": 417,
"error": "Expectation Failed",
"message": "expected this to work"
"statusCode": 417,
"error": "Expectation Failed",
"message": "expected this to work"
}
```
@ -1123,9 +1123,9 @@ Generates the following response payload:
```json
{
"statusCode": 418,
"error": "I'm a Teapot",
"message": "Sorry, no coffee..."
"statusCode": 418,
"error": "I'm a Teapot",
"message": "Sorry, no coffee..."
}
```
@ -1143,9 +1143,9 @@ Generates the following response payload:
```json
{
"statusCode": 422,
"error": "Unprocessable Entity",
"message": "your data is bad and you should feel bad"
"statusCode": 422,
"error": "Unprocessable Entity",
"message": "your data is bad and you should feel bad"
}
```
@ -1163,9 +1163,9 @@ Generates the following response payload:
```json
{
"statusCode": 423,
"error": "Locked",
"message": "this resource has been locked"
"statusCode": 423,
"error": "Locked",
"message": "this resource has been locked"
}
```
@ -1183,9 +1183,9 @@ Generates the following response payload:
```json
{
"statusCode": 428,
"error": "Precondition Required",
"message": "you must supply an If-Match header"
"statusCode": 428,
"error": "Precondition Required",
"message": "you must supply an If-Match header"
}
```
@ -1203,9 +1203,9 @@ Generates the following response payload:
```json
{
"statusCode": 429,
"error": "Too Many Requests",
"message": "you have exceeded your request limit"
"statusCode": 429,
"error": "Too Many Requests",
"message": "you have exceeded your request limit"
}
```
@ -1223,9 +1223,9 @@ Generates the following response payload:
```json
{
"statusCode": 451,
"error": "Unavailable For Legal Reasons",
"message": "you are not permitted to view this resource for legal reasons"
"statusCode": 451,
"error": "Unavailable For Legal Reasons",
"message": "you are not permitted to view this resource for legal reasons"
}
```
@ -1247,9 +1247,9 @@ Generates the following response payload:
```json
{
"statusCode": 500,
"error": "Internal Server Error",
"message": "An internal server error occurred"
"statusCode": 500,
"error": "Internal Server Error",
"message": "An internal server error occurred"
}
```
@ -1267,9 +1267,9 @@ Generates the following response payload:
```json
{
"statusCode": 501,
"error": "Not Implemented",
"message": "method not implemented"
"statusCode": 501,
"error": "Not Implemented",
"message": "method not implemented"
}
```
@ -1287,9 +1287,9 @@ Generates the following response payload:
```json
{
"statusCode": 502,
"error": "Bad Gateway",
"message": "that is a bad gateway"
"statusCode": 502,
"error": "Bad Gateway",
"message": "that is a bad gateway"
}
```
@ -1307,9 +1307,9 @@ Generates the following response payload:
```json
{
"statusCode": 503,
"error": "Service Unavailable",
"message": "unavailable"
"statusCode": 503,
"error": "Service Unavailable",
"message": "unavailable"
}
```
@ -1327,7 +1327,7 @@ Generates the following response payload:
```json
{
"statusCode": 504,
"error": "Gateway Time-out"
"statusCode": 504,
"error": "Gateway Time-out"
}
```

View File

@ -1,6 +1,6 @@
{
"private": true,
"version": "3.0.0-alpha.8",
"version": "3.0.0-alpha.8.3",
"devDependencies": {
"assert": "~1.3.0",
"babel-eslint": "^6.1.2",

View File

@ -8,3 +8,4 @@ package-lock.json
.DS_Store
npm-debug.log
.idea
manifest.json

View File

@ -1,7 +1,6 @@
# Don't check auto-generated stuff into git
coverage
node_modules
build
plugins.json
stats.json
package-lock.json

View File

@ -5,12 +5,25 @@
.icoContainer {
width: 70px;
height: 36px;
position: relative;
margin: auto 0;
line-height: 36px;
text-align: center;
border: 1px solid rgba(28,93,231,0.1);
border-radius: 3px;
font-size: 20px;
> img {
max-width: 100%;
max-height: 100%;
width: auto;
height: auto;
position: absolute;
top: 0;
bottom: 0;
left: 0;
right: 0;
margin: auto;
}
}
.pluginContent {

File diff suppressed because one or more lines are too long

View File

@ -1,6 +1,6 @@
{
"name": "strapi-admin",
"version": "3.0.0-alpha.8",
"version": "3.0.0-alpha.8.3",
"description": "Strapi Admin",
"repository": {
"type": "git",
@ -16,10 +16,9 @@
"build:clean": "node ./node_modules/strapi-helper-plugin/node_modules/.bin/rimraf admin/build",
"start": "node ./node_modules/strapi-helper-plugin/node_modules/.bin/cross-env NODE_ENV=development PORT=4000 IS_ADMIN=true node ./node_modules/strapi-helper-plugin/lib/server",
"generate": "node ./node_modules/strapi-helper-plugin/node_modules/.bin/plop --plopfile ./node_modules/strapi-helper-plugin/lib/internals/generators/index.js",
"lint": "node ./node_modules/strapi-helper-plugin/node_modules/.bin/eslint --ignore-path ./admin/.gitignore --config ./node_modules/strapi-helper-plugin/lib/internals/eslint/.eslintrc.json admin",
"pretest": "npm run lint",
"lint": "node ./node_modules/strapi-helper-plugin/node_modules/.bin/eslint --ignore-path ./admin/.gitignore --ignore-pattern build --config ./node_modules/strapi-helper-plugin/lib/internals/eslint/.eslintrc.json admin",
"prettier": "node ./node_modules/strapi-helper-plugin/node_modules/.bin/prettier --single-quote --trailing-comma es5 --write \"{admin,__{tests,mocks}__}/**/*.js\"",
"test": "echo Tests are not implemented.",
"test": "npm run lint",
"prepublishOnly": "npm run build",
"setup": "node ./scripts/setup.js"
},
@ -28,8 +27,8 @@
},
"devDependencies": {
"sanitize.css": "^4.1.0",
"strapi-helper-plugin": "3.0.0-alpha.8",
"strapi-utils": "3.0.0-alpha.8"
"strapi-helper-plugin": "3.0.0-alpha.8.3",
"strapi-utils": "3.0.0-alpha.8.3"
},
"author": {
"name": "Strapi",

View File

@ -61,12 +61,20 @@ if (process.env.npm_config_plugins === 'true') {
shell.exec(`cd ${path.resolve(plugins, plugin)} && npm install`, {
silent
});
shell.exec(`cd ${path.resolve(plugins, plugin, 'node_modules', 'strapi-helper-plugin')} && npm install`, {
silent
});
if (isDevelopmentMode) {
shell.exec(`cd ${path.resolve(plugins, plugin)} && npm link strapi-helper-plugin`, {
silent
});
} else {
shell.exec(`cd ${path.resolve(plugins, plugin, 'node_modules', 'strapi-helper-plugin')} && npm install`, {
silent
});
}
shell.echo('🏗 Building...');
const build = shell.exec(`cd ${path.resolve(plugins, plugin)} && APP_PATH=${appPath} npm run build`, {
const build = shell.exec(`cd ${path.resolve(plugins, plugin)} && APP_PATH=${appPath} npm run build`, {
silent
});

View File

@ -1,6 +1,6 @@
{
"name": "strapi-bookshelf",
"version": "3.0.0-alpha.8",
"version": "3.0.0-alpha.8.3",
"description": "Bookshelf hook for the Strapi framework",
"homepage": "http://strapi.io",
"keywords": [
@ -19,8 +19,8 @@
"bookshelf": "^0.10.3",
"lodash": "^4.17.4",
"pluralize": "^6.0.0",
"strapi-knex": "3.0.0-alpha.8",
"strapi-utils": "3.0.0-alpha.8"
"strapi-knex": "3.0.0-alpha.8.3",
"strapi-utils": "3.0.0-alpha.8.3"
},
"strapi": {
"isHook": true,
@ -55,4 +55,4 @@
"npm": ">= 5.3.0"
},
"license": "MIT"
}
}

View File

@ -1,6 +1,6 @@
{
"name": "strapi-ejs",
"version": "3.0.0-alpha.8",
"version": "3.0.0-alpha.8.3",
"description": "EJS hook for the Strapi framework",
"homepage": "http://strapi.io",
"keywords": [
@ -46,4 +46,4 @@
"npm": ">= 5.3.0"
},
"license": "MIT"
}
}

View File

@ -1,6 +1,6 @@
{
"name": "strapi-generate-admin",
"version": "3.0.0-alpha.8",
"version": "3.0.0-alpha.8.3",
"description": "Generate the default admin panel for a Strapi application.",
"homepage": "http://strapi.io",
"keywords": [
@ -15,7 +15,7 @@
"dependencies": {
"fs-extra": "^4.0.1",
"lodash": "^4.17.4",
"strapi-admin": "3.0.0-alpha.8"
"strapi-admin": "3.0.0-alpha.8.3"
},
"author": {
"email": "hi@strapi.io",

View File

@ -1,6 +1,6 @@
{
"name": "strapi-generate-api",
"version": "3.0.0-alpha.8",
"version": "3.0.0-alpha.8.3",
"description": "Generate an API for a Strapi application.",
"homepage": "http://strapi.io",
"keywords": [
@ -43,4 +43,4 @@
"npm": ">= 5.3.0"
},
"license": "MIT"
}
}

View File

@ -1,6 +1,6 @@
{
"name": "strapi-generate-controller",
"version": "3.0.0-alpha.8",
"version": "3.0.0-alpha.8.3",
"description": "Generate a controller for a Strapi API.",
"homepage": "http://strapi.io",
"keywords": [
@ -43,4 +43,4 @@
"npm": ">= 5.3.0"
},
"license": "MIT"
}
}

View File

@ -1,6 +1,6 @@
{
"name": "strapi-generate-model",
"version": "3.0.0-alpha.8",
"version": "3.0.0-alpha.8.3",
"description": "Generate a model for a Strapi API.",
"homepage": "http://strapi.io",
"keywords": [
@ -43,4 +43,4 @@
"npm": ">= 5.3.0"
},
"license": "MIT"
}
}

View File

@ -1,6 +1,6 @@
{
"session": {
"enabled": false,
"enabled": true,
"client": "cookie",
"key": "strapi.sid",
"prefix": "strapi:sess:",

View File

@ -13,6 +13,7 @@ const execSync = require('child_process').execSync;
const _ = require('lodash');
const fs = require('fs-extra');
const inquirer = require('inquirer');
const shell = require('shelljs');
// Logger.
const logger = require('strapi-utils').logger;
@ -186,14 +187,14 @@ module.exports = (scope, cb) => {
});
}),
new Promise(resolve => {
let cmd = `npm install --prefix ${scope.rootPath} ${scope.client.connector}@alpha`;
let cmd = `npm install --prefix "${scope.rootPath}" ${scope.client.connector}@alpha`;
if (scope.client.module) {
cmd += ` ${scope.client.module}`;
}
exec(cmd, () => {
if (scope.client.module) {
const lock = require(`${scope.rootPath}/node_modules/${scope.client.module}/package.json`);
const lock = require(path.join(`${scope.rootPath}`,`/node_modules/`,`${scope.client.module}/package.json`));
scope.client.version = lock.version;
}
@ -205,12 +206,10 @@ module.exports = (scope, cb) => {
Promise.all(asyncFn)
.then(() => {
try {
require(path.resolve(`${scope.rootPath}/node_modules/${scope.client.connector}/lib/utils/connectivity.js`))(scope, cb.success, connectionValidation);
require(path.join(`${scope.rootPath}`,`/node_modules/`,`${scope.client.connector}/lib/utils/connectivity.js`))(scope, cb.success, connectionValidation);
} catch(err) {
execSync(`rm -r ${scope.rootPath}`);
shell.rm('-r', scope.rootPath);
logger.info('Copying the dashboard...');
cb.success();
}
});

View File

@ -1,6 +1,6 @@
{
"name": "strapi-generate-new",
"version": "3.0.0-alpha.8",
"version": "3.0.0-alpha.8.3",
"description": "Generate a new Strapi application.",
"homepage": "http://strapi.io",
"keywords": [
@ -18,7 +18,7 @@
"get-installed-path": "^3.0.1",
"inquirer": "^4.0.2",
"lodash": "^4.17.4",
"strapi-utils": "3.0.0-alpha.8",
"strapi-utils": "3.0.0-alpha.8.3",
"uuid": "^3.1.0"
},
"scripts": {
@ -48,4 +48,4 @@
"npm": ">= 5.3.0"
},
"license": "MIT"
}
}

View File

@ -35,10 +35,9 @@ module.exports = scope => {
'build:clean': 'node ./node_modules/strapi-helper-plugin/node_modules/.bin/rimraf admin/build',
'start': 'node ./node_modules/strapi-helper-plugin/node_modules/.bin/cross-env NODE_ENV=development node ./node_modules/strapi-helper-plugin/lib/server',
'generate': 'node ./node_modules/plop/plop.js --plopfile node_modules/strapi-helper-plugin/lib/internals/generators/index.js',
'lint': 'node ./node_modules/strapi-helper-plugin/node_modules/.bin/eslint --ignore-path .gitignore --config ./node_modules/strapi-helper-plugin/lib/internals/eslint/.eslintrc.json admin',
'pretest': 'npm run lint',
'lint': 'node ./node_modules/strapi-helper-plugin/node_modules/.bin/eslint --ignore-path .gitignore --ignore-pattern \'/admin/build/\' --config ./node_modules/strapi-helper-plugin/lib/internals/eslint/.eslintrc.json admin',
'prettier': 'node ./node_modules/strapi-helper-plugin/node_modules/.bin/prettier --single-quote --trailing-comma es5 --write "{admin,__{tests,mocks}__}/**/*.js"',
'test': 'echo Tests are not implemented.',
'test': 'npm run lint',
'prepublishOnly': 'npm run build'
},
'dependencies': {},

View File

@ -1,6 +1,6 @@
{
"name": "strapi-generate-plugin",
"version": "3.0.0-alpha.8",
"version": "3.0.0-alpha.8.3",
"description": "Generate an plugin for a Strapi application.",
"homepage": "http://strapi.io",
"keywords": [
@ -44,4 +44,4 @@
"npm": ">= 5.3.0"
},
"license": "MIT"
}
}

View File

@ -1,6 +1,5 @@
# Don't check auto-generated stuff into git
coverage
build
node_modules
stats.json
package-lock.json

View File

@ -1,6 +1,6 @@
{
"name": "strapi-generate-policy",
"version": "3.0.0-alpha.8",
"version": "3.0.0-alpha.8.3",
"description": "Generate a policy for a Strapi API.",
"homepage": "http://strapi.io",
"keywords": [
@ -43,4 +43,4 @@
"npm": ">= 5.3.0"
},
"license": "MIT"
}
}

View File

@ -1,6 +1,6 @@
{
"name": "strapi-generate-service",
"version": "3.0.0-alpha.8",
"version": "3.0.0-alpha.8.3",
"description": "Generate a service for a Strapi API.",
"homepage": "http://strapi.io",
"keywords": [
@ -43,4 +43,4 @@
"npm": ">= 5.3.0"
},
"license": "MIT"
}
}

View File

@ -1,6 +1,6 @@
{
"name": "strapi-generate",
"version": "3.0.0-alpha.8",
"version": "3.0.0-alpha.8.3",
"description": "Master of ceremonies for the Strapi generators.",
"homepage": "http://strapi.io",
"keywords": [
@ -17,7 +17,7 @@
"fs-extra": "^4.0.0",
"lodash": "^4.17.4",
"reportback": "^2.0.1",
"strapi-utils": "3.0.0-alpha.8"
"strapi-utils": "3.0.0-alpha.8.3"
},
"author": {
"name": "Strapi team",

View File

@ -20,11 +20,11 @@ const appPath = (() => {
})();
const isSetup = path.resolve(process.env.PWD, '..', '..') === path.resolve(process.env.INIT_CWD);
const adminPath = (() => {
if (isSetup) {
return isAdmin ? path.resolve(appPath, 'strapi-admin') : path.resolve(process.env.PWD);
if (isAdmin && isSetup) {
return path.resolve(appPath, 'strapi-admin');
}
return path.resolve(appPath, 'admin');
return path.resolve(process.env.PWD);
})();
if (!isSetup) {

View File

@ -15,6 +15,7 @@ const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPl
const LodashModuleReplacementPlugin = require('lodash-webpack-plugin');
const isAdmin = process.env.IS_ADMIN === 'true';
const isSetup = path.resolve(process.env.PWD, '..', '..') === path.resolve(process.env.INIT_CWD);
const appPath = (() => {
if (process.env.APP_PATH) {
return process.env.APP_PATH;
@ -22,7 +23,13 @@ const appPath = (() => {
return isAdmin ? path.resolve(process.env.PWD, '..') : path.resolve(process.env.PWD, '..', '..');
})();
const isSetup = path.resolve(process.env.PWD, '..', '..') === path.resolve(process.env.INIT_CWD);
const rootAdminpath = (() => {
if (isSetup) {
return isAdmin ? path.resolve(appPath, 'strapi-admin') : path.resolve(appPath, 'packages', 'strapi-admin');
}
return path.resolve(appPath, 'admin');
})();
// Load plugins into the same build in development mode.
const plugins = {
@ -117,30 +124,14 @@ module.exports = require('./webpack.base.babel')({
],
alias: {
moment: 'moment/moment.js',
'babel-polyfill': isSetup ?
path.resolve(__dirname, '..', '..', '..', 'node_modules', 'babel-polyfill'):
path.resolve(appPath, 'admin', 'node_modules', 'strapi-helper-plugin', 'node_modules', 'babel-polyfill'),
'lodash': isSetup ?
path.resolve(__dirname, '..', '..', '..', 'node_modules', 'lodash'):
path.resolve(appPath, 'admin', 'node_modules', 'strapi-helper-plugin', 'node_modules', 'lodash'),
'immutable': isSetup ?
path.resolve(__dirname, '..', '..', '..', 'node_modules', 'immutable'):
path.resolve(appPath, 'admin', 'node_modules', 'strapi-helper-plugin', 'node_modules', 'immutable'),
'react-intl': isSetup ?
path.resolve(__dirname, '..', '..', '..', 'node_modules', 'react-intl'):
path.resolve(appPath, 'admin', 'node_modules', 'strapi-helper-plugin', 'node_modules', 'react-intl'),
'react': isSetup ?
path.resolve(__dirname, '..', '..', '..', 'node_modules', 'react'):
path.resolve(appPath, 'admin', 'node_modules', 'strapi-helper-plugin', 'node_modules', 'react'),
'react-dom': isSetup ?
path.resolve(__dirname, '..', '..', '..', 'node_modules', 'react-dom'):
path.resolve(appPath, 'admin', 'node_modules', 'strapi-helper-plugin', 'node_modules', 'react-dom'),
'react-transition-group': isSetup ?
path.resolve(__dirname, '..', '..', '..', 'node_modules', 'react-transition-group'):
path.resolve(appPath, 'admin', 'node_modules', 'strapi-helper-plugin', 'node_modules', 'react-transition-group'),
'reactstrap': isSetup ?
path.resolve(__dirname, '..', '..', '..', 'node_modules', 'reactstrap'):
path.resolve(appPath, 'admin', 'node_modules', 'strapi-helper-plugin', 'node_modules', 'reactstrap')
'babel-polyfill': path.resolve(rootAdminpath, 'node_modules', 'strapi-helper-plugin', 'node_modules', 'babel-polyfill'),
'lodash': path.resolve(rootAdminpath, 'node_modules', 'strapi-helper-plugin', 'node_modules', 'lodash'),
'immutable': path.resolve(rootAdminpath, 'node_modules', 'strapi-helper-plugin', 'node_modules', 'immutable'),
'react-intl': path.resolve(rootAdminpath, 'node_modules', 'strapi-helper-plugin', 'node_modules', 'react-intl'),
'react': path.resolve(rootAdminpath, 'node_modules', 'strapi-helper-plugin', 'node_modules', 'react'),
'react-dom': path.resolve(rootAdminpath, 'node_modules', 'strapi-helper-plugin', 'node_modules', 'react-dom'),
'react-transition-group': path.resolve(rootAdminpath, 'node_modules', 'strapi-helper-plugin', 'node_modules', 'react-transition-group'),
'reactstrap': path.resolve(rootAdminpath, 'node_modules', 'strapi-helper-plugin', 'node_modules', 'reactstrap')
},
// Emit a source map for easier debugging

View File

@ -21,6 +21,14 @@ const appPath = (() => {
})();
const isSetup = path.resolve(process.env.PWD, '..', '..') === path.resolve(process.env.INIT_CWD);
const rootAdminpath = (() => {
if (isSetup) {
return isAdmin ? path.resolve(appPath, 'strapi-admin') : path.resolve(appPath, 'packages', 'strapi-admin');
}
return path.resolve(appPath, 'admin');
})();
module.exports = {
context: appPath,
entry: {
@ -29,9 +37,7 @@ module.exports = {
devtool: 'cheap-module-source-map',
output: {
filename: '[name].dll.js',
path: isSetup ?
path.join(__dirname, 'dist'):
path.join(appPath, 'admin', 'node_modules', 'strapi-helper-plugin', 'lib', 'internals', 'webpack', 'dist'),
path: path.resolve(rootAdminpath, 'node_modules', 'strapi-helper-plugin', 'lib', 'internals', 'webpack', 'dist'),
// The name of the global variable which the library's
// require() function will be assigned to
@ -40,9 +46,7 @@ module.exports = {
plugins: [
new webpack.DllPlugin({
name: '[name]_lib',
path: isSetup ?
path.join(__dirname, 'manifest.json'):
path.join(appPath, 'admin', 'node_modules', 'strapi-helper-plugin', 'lib', 'internals', 'webpack', 'manifest.json'),
path: path.resolve(rootAdminpath, 'admin', 'src', 'config', 'manifest.json'),
})
],
resolve: {
@ -54,30 +58,14 @@ module.exports = {
],
alias: {
moment: 'moment/moment.js',
'babel-polyfill': isSetup ?
path.resolve(__dirname, '..', '..', '..', 'node_modules', 'babel-polyfill'):
path.resolve(appPath, 'admin', 'node_modules', 'strapi-helper-plugin', 'node_modules', 'babel-polyfill'),
'lodash': isSetup ?
path.resolve(__dirname, '..', '..', '..', 'node_modules', 'lodash'):
path.resolve(appPath, 'admin', 'node_modules', 'strapi-helper-plugin', 'node_modules', 'lodash'),
'immutable': isSetup ?
path.resolve(__dirname, '..', '..', '..', 'node_modules', 'immutable'):
path.resolve(appPath, 'admin', 'node_modules', 'strapi-helper-plugin', 'node_modules', 'immutable'),
'react-intl': isSetup ?
path.resolve(__dirname, '..', '..', '..', 'node_modules', 'react-intl'):
path.resolve(appPath, 'admin', 'node_modules', 'strapi-helper-plugin', 'node_modules', 'react-intl'),
'react': isSetup ?
path.resolve(__dirname, '..', '..', '..', 'node_modules', 'react'):
path.resolve(appPath, 'admin', 'node_modules', 'strapi-helper-plugin', 'node_modules', 'react'),
'react-dom': isSetup ?
path.resolve(__dirname, '..', '..', '..', 'node_modules', 'react-dom'):
path.resolve(appPath, 'admin', 'node_modules', 'strapi-helper-plugin', 'node_modules', 'react-dom'),
'react-transition-group': isSetup ?
path.resolve(__dirname, '..', '..', '..', 'node_modules', 'react-transition-group'):
path.resolve(appPath, 'admin', 'node_modules', 'strapi-helper-plugin', 'node_modules', 'react-transition-group'),
'reactstrap': isSetup ?
path.resolve(__dirname, '..', '..', '..', 'node_modules', 'reactstrap'):
path.resolve(appPath, 'admin', 'node_modules', 'strapi-helper-plugin', 'node_modules', 'reactstrap')
'babel-polyfill': path.resolve(rootAdminpath, 'node_modules', 'strapi-helper-plugin', 'node_modules', 'babel-polyfill'),
'lodash': path.resolve(rootAdminpath, 'node_modules', 'strapi-helper-plugin', 'node_modules', 'lodash'),
'immutable': path.resolve(rootAdminpath, 'node_modules', 'strapi-helper-plugin', 'node_modules', 'immutable'),
'react-intl': path.resolve(rootAdminpath, 'node_modules', 'strapi-helper-plugin', 'node_modules', 'react-intl'),
'react': path.resolve(rootAdminpath, 'node_modules', 'strapi-helper-plugin', 'node_modules', 'react'),
'react-dom': path.resolve(rootAdminpath, 'node_modules', 'strapi-helper-plugin', 'node_modules', 'react-dom'),
'react-transition-group': path.resolve(rootAdminpath, 'node_modules', 'strapi-helper-plugin', 'node_modules', 'react-transition-group'),
'reactstrap': path.resolve(rootAdminpath, 'node_modules', 'strapi-helper-plugin', 'node_modules', 'reactstrap')
},
symlinks: false,
extensions: [

View File

@ -35,12 +35,16 @@ const adminPath = (() => {
return path.resolve(appPath, 'admin');
})();
const rootAdminpath = (() => {
if (isSetup) {
return isAdmin ? path.resolve(appPath, 'strapi-admin') : path.resolve(appPath, 'packages', 'strapi-admin');
}
return path.resolve(appPath, 'admin');
})();
const plugins = [
new webpack.DllReferencePlugin({
manifest: require(isSetup ?
path.join(__dirname, 'manifest.json'):
path.resolve(appPath, 'admin', 'node_modules', 'strapi-helper-plugin', 'lib', 'internals', 'webpack', 'manifest.json')
),
manifest: require(path.resolve(rootAdminpath, 'admin', 'src', 'config', 'manifest.json'))
}),
// Minify and optimize the JavaScript
new webpack.optimize.UglifyJsPlugin({
@ -79,13 +83,6 @@ if (isAdmin && !isSetup) {
} catch (e) {
throw new Error(`Impossible to access to ${serverConfig}`);
}
// Note: Travis failed with it.
plugins.push(new CopyWebpackPlugin([{
from: 'config/plugins.json',
context: path.resolve(adminPath, 'admin', 'src'),
to: 'config/plugins.json'
}]));
}
// Build the `index.html file`
@ -112,6 +109,11 @@ if (isAdmin) {
plugins.push(new AddAssetHtmlPlugin({
filepath: path.resolve(__dirname, 'dist/*.dll.js')
}));
plugins.push(new CopyWebpackPlugin([{
from: 'config/plugins.json',
context: path.resolve(adminPath, 'admin', 'src'),
to: 'config/plugins.json'
}]));
}
const main = (() => {
@ -167,30 +169,14 @@ module.exports = base({
alias: {
moment: 'moment/moment.js',
'babel-polyfill': isSetup ?
path.resolve(__dirname, '..', '..', '..', 'node_modules', 'babel-polyfill'):
path.resolve(appPath, 'admin', 'node_modules', 'strapi-helper-plugin', 'node_modules', 'babel-polyfill'),
'lodash': isSetup ?
path.resolve(__dirname, '..', '..', '..', 'node_modules', 'lodash'):
path.resolve(appPath, 'admin', 'node_modules', 'strapi-helper-plugin', 'node_modules', 'lodash'),
'immutable': isSetup ?
path.resolve(__dirname, '..', '..', '..', 'node_modules', 'immutable'):
path.resolve(appPath, 'admin', 'node_modules', 'strapi-helper-plugin', 'node_modules', 'immutable'),
'react-intl': isSetup ?
path.resolve(__dirname, '..', '..', '..', 'node_modules', 'react-intl'):
path.resolve(appPath, 'admin', 'node_modules', 'strapi-helper-plugin', 'node_modules', 'react-intl'),
'react': isSetup ?
path.resolve(__dirname, '..', '..', '..', 'node_modules', 'react'):
path.resolve(appPath, 'admin', 'node_modules', 'strapi-helper-plugin', 'node_modules', 'react'),
'react-dom': isSetup ?
path.resolve(__dirname, '..', '..', '..', 'node_modules', 'react-dom'):
path.resolve(appPath, 'admin', 'node_modules', 'strapi-helper-plugin', 'node_modules', 'react-dom'),
'react-transition-group': isSetup ?
path.resolve(__dirname, '..', '..', '..', 'node_modules', 'react-transition-group'):
path.resolve(appPath, 'admin', 'node_modules', 'strapi-helper-plugin', 'node_modules', 'react-transition-group'),
'reactstrap': isSetup ?
path.resolve(__dirname, '..', '..', '..', 'node_modules', 'reactstrap'):
path.resolve(appPath, 'admin', 'node_modules', 'strapi-helper-plugin', 'node_modules', 'reactstrap')
'babel-polyfill': path.resolve(rootAdminpath, 'node_modules', 'strapi-helper-plugin', 'node_modules', 'babel-polyfill'),
'lodash': path.resolve(rootAdminpath, 'node_modules', 'strapi-helper-plugin', 'node_modules', 'lodash'),
'immutable': path.resolve(rootAdminpath, 'node_modules', 'strapi-helper-plugin', 'node_modules', 'immutable'),
'react-intl': path.resolve(rootAdminpath, 'node_modules', 'strapi-helper-plugin', 'node_modules', 'react-intl'),
'react': path.resolve(rootAdminpath, 'node_modules', 'strapi-helper-plugin', 'node_modules', 'react'),
'react-dom': path.resolve(rootAdminpath, 'node_modules', 'strapi-helper-plugin', 'node_modules', 'react-dom'),
'react-transition-group': path.resolve(rootAdminpath, 'node_modules', 'strapi-helper-plugin', 'node_modules', 'react-transition-group'),
'reactstrap': path.resolve(rootAdminpath, 'node_modules', 'strapi-helper-plugin', 'node_modules', 'reactstrap')
},
devtool: 'cheap-module-source-map',

View File

@ -24,6 +24,7 @@ module.exports = {
// Some libraries don't like being run through babel.
// If they gripe, put them here.
noParse: [
/build/,
/node_modules(\\|\/)sinon/,
/node_modules(\\|\/)acorn/,
],

View File

@ -1,6 +1,6 @@
{
"name": "strapi-helper-plugin",
"version": "3.0.0-alpha.8",
"version": "3.0.0-alpha.8.3",
"description": "Helper for Strapi plugins development",
"engines": {
"node": ">= 8.0.0",
@ -21,9 +21,8 @@
"license": "MIT",
"scripts": {
"lint": "cross-env IS_HELPER=true ./node_modules/eslint/bin/eslint.js --ignore-path .gitignore --config ./lib/internals/eslint/eslint-config.js .",
"pretest": "npm run lint",
"prettier": "prettier --single-quote --trailing-comma es5 --write \"{lib,__{tests,mocks}__}/**/*.js\"",
"test": "echo Tests are not implemented."
"test": "npm run lint"
},
"pre-commit": [
"lint:admin"

View File

@ -1,6 +1,6 @@
{
"name": "strapi-knex",
"version": "3.0.0-alpha.8",
"version": "3.0.0-alpha.8.3",
"description": "Knex hook for the Strapi framework",
"homepage": "http://strapi.io",
"keywords": [

View File

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

View File

@ -1,6 +1,6 @@
{
"name": "strapi-mongoose",
"version": "3.0.0-alpha.8",
"version": "3.0.0-alpha.8.3",
"description": "Mongoose hook for the Strapi framework",
"homepage": "http://strapi.io",
"keywords": [
@ -19,7 +19,7 @@
"mongoose": "^5.0.0-rc1",
"mongoose-float": "^1.0.2",
"pluralize": "^6.0.0",
"strapi-utils": "3.0.0-alpha.8"
"strapi-utils": "3.0.0-alpha.8.3"
},
"strapi": {
"isHook": true

View File

@ -1,6 +1,5 @@
# Don't check auto-generated stuff into git
coverage
build
node_modules
stats.json
package-lock.json

View File

@ -1,28 +1,7 @@
{
"name": "strapi-plugin-content-manager",
"version": "3.0.0-alpha.8",
"version": "3.0.0-alpha.8.3",
"description": "A powerful UI to easily manage your data.",
"engines": {
"node": ">= 8.0.0",
"npm": ">= 5.3.0"
},
"author": {
"email": "hi@strapi.io",
"name": "Strapi team",
"url": "http://strapi.io"
},
"maintainers": [
{
"name": "Strapi team",
"email": "hi@strapi.io",
"url": "http://strapi.io"
}
],
"repository": {
"type": "git",
"url": "git://github.com/strapi/strapi.git"
},
"license": "MIT",
"strapi": {
"name": "Content Manager",
"icon": "plug",
@ -38,14 +17,34 @@
"build:clean": "node ./node_modules/strapi-helper-plugin/node_modules/.bin/rimraf admin/build",
"start": "node ./node_modules/strapi-helper-plugin/node_modules/.bin/cross-env NODE_ENV=development PLUGIN=true node ./node_modules/strapi-helper-plugin/lib/server",
"generate": "node ./node_modules/plop/plop.js --plopfile ./node_modules/strapi-helper-plugin/lib/internals/generators/index.js",
"lint": "node ./node_modules/strapi-helper-plugin/node_modules/.bin/eslint --ignore-path .gitignore --config ./node_modules/strapi-helper-plugin/lib/internals/eslint/.eslintrc.json admin",
"pretest": "npm run lint",
"lint": "node ./node_modules/strapi-helper-plugin/node_modules/.bin/eslint --ignore-path .gitignore --ignore-pattern '/admin/build/' --config ./node_modules/strapi-helper-plugin/lib/internals/eslint/.eslintrc.json admin",
"prettier": "node ./node_modules/strapi-helper-plugin/node_modules/.bin/prettier --single-quote --trailing-comma es5 --write \"{admin,__{tests,mocks}__}/**/*.js\"",
"test": "echo Tests are not implemented.",
"test": "npm run lint",
"prepublishOnly": "npm run build"
},
"devDependencies": {
"react-select": "^1.0.0-rc.5",
"strapi-helper-plugin": "3.0.0-alpha.8"
}
}
"strapi-helper-plugin": "3.0.0-alpha.8.3"
},
"author": {
"name": "Strapi team",
"email": "hi@strapi.io",
"url": "http://strapi.io"
},
"maintainers": [
{
"name": "Strapi team",
"email": "hi@strapi.io",
"url": "http://strapi.io"
}
],
"repository": {
"type": "git",
"url": "git://github.com/strapi/strapi.git"
},
"engines": {
"node": ">= 8.0.0",
"npm": ">= 3.0.0"
},
"license": "MIT"
}

View File

@ -1,6 +1,5 @@
# Dont check auto-generated stuff into git
coverage
build
node_modules
stats.json

View File

@ -1,6 +1,6 @@
{
"name": "strapi-plugin-content-type-builder",
"version": "3.0.0-alpha.8",
"version": "3.0.0-alpha.8.3",
"description": "Strapi plugin to create content type (API).",
"strapi": {
"name": "Content Type Builder",
@ -17,19 +17,18 @@
"build:clean": "node ./node_modules/strapi-helper-plugin/node_modules/.bin/rimraf admin/build",
"start": "node ./node_modules/strapi-helper-plugin/node_modules/.bin/cross-env NODE_ENV=development node ./node_modules/strapi-helper-plugin/lib/server",
"generate": "node ./node_modules/plop/plop.js --plopfile node_modules/strapi-helper-plugin/lib/internals/generators/index.js",
"lint": "node ./node_modules/strapi-helper-plugin/node_modules/.bin/eslint --ignore-path .gitignore --config ./node_modules/strapi-helper-plugin/lib/internals/eslint/.eslintrc.json admin",
"pretest": "npm run lint",
"lint": "node ./node_modules/strapi-helper-plugin/node_modules/.bin/eslint --ignore-path .gitignore --ignore-pattern '/admin/build/' --config ./node_modules/strapi-helper-plugin/lib/internals/eslint/.eslintrc.json admin",
"prettier": "node ./node_modules/strapi-helper-plugin/node_modules/.bin/prettier --single-quote --trailing-comma es5 --write \"{admin,__{tests,mocks}__}/**/*.js\"",
"test": "echo Tests are not implemented.",
"test": "npm run lint",
"prepublishOnly": "npm run build"
},
"dependencies": {
"pluralize": "^7.0.0",
"strapi-generate": "3.0.0-alpha.8",
"strapi-generate-api": "3.0.0-alpha.8"
"strapi-generate": "3.0.0-alpha.8.3",
"strapi-generate-api": "3.0.0-alpha.8.3"
},
"devDependencies": {
"strapi-helper-plugin": "3.0.0-alpha.8"
"strapi-helper-plugin": "3.0.0-alpha.8.3"
},
"author": {
"name": "Strapi team",
@ -43,6 +42,10 @@
"url": "http://strapi.io"
}
],
"repository": {
"type": "git",
"url": "git://github.com/strapi/strapi.git"
},
"engines": {
"node": ">= 8.0.0",
"npm": ">= 3.0.0"

View File

@ -1,6 +1,5 @@
# Don't check auto-generated stuff into git
coverage
build
node_modules
stats.json

View File

@ -1,6 +1,6 @@
{
"name": "strapi-plugin-email",
"version": "3.0.0-alpha.8",
"version": "3.0.0-alpha.8.3",
"description": "This is the description of the plugin.",
"strapi": {
"name": "Email",
@ -8,42 +8,45 @@
"description": "email.plugin.description"
},
"scripts": {
"analyze:clean": "node node_modules/strapi-helper-plugin/node_modules/.bin/rimraf stats.json",
"analyze:clean": "node ./node_modules/strapi-helper-plugin/node_modules/.bin/rimraf stats.json",
"preanalyze": "npm run analyze:clean",
"analyze": "node node_modules/strapi-helper-plugin/lib/internals/scripts/analyze.js",
"analyze": "node ./node_modules/strapi-helper-plugin/lib/internals/scripts/analyze.js",
"prebuild": "npm run build:clean && npm run test",
"build:dev": "node node_modules/strapi-helper-plugin/node_modules/.bin/cross-env NODE_ENV=development node node_modules/strapi-helper-plugin/node_modules/.bin/webpack --config node_modules/strapi-helper-plugin/lib/internals/webpack/webpack.prod.babel.js --color -p --progress",
"build": "node node_modules/strapi-helper-plugin/node_modules/.bin/cross-env NODE_ENV=production node node_modules/strapi-helper-plugin/node_modules/.bin/webpack --config node_modules/strapi-helper-plugin/lib/internals/webpack/webpack.prod.babel.js --color -p --progress",
"build:clean": "node node_modules/strapi-helper-plugin/node_modules/.bin/rimraf admin/build",
"start": "node node_modules/strapi-helper-plugin/node_modules/.bin/cross-env NODE_ENV=development node node_modules/strapi-helper-plugin/lib/server",
"generate": "node node_modules/plop/plop.js --plopfile node_modules/strapi-helper-plugin/lib/internals/generators/index.js",
"lint": "node node_modules/strapi-helper-plugin/node_modules/.bin/eslint --ignore-path .gitignore --config node_modules/strapi-helper-plugin/lib/internals/eslint/.eslintrc.json admin",
"pretest": "npm run lint",
"prettier": "node node_modules/strapi-helper-plugin/node_modules/.bin/prettier --single-quote --trailing-comma es5 --write \"{admin,__{tests,mocks}__}/**/*.js\"",
"test": "echo Tests are not implemented.",
"build:dev": "node ./node_modules/strapi-helper-plugin/node_modules/.bin/cross-env NODE_ENV=development node ./node_modules/strapi-helper-plugin/node_modules/.bin/webpack --config node_modules/strapi-helper-plugin/lib/internals/webpack/webpack.prod.babel.js --color -p --progress",
"build": "node ./node_modules/strapi-helper-plugin/node_modules/.bin/cross-env NODE_ENV=production node node_modules/strapi-helper-plugin/node_modules/.bin/webpack --config node_modules/strapi-helper-plugin/lib/internals/webpack/webpack.prod.babel.js --color -p --progress",
"build:clean": "node ./node_modules/strapi-helper-plugin/node_modules/.bin/rimraf admin/build",
"start": "node ./node_modules/strapi-helper-plugin/node_modules/.bin/cross-env NODE_ENV=development node ./node_modules/strapi-helper-plugin/lib/server",
"generate": "node ./node_modules/strapi-helper-plugin/node_modules/.bin/plop --plopfile ./node_modules/strapi-helper-plugin/lib/internals/generators/index.js",
"lint": "node ./node_modules/strapi-helper-plugin/node_modules/.bin/eslint --ignore-path .gitignore --ignore-pattern '/admin/build/' --config ./node_modules/strapi-helper-plugin/lib/internals/eslint/.eslintrc.json admin",
"prettier": "node ./node_modules/strapi-helper-plugin/node_modules/.bin/prettier --single-quote --trailing-comma es5 --write \"{admin,__{tests,mocks}__}/**/*.js\"",
"test": "npm run lint",
"prepublishOnly": "npm run build"
},
"dependencies": {
"sendmail": "^1.2.0"
},
"devDependencies": {
"strapi-helper-plugin": "3.0.0-alpha.8"
"strapi-helper-plugin": "3.0.0-alpha.8.3"
},
"author": {
"name": "A Strapi developer",
"email": "",
"url": ""
"name": "Strapi team",
"email": "hi@strapi.io",
"url": "http://strapi.io"
},
"maintainers": [
{
"name": "A Strapi developer",
"email": "",
"url": ""
"name": "Strapi team",
"email": "hi@strapi.io",
"url": "http://strapi.io"
}
],
"repository": {
"type": "git",
"url": "git://github.com/strapi/strapi.git"
},
"engines": {
"node": ">= 7.0.0",
"npm": ">= 3.0.0"
},
"license": "MIT"
}
}

View File

@ -1,6 +1,6 @@
{
"name": "strapi-plugin-settings-manager",
"version": "3.0.0-alpha.8",
"version": "3.0.0-alpha.8.3",
"description": "Strapi plugin to manage settings.",
"strapi": {
"name": "Settings Manager",
@ -17,16 +17,15 @@
"build:clean": "node ./node_modules/strapi-helper-plugin/node_modules/.bin/rimraf admin/build",
"start": "node ./node_modules/strapi-helper-plugin/node_modules/.bin/cross-env NODE_ENV=development node ./node_modules/strapi-helper-plugin/lib/server",
"generate": "node ./node_modules/strapi-helper-plugin/node_modules/.bin/plop --plopfile ./node_modules/strapi-helper-plugin/lib/internals/generators/index.js",
"lint": "node ./node_modules/strapi-helper-plugin/node_modules/.bin/eslint --ignore-path .gitignore --config ./node_modules/strapi-helper-plugin/lib/internals/eslint/.eslintrc.json admin",
"pretest": "npm run lint",
"lint": "node ./node_modules/strapi-helper-plugin/node_modules/.bin/eslint --ignore-path .gitignore --ignore-pattern '/admin/build/' --config ./node_modules/strapi-helper-plugin/lib/internals/eslint/.eslintrc.json admin",
"prettier": "node ./node_modules/strapi-helper-plugin/node_modules/.bin/prettier --single-quote --trailing-comma es5 --write \"{admin,__{tests,mocks}__}/**/*.js\"",
"test": "echo Tests are not implemented.",
"test": "npm run lint",
"prepublishOnly": "npm run build"
},
"devDependencies": {
"flag-icon-css": "^2.8.0",
"react-select": "^1.0.0-rc.5",
"strapi-helper-plugin": "3.0.0-alpha.8"
"strapi-helper-plugin": "3.0.0-alpha.8.3"
},
"author": {
"name": "Strapi team",
@ -40,9 +39,13 @@
"url": "http://strapi.io"
}
],
"repository": {
"type": "git",
"url": "git://github.com/strapi/strapi.git"
},
"engines": {
"node": ">= 8.0.0",
"npm": ">= 3.0.0"
},
"license": "MIT"
}
}

View File

@ -5,6 +5,7 @@ node_modules
stats.json
roles.json
jwt.json
grant.json
# Cruft
.DS_Store

View File

@ -27,6 +27,47 @@ module.exports = cb => {
}
}
if (!_.get(strapi.plugins['users-permissions'], 'config.grant')) {
try {
const grant = {
facebook: {
key: '',
secret: '',
callback: '/auth/facebook/callback',
scope: ['email']
},
google: {
key: '',
secret: '',
callback: '/auth/google/callback',
scope: ['email']
},
github: {
key: '',
secret: '',
redirect_uri: '/auth/google/callback',
scope: [
'user',
'user:email'
]
},
twitter: {
key: '',
secret: '',
callback: '/auth/twitter/callback'
}
};
fs.writeFileSync(path.join(strapi.config.appPath, 'plugins', 'users-permissions', 'config', 'grant.json'), JSON.stringify({
grant
}, null, 2), 'utf8');
_.set(strapi.plugins['users-permissions'], 'config.grant', grant);
} catch(err) {
strapi.log.error(err);
}
}
strapi.plugins['users-permissions'].services.userspermissions.syncSchema(() => {
strapi.plugins['users-permissions'].services.userspermissions.updatePermissions(cb);
});

View File

@ -25,10 +25,13 @@ module.exports = async (ctx, next) => {
}
}
const permission = _.get(strapi.plugins['users-permissions'].config, ['roles', role.toString(), 'permissions', route.plugin || 'application', 'controllers', route.controller, route.action]);
const actions = _.get(strapi.plugins['users-permissions'].config, ['roles', role.toString(), 'permissions', route.plugin || 'application', 'controllers', route.controller], {});
const permission = _.find(actions, (config, name) => {
return name.toLowerCase() === route.action.toLowerCase();
});
if (!permission) {
return await next();
return ctx.unauthorized('Access restricted for this action.');
}
if (permission.enabled && permission.policy) {

View File

@ -116,6 +116,15 @@
"prefix": ""
}
},
{
"method": "GET",
"path": "/auth/:provider/callback",
"handler": "Auth.callback",
"config": {
"policies": [],
"prefix": ""
}
},
{
"method": "POST",
"path": "/auth/forgot-password",

View File

@ -14,7 +14,6 @@ module.exports = {
callback: async (ctx) => {
const provider = ctx.params.provider || 'local';
const params = ctx.request.body;
const access_token = ctx.query.access_token;
if (provider === 'local') {
// The identifier is required.
@ -63,9 +62,12 @@ module.exports = {
}
} else {
// Connect the user thanks to the third-party provider.
const user = await strapi.api.user.services.grant.connect(provider, access_token);
const user = await strapi.plugins['users-permissions'].services.providers.connect(provider, ctx.query);
ctx.redirect(strapi.config.frontendUrl || strapi.config.url + '?jwt=' + strapi.api.user.services.jwt.issue(user) + '&user=' + JSON.stringify(user));
ctx.send({
jwt: strapi.plugins['users-permissions'].services.jwt.issue(user),
user: _.omit(user.toJSON ? user.toJSON() : user, ['password', 'resetPasswordToken'])
});
}
},

View File

@ -0,0 +1,5 @@
{
"provider": {
"enabled": true
}
}

View File

@ -0,0 +1,32 @@
'use strict';
/**
* Module dependencies
*/
// Public node modules.
const _ = require('lodash');
const Grant = require('grant-koa');
module.exports = strapi => {
return {
beforeInitialize: function() {
strapi.config.middleware.load.after.push('provider');
},
initialize: function(cb) {
_.defaultsDeep(strapi.plugins['users-permissions'].config.grant, {
server: {
protocol: 'http',
host: 'localhost:1337'
}
});
const grant = new Grant(strapi.plugins['users-permissions'].config.grant);
strapi.app.use(strapi.koaMiddlewares.compose(grant.middleware));
cb();
}
};
};

View File

@ -1,3 +1,10 @@
'use strict';
/**
* Module dependencies
*/
// Public node modules.
const _ = require('lodash');
module.exports = strapi => {

View File

@ -26,8 +26,7 @@
"password": {
"type": "password",
"minLength": 6,
"configurable": false,
"required": true
"configurable": false
},
"resetPasswordToken": {
"type": "string",

View File

@ -1,7 +1,7 @@
{
"name": "strapi-plugin-users-permissions",
"version": "3.0.0-alpha.8",
"description": "This is the description of the plugin.",
"description": "Protect your API with a full-authentication process based on JWT",
"strapi": {
"name": "Auth & Permissions",
"icon": "users",
@ -17,20 +17,22 @@
"build:clean": "node ./node_modules/strapi-helper-plugin/node_modules/.bin/rimraf admin/build",
"start": "node ./node_modules/strapi-helper-plugin/node_modules/.bin/cross-env NODE_ENV=development node ./node_modules/strapi-helper-plugin/lib/server",
"generate": "node ./node_modules/plop/plop.js --plopfile node_modules/strapi-helper-plugin/lib/internals/generators/index.js",
"lint": "node ./node_modules/strapi-helper-plugin/node_modules/.bin/eslint --ignore-path .gitignore --config ./node_modules/strapi-helper-plugin/lib/internals/eslint/.eslintrc.json admin",
"pretest": "npm run lint",
"lint": "node ./node_modules/strapi-helper-plugin/node_modules/.bin/eslint --ignore-path .gitignore --ignore-pattern '/admin/build/' --config ./node_modules/strapi-helper-plugin/lib/internals/eslint/.eslintrc.json admin",
"prettier": "node ./node_modules/strapi-helper-plugin/node_modules/.bin/prettier --single-quote --trailing-comma es5 --write \"{admin,__{tests,mocks}__}/**/*.js\"",
"test": "echo Tests are not implemented.",
"test": "npm run lint",
"prepublishOnly": "npm run build"
},
"dependencies": {
"bcryptjs": "^2.4.3",
"grant-koa": "^3.8.1",
"jsonwebtoken": "^8.1.0",
"koa": "^2.1.0",
"purest": "^2.0.1",
"request": "^2.83.0",
"uuid": "^3.1.0"
},
"devDependencies": {
"strapi-helper-plugin": "3.0.0-alpha.8"
"strapi-helper-plugin": "3.0.0-alpha.8.3"
},
"author": {
"name": "Strapi team",
@ -44,6 +46,10 @@
"url": "http://strapi.io"
}
],
"repository": {
"type": "git",
"url": "git://github.com/strapi/strapi.git"
},
"engines": {
"node": ">= 7.0.0",
"npm": ">= 3.0.0"

View File

@ -0,0 +1,168 @@
'use strict';
/**
* Module dependencies.
*/
// Public node modules.
const _ = require('lodash');
const request = require('request');
// Purest strategies.
const Purest = require('purest');
const facebook = new Purest({
provider: 'facebook'
});
const github = new Purest({
provider: 'github',
defaults: {
headers: {
'user-agent': 'strapi'
}
}
});
const google = new Purest({
provider: 'google'
});
const twitter = new Purest({
provider: 'twitter'
});
/**
* Connect thanks to a third-party provider.
*
*
* @param {String} provider
* @param {String} access_token
*
* @return {*}
*/
exports.connect = (provider, query) => {
const access_token = query.access_token || query.code || query.oauth_token;
return new Promise((resolve, reject) => {
if (!access_token) {
reject({
message: 'No access_token.'
});
} else {
// Get the profile.
getProfile(provider, query, (err, profile) => {
if (err) {
reject(err);
} else {
// We need at least the mail.
if (!profile.email) {
reject({
message: 'Email was not available.'
});
} else {
strapi.query('user', 'users-permissions').findOne({email: profile.email})
.then(user => {
if (!user) {
// Create the new user.
const params = _.assign(profile, {
provider: provider
});
strapi.query('user', 'users-permissions').create(params)
.then(user => {
resolve(user);
})
.catch(err => {
reject(err);
});
} else {
resolve(user);
}
})
.catch(err => {
reject(err);
});
}
}
});
}
});
};
/**
* Helper to get profiles
*
* @param {String} provider
* @param {Function} callback
*/
const getProfile = (provider, query, callback) => {
const access_token = query.access_token || query.code || query.oauth_token;
switch (provider) {
case 'facebook':
facebook.query().get('me?fields=name,email').auth(access_token).request((err, res, body) => {
if (err) {
callback(err);
} else {
callback(null, {
username: body.name,
email: body.email
});
}
});
break;
case 'google':
google.query('plus').get('people/me').auth(access_token).request((err, res, body) => {
if (err) {
callback(err);
} else {
callback(null, {
username: body.displayName,
email: body.emails[0].value
});
}
});
break;
case 'github':
request.post({
url: 'https://github.com/login/oauth/access_token',
form: {
client_id: strapi.plugins['users-permissions'].config.grant.github.key,
client_secret: strapi.plugins['users-permissions'].config.grant.github.secret,
code: access_token
}
}, (err, res, body) => {
github.query().get('user').auth(body.split('&')[0].split('=')[1]).request((err, res, body) => {
if (err) {
callback(err);
} else {
callback(null, {
username: body.login,
email: body.email
});
}
});
});
break;
case 'twitter':
twitter.query().get('account/verify_credentials').auth(access_token, query.access_secret).qs({screen_name: query['raw[screen_name]']}).qs({include_email: 'true'}).request((err, res, body) => {
if (err) {
callback(err);
} else {
callback(null, {
username: body.screen_name,
email: body.email
});
}
});
break;
default:
callback({
message: 'Unknown provider.'
});
break;
}
}

View File

@ -1,6 +1,6 @@
{
"name": "strapi-redis",
"version": "3.0.0-alpha.8",
"version": "3.0.0-alpha.8.3",
"description": "Redis hook for the Strapi framework",
"homepage": "http://strapi.io",
"keywords": [
@ -18,7 +18,7 @@
"ioredis": "^3.1.2",
"lodash": "^4.17.4",
"stack-trace": "0.0.10",
"strapi-utils": "3.0.0-alpha.8"
"strapi-utils": "3.0.0-alpha.8.3"
},
"strapi": {
"isHook": true

View File

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

View File

@ -110,7 +110,7 @@ module.exports = function() {
return reject(err);
}
mountMiddlewares.call(this, files, cwd)(resolve, reject);
mountMiddlewares.call(this, files, cwd, true)(resolve, reject);
}
);
})
@ -154,12 +154,13 @@ const requireMiddlewares = function (files, cwd) {
);
};
const mountMiddlewares = function (files, cwd) {
const mountMiddlewares = function (files, cwd, isPlugin) {
return (resolve, reject) =>
parallel(
files.map(p => cb => {
const name = p.replace(/^.\/node_modules\/strapi-middleware-/, './')
.split('/')[1];
const folders = p.replace(/^.\/node_modules\/strapi-middleware-/, './')
.split('/');
const name = isPlugin ? folders[folders.length - 2] : folders[1];
this.middleware[name] = this.middleware[name] || {
loaded: false

View File

@ -17,36 +17,46 @@ const pluginsDirPath = path.join(process.cwd(), 'plugins');
const adminDirPath = path.join(process.cwd(), 'admin');
const plugins = fs.readdirSync(pluginsDirPath).filter(x => x[0] !== '.');
// Install dependencies for each plugins
_.forEach(plugins, plugin => {
const pluginPath = path.join(pluginsDirPath, plugin);
console.log(`📦 Installing ${_.upperFirst(plugin)} (plugin) packages...`);
try {
const install = exec(`cd ${pluginPath} && npm install --prod --ignore-scripts`, {
silent: true
});
if (install.stderr) {
console.error(install.stderr);
}
} catch (err) {
console.log(err);
}
});
// Install admin dependencies
console.log(`📦 Installing admin packages...`);
console.log(`🔸 Administration Panel`);
console.log('📦 Installing packages...');
try {
const install = exec(`cd ${adminDirPath} && npm install --prod --ignore-scripts`, {
silent: true
});
if (install.stderr) {
console.error(build.stderr);
if (install.stderr && install.code !== 0) {
console.error(install.stderr);
process.exit(1);
}
console.log('✅ Success');
console.log('');
} catch (err) {
console.log(err);
}
// Install dependencies for each plugins
_.forEach(plugins, plugin => {
const pluginPath = path.join(pluginsDirPath, plugin);
console.log(`🔸 Plugin - ${_.upperFirst(plugin)}`);
console.log('📦 Installing packages...');
try {
const install = exec(`cd ${pluginPath} && npm install --prod --ignore-scripts`, {
silent: true
});
if (install.stderr && install.code !== 0) {
console.error(install.stderr);
process.exit(1);
}
console.log('✅ Success');
console.log('');
} catch (err) {
console.log(err);
}
});

View File

@ -1,6 +1,6 @@
{
"name": "strapi",
"version": "3.0.0-alpha.8",
"version": "3.0.0-alpha.8.3",
"description": "An open source solution to create and manage your own API. It provides a powerful dashboard and features to make your life easier.",
"homepage": "http://strapi.io",
"keywords": [
@ -55,14 +55,14 @@
"rimraf": "^2.6.2",
"semver": "^5.4.1",
"stack-trace": "0.0.10",
"strapi-generate": "3.0.0-alpha.8",
"strapi-generate-admin": "3.0.0-alpha.8",
"strapi-generate-api": "3.0.0-alpha.8",
"strapi-generate-new": "3.0.0-alpha.8",
"strapi-generate-plugin": "3.0.0-alpha.8",
"strapi-generate-policy": "3.0.0-alpha.8",
"strapi-generate-service": "3.0.0-alpha.8",
"strapi-utils": "3.0.0-alpha.8"
"strapi-generate": "3.0.0-alpha.8.3",
"strapi-generate-admin": "3.0.0-alpha.8.3",
"strapi-generate-api": "3.0.0-alpha.8.3",
"strapi-generate-new": "3.0.0-alpha.8.3",
"strapi-generate-plugin": "3.0.0-alpha.8.3",
"strapi-generate-policy": "3.0.0-alpha.8.3",
"strapi-generate-service": "3.0.0-alpha.8.3",
"strapi-utils": "3.0.0-alpha.8.3"
},
"author": {
"email": "hi@strapi.io",

View File

@ -1,14 +1,15 @@
const shell = require('shelljs');
// Store installation start date.
const silent = process.env.npm_config_debug !== 'true';
const installationStartDate = new Date();
const watcher = (label, cmd, withSuccess = true) => {
if (label.length > 0) {
shell.echo(`📦 ${label}`);
shell.echo(label);
}
const data = shell.exec(cmd, {
silent: true
silent
});
if (data.stderr && data.code !== 0) {
@ -30,75 +31,84 @@ shell.echo('');
shell.rm('-f', '/usr/local/bin/strapi.js');
shell.cd('packages/strapi-utils');
watcher('Linking strapi-utils...', 'npm link');
watcher('📦 Linking strapi-utils...', 'npm link');
shell.cd('../strapi-generate');
watcher('', 'npm install ../strapi-utils');
watcher('Linking strapi-generate...', 'npm link');
watcher('📦 Linking strapi-generate...', 'npm link');
shell.cd('../strapi-generate-api');
watcher('Linking strapi-generate-api...', 'npm link');
watcher('📦 Linking strapi-generate-api...', 'npm link');
shell.cd('../strapi-helper-plugin');
watcher('Linking strapi-helper-plugin...', 'npm link');
watcher('📦 Linking strapi-helper-plugin...', 'npm link');
shell.cd('../strapi-admin');
watcher('', 'npm install ../strapi-helper-plugin --no-optional');
watcher('', 'npm install ../strapi-utils --no-optional');
shell.rm('-f', 'package-lock.json');
watcher('Linking strapi-admin', 'npm link --no-optional', false);
watcher('Building...', 'npm run build');
// Without these line Travis failed.
if (shell.test('-e', 'admin/src/config/plugins.json') === false) {
shell.config.silent = silent;
shell.cd('admin/src/config/');
shell.ShellString('[]').to('plugins.json');
shell.cd('../../../');
}
watcher('📦 Linking strapi-admin', 'npm link --no-optional', false);
watcher('🏗 Building...', 'npm run build');
shell.cd('../strapi-generate-admin');
watcher('', 'npm install ../strapi-admin');
watcher('Linking strapi-generate-admin...', 'npm link');
watcher('📦 Linking strapi-generate-admin...', 'npm link');
shell.cd('../strapi-generate-new');
watcher('', 'npm install ../strapi-utils');
watcher('Linking strapi-generate-new', 'npm link');
watcher('📦 Linking strapi-generate-new', 'npm link');
shell.cd('../strapi-mongoose');
watcher('', 'npm install ../strapi-utils');
watcher('Linking strapi-mongoose...', 'npm link');
watcher('📦 Linking strapi-mongoose...', 'npm link');
shell.cd('../strapi');
watcher('', 'npm install ../strapi-generate ../strapi-generate-admin ../strapi-generate-api ../strapi-generate-new ../strapi-generate-plugin ../strapi-generate-policy ../strapi-generate-service ../strapi-utils');
watcher('Linking strapi...', 'npm link');
watcher('📦 Linking strapi...', 'npm link');
shell.cd('../strapi-plugin-email');
watcher('', 'npm install ../strapi-helper-plugin --no-optional');
shell.rm('-f', 'package-lock.json');
watcher('Linking strapi-plugin-email...', 'npm link --no-optional', false);
watcher('Building...', 'npm run build');
watcher('📦 Linking strapi-plugin-email...', 'npm link --no-optional', false);
watcher('🏗 Building...', 'npm run build');
shell.cd('../strapi-plugin-users-permissions');
watcher('', 'npm install ../strapi-helper-plugin --no-optional');
shell.rm('-f', 'package-lock.json');
watcher('Linking strapi-plugin-users-permissions...', 'npm link --no-optional', false);
watcher('Building...', 'npm run build');
watcher('📦 Linking strapi-plugin-users-permissions...', 'npm link --no-optional', false);
watcher('🏗 Building...', 'npm run build');
shell.cd('../strapi-plugin-content-manager');
watcher('', 'npm install ../strapi-helper-plugin --no-optional');
shell.rm('-f', 'package-lock.json');
watcher('Linking strapi-plugin-content-manager...', 'npm link --no-optional', false);
watcher('Building...', 'npm run build');
watcher('📦 Linking strapi-plugin-content-manager...', 'npm link --no-optional', false);
watcher('🏗 Building...', 'npm run build');
shell.cd('../strapi-plugin-settings-manager');
watcher('', 'npm install ../strapi-helper-plugin --no-optional');
shell.rm('-f', 'package-lock.json');
watcher('Linking strapi-plugin-settings-manager...', 'npm link --no-optional', false);
watcher('Building...', 'npm run build');
watcher('📦 Linking strapi-plugin-settings-manager...', 'npm link --no-optional', false);
watcher('🏗 Building...', 'npm run build');
shell.cd('../strapi-plugin-content-type-builder');
watcher('', 'npm install ../strapi-helper-plugin --no-optional');
watcher('', 'npm install ../strapi-generate --no-optional');
watcher('', 'npm install ../strapi-generate-api --no-optional');
shell.rm('-f', 'package-lock.json');
watcher('Linking strapi-plugin-content-type-builder...', 'npm link --no-optional', false);
watcher('Building...', 'npm run build');
watcher('📦 Linking strapi-plugin-content-type-builder...', 'npm link --no-optional', false);
watcher('🏗 Building...', 'npm run build');
// Log installation duration.
const installationEndDate = new Date();
const duration = (installationEndDate.getTime() - installationStartDate.getTime()) / 1000;
shell.echo('Strapi has been succesfully installed.');
shell.echo(`Installation took ${Math.floor(duration / 60) > 0 ? `${Math.floor(duration / 60)} minutes and ` : ''}${Math.floor(duration % 60)} seconds.`);
shell.echo('Strapi has been succesfully installed.');
shell.echo(`⏳ The installation took ${Math.floor(duration / 60) > 0 ? `${Math.floor(duration / 60)} minutes and ` : ''}${Math.floor(duration % 60)} seconds.`);