mirror of
https://github.com/strapi/strapi.git
synced 2025-11-13 16:52:18 +00:00
Merge branch 'master' into fix/802
This commit is contained in:
commit
49ced583f3
@ -15,10 +15,10 @@ The most advanced open-source Content Management Framework to build powerful API
|
|||||||
|
|
||||||
{% endcenter %}
|
{% endcenter %}
|
||||||
|
|
||||||
## v3@alpha.11 is available!
|
## v3@alpha.12 is available!
|
||||||
We've been working on a major update for Strapi during the past months, rewriting the core framework and the dashboard.
|
We've been working on a major update for Strapi during the past months, rewriting the core framework and the dashboard.
|
||||||
|
|
||||||
This documentation is only related to Strapi v3@alpha.11 ([v1 documentation is still available](http://strapi.io/documentation/1.x.x)).
|
This documentation is only related to Strapi v3@alpha.12 ([v1 documentation is still available](http://strapi.io/documentation/1.x.x)).
|
||||||
|
|
||||||
**[Get Started](getting-started/installation.md)**<br />
|
**[Get Started](getting-started/installation.md)**<br />
|
||||||
Learn how to install Strapi and start developing your API.
|
Learn how to install Strapi and start developing your API.
|
||||||
|
|||||||
@ -12,7 +12,7 @@ The entire logic of the admin panel is located in a single folder named `./admin
|
|||||||
└─── admin
|
└─── admin
|
||||||
| └─── build // Webpack generated build of the front-end
|
| └─── build // Webpack generated build of the front-end
|
||||||
| └─── src // Front-end directory
|
| └─── src // Front-end directory
|
||||||
| └─── app.js // Entry point of the Reacr application
|
| └─── app.js // Entry point of the React application
|
||||||
| └─── assets // Assets directory containing images,...
|
| └─── assets // Assets directory containing images,...
|
||||||
| └─── components // Admin's React components directory
|
| └─── components // Admin's React components directory
|
||||||
| └─── containers // Admin's high level components directory
|
| └─── containers // Admin's high level components directory
|
||||||
|
|||||||
@ -17,8 +17,10 @@ defineMessages(messages);
|
|||||||
function LeftMenuFooter({ version }) { // eslint-disable-line react/prefer-stateless-function
|
function LeftMenuFooter({ version }) { // eslint-disable-line react/prefer-stateless-function
|
||||||
return (
|
return (
|
||||||
<div className={styles.leftMenuFooter}>
|
<div className={styles.leftMenuFooter}>
|
||||||
|
<div>
|
||||||
<FormattedMessage {...messages.poweredBy} />
|
<FormattedMessage {...messages.poweredBy} />
|
||||||
<a href="https://strapi.io" target="_blank">v{version}</a>
|
<a href="https://strapi.io" target="_blank">v{version}</a>
|
||||||
|
</div>
|
||||||
<LocaleToggle />
|
<LocaleToggle />
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|||||||
@ -4,6 +4,8 @@
|
|||||||
.leftMenuFooter { /* stylelint-disable */
|
.leftMenuFooter { /* stylelint-disable */
|
||||||
position: absolute;
|
position: absolute;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
bottom: 0;
|
bottom: 0;
|
||||||
height: 3rem;
|
height: 3rem;
|
||||||
padding-left: 15px;
|
padding-left: 15px;
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
@ -4,6 +4,7 @@
|
|||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
import {
|
import {
|
||||||
|
GET_CURR_ENV_SUCCEEDED,
|
||||||
GET_GA_STATUS,
|
GET_GA_STATUS,
|
||||||
GET_GA_STATUS_SUCCEEDED,
|
GET_GA_STATUS_SUCCEEDED,
|
||||||
GET_LAYOUT,
|
GET_LAYOUT,
|
||||||
@ -11,6 +12,13 @@ import {
|
|||||||
GET_STRAPI_VERSION_SUCCEEDED,
|
GET_STRAPI_VERSION_SUCCEEDED,
|
||||||
} from './constants';
|
} from './constants';
|
||||||
|
|
||||||
|
export function getCurrEnvSucceeded(currentEnvironment) {
|
||||||
|
return {
|
||||||
|
type: GET_CURR_ENV_SUCCEEDED,
|
||||||
|
currentEnvironment,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
export function getGaStatus() {
|
export function getGaStatus() {
|
||||||
return {
|
return {
|
||||||
type: GET_GA_STATUS,
|
type: GET_GA_STATUS,
|
||||||
|
|||||||
@ -4,6 +4,7 @@
|
|||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
export const GET_CURR_ENV_SUCCEEDED = 'app/Admin/GET_CURR_ENV_SUCCEEDED';
|
||||||
export const GET_GA_STATUS = 'app/Admin/GET_GA_STATUS';
|
export const GET_GA_STATUS = 'app/Admin/GET_GA_STATUS';
|
||||||
export const GET_GA_STATUS_SUCCEEDED = 'app/Admin/GET_GA_STATUS_SUCCEEDED';
|
export const GET_GA_STATUS_SUCCEEDED = 'app/Admin/GET_GA_STATUS_SUCCEEDED';
|
||||||
export const GET_LAYOUT = 'app/Admin/GET_LAYOUT';
|
export const GET_LAYOUT = 'app/Admin/GET_LAYOUT';
|
||||||
|
|||||||
@ -59,6 +59,8 @@ import selectAdminPage from './selectors';
|
|||||||
|
|
||||||
import styles from './styles.scss';
|
import styles from './styles.scss';
|
||||||
|
|
||||||
|
const PLUGINS_TO_BLOCK_PRODUCTION = ['content-type-builder', 'settings-manager'];
|
||||||
|
|
||||||
export class AdminPage extends React.Component { // eslint-disable-line react/prefer-stateless-function
|
export class AdminPage extends React.Component { // eslint-disable-line react/prefer-stateless-function
|
||||||
state = { hasAlreadyRegistereOtherPlugins: false };
|
state = { hasAlreadyRegistereOtherPlugins: false };
|
||||||
|
|
||||||
@ -136,6 +138,20 @@ export class AdminPage extends React.Component { // eslint-disable-line react/pr
|
|||||||
|
|
||||||
showLeftMenu = () => !includes(this.props.location.pathname, 'users-permissions/auth/');
|
showLeftMenu = () => !includes(this.props.location.pathname, 'users-permissions/auth/');
|
||||||
|
|
||||||
|
retrievePlugins = () => {
|
||||||
|
const { adminPage: { currentEnvironment }, plugins } = this.props;
|
||||||
|
|
||||||
|
if (currentEnvironment === 'production') {
|
||||||
|
let pluginsToDisplay = plugins;
|
||||||
|
PLUGINS_TO_BLOCK_PRODUCTION.map(plugin =>
|
||||||
|
pluginsToDisplay = pluginsToDisplay.delete(plugin));
|
||||||
|
|
||||||
|
return pluginsToDisplay;
|
||||||
|
}
|
||||||
|
|
||||||
|
return plugins;
|
||||||
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const { adminPage } = this.props;
|
const { adminPage } = this.props;
|
||||||
const header = this.showLeftMenu() ? <Header /> : '';
|
const header = this.showLeftMenu() ? <Header /> : '';
|
||||||
@ -145,7 +161,7 @@ export class AdminPage extends React.Component { // eslint-disable-line react/pr
|
|||||||
<div className={styles.adminPage}>
|
<div className={styles.adminPage}>
|
||||||
{this.showLeftMenu() && (
|
{this.showLeftMenu() && (
|
||||||
<LeftMenu
|
<LeftMenu
|
||||||
plugins={this.props.plugins}
|
plugins={this.retrievePlugins()}
|
||||||
layout={adminPage.layout}
|
layout={adminPage.layout}
|
||||||
version={adminPage.strapiVersion}
|
version={adminPage.strapiVersion}
|
||||||
/>
|
/>
|
||||||
|
|||||||
@ -7,6 +7,7 @@
|
|||||||
import { fromJS, Map } from 'immutable';
|
import { fromJS, Map } from 'immutable';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
|
GET_CURR_ENV_SUCCEEDED,
|
||||||
GET_GA_STATUS_SUCCEEDED,
|
GET_GA_STATUS_SUCCEEDED,
|
||||||
GET_LAYOUT_SUCCEEDED,
|
GET_LAYOUT_SUCCEEDED,
|
||||||
GET_STRAPI_VERSION_SUCCEEDED,
|
GET_STRAPI_VERSION_SUCCEEDED,
|
||||||
@ -14,12 +15,15 @@ import {
|
|||||||
|
|
||||||
const initialState = fromJS({
|
const initialState = fromJS({
|
||||||
allowGa: true,
|
allowGa: true,
|
||||||
|
currentEnvironment: 'development',
|
||||||
layout: Map({}),
|
layout: Map({}),
|
||||||
strapiVersion: '3',
|
strapiVersion: '3',
|
||||||
});
|
});
|
||||||
|
|
||||||
function adminPageReducer(state = initialState, action) {
|
function adminPageReducer(state = initialState, action) {
|
||||||
switch (action.type) {
|
switch (action.type) {
|
||||||
|
case GET_CURR_ENV_SUCCEEDED:
|
||||||
|
return state.update('currentEnvironment', () => action.currentEnvironment);
|
||||||
case GET_GA_STATUS_SUCCEEDED:
|
case GET_GA_STATUS_SUCCEEDED:
|
||||||
return state.update('allowGa', () => action.allowGa);
|
return state.update('allowGa', () => action.allowGa);
|
||||||
case GET_LAYOUT_SUCCEEDED:
|
case GET_LAYOUT_SUCCEEDED:
|
||||||
|
|||||||
@ -2,6 +2,7 @@ import { fork, call, put, takeLatest } from 'redux-saga/effects';
|
|||||||
import request from 'utils/request';
|
import request from 'utils/request';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
|
getCurrEnvSucceeded,
|
||||||
getGaStatusSucceeded,
|
getGaStatusSucceeded,
|
||||||
getLayoutSucceeded,
|
getLayoutSucceeded,
|
||||||
getStrapiVersionSucceeded,
|
getStrapiVersionSucceeded,
|
||||||
@ -10,11 +11,13 @@ import { GET_GA_STATUS, GET_LAYOUT } from './constants';
|
|||||||
|
|
||||||
function* getGaStatus() {
|
function* getGaStatus() {
|
||||||
try {
|
try {
|
||||||
const [allowGa, strapiVersion] = yield [
|
const [allowGa, strapiVersion, currentEnvironment] = yield [
|
||||||
call(request, '/admin/gaConfig', { method: 'GET' }),
|
call(request, '/admin/gaConfig', { method: 'GET' }),
|
||||||
call(request, '/admin/strapiVersion', { method: 'GET' }),
|
call(request, '/admin/strapiVersion', { method: 'GET' }),
|
||||||
|
call(request, '/admin/currentEnvironment', { method: 'GET' }),
|
||||||
];
|
];
|
||||||
|
|
||||||
|
yield put(getCurrEnvSucceeded(currentEnvironment.currentEnvironment));
|
||||||
yield put(getGaStatusSucceeded(allowGa));
|
yield put(getGaStatusSucceeded(allowGa));
|
||||||
yield put(getStrapiVersionSucceeded(strapiVersion.strapiVersion));
|
yield put(getStrapiVersionSucceeded(strapiVersion.strapiVersion));
|
||||||
} catch(err) {
|
} catch(err) {
|
||||||
|
|||||||
@ -10,17 +10,20 @@
|
|||||||
"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",
|
"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": "APP_PATH=$APP_PATH node ./node_modules/strapi-helper-plugin/node_modules/.bin/cross-env NODE_ENV=production IS_ADMIN=true node ./node_modules/strapi-helper-plugin/lib/internals/scripts/loadAdminConfigurations.js",
|
||||||
"build:dev": "npm run build:dll && node ./node_modules/strapi-helper-plugin/node_modules/.bin/cross-env NODE_ENV=development IS_ADMIN=true 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:dev": "npm run build:dll && node ./node_modules/strapi-helper-plugin/node_modules/.bin/cross-env NODE_ENV=development IS_ADMIN=true 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": "APP_PATH=$APP_PATH npm run build:dll && node ./node_modules/strapi-helper-plugin/node_modules/.bin/cross-env NODE_ENV=production IS_ADMIN=true 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": "APP_PATH=$APP_PATH npm run build:dll && node ./node_modules/strapi-helper-plugin/node_modules/.bin/cross-env NODE_ENV=production IS_ADMIN=true 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:dll": "APP_PATH=$APP_PATH node ./node_modules/strapi-helper-plugin/node_modules/.bin/cross-env NODE_ENV=production IS_ADMIN=true node ./node_modules/strapi-helper-plugin/node_modules/.bin/webpack --config ./node_modules/strapi-helper-plugin/lib/internals/webpack/webpack.dll.babel.js --color -p --progress",
|
"build:dll": "APP_PATH=$APP_PATH node ./node_modules/strapi-helper-plugin/node_modules/.bin/cross-env NODE_ENV=production IS_ADMIN=true node ./node_modules/strapi-helper-plugin/node_modules/.bin/webpack --config ./node_modules/strapi-helper-plugin/lib/internals/webpack/webpack.dll.babel.js --color -p --progress",
|
||||||
"build:clean": "node ./node_modules/strapi-helper-plugin/node_modules/.bin/rimraf admin/build",
|
"build:clean": "node ./node_modules/strapi-helper-plugin/node_modules/.bin/rimraf admin/build",
|
||||||
|
"prestart": "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/internals/scripts/loadAdminConfigurations.js",
|
||||||
"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",
|
"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",
|
"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 --ignore-pattern build --config ./node_modules/strapi-helper-plugin/lib/internals/eslint/.eslintrc.json admin",
|
"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\"",
|
"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",
|
"test": "npm run lint",
|
||||||
"prepublishOnly": "npm run build",
|
"prepublishOnly": "npm run build",
|
||||||
"setup": "node ./scripts/setup.js"
|
"setup": "node ./scripts/setup.js",
|
||||||
|
"presetup": "node ./scripts/preSetup.js"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"react-ga": "^2.4.1",
|
"react-ga": "^2.4.1",
|
||||||
|
|||||||
43
packages/strapi-admin/scripts/preSetup.js
Normal file
43
packages/strapi-admin/scripts/preSetup.js
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
const shell = require('shelljs');
|
||||||
|
const path = require('path');
|
||||||
|
const _ = require('lodash');
|
||||||
|
|
||||||
|
shell.echo('');
|
||||||
|
shell.echo('🕓 The setup process can take few minutes.');
|
||||||
|
shell.echo('');
|
||||||
|
shell.echo('🔸 Administration Panel');
|
||||||
|
shell.echo('📦 Installing packages...');
|
||||||
|
|
||||||
|
const pwd = shell.pwd();
|
||||||
|
|
||||||
|
const silent = process.env.npm_config_debug !== 'true';
|
||||||
|
const isDevelopmentMode = path.resolve(pwd.stdout).indexOf('strapi-admin') !== -1;
|
||||||
|
const appPath = isDevelopmentMode ? path.resolve(process.env.PWD, '..') : path.resolve(pwd.stdout, '..');
|
||||||
|
|
||||||
|
// We just install the admin's dependencies here
|
||||||
|
|
||||||
|
// Remove package-lock.json.
|
||||||
|
shell.rm('-rf', path.resolve(appPath, 'package-lock.json'));
|
||||||
|
shell.rm('-rf', path.resolve(appPath, 'admin', 'package-lock.json'));
|
||||||
|
|
||||||
|
// Install the project dependencies.
|
||||||
|
shell.exec(`cd "${appPath}" && npm install --ignore-scripts`, {
|
||||||
|
silent
|
||||||
|
});
|
||||||
|
|
||||||
|
// Install the administration dependencies.
|
||||||
|
shell.exec(`cd "${path.resolve(appPath, 'admin')}" && npm install`, {
|
||||||
|
silent
|
||||||
|
});
|
||||||
|
|
||||||
|
if (isDevelopmentMode) {
|
||||||
|
shell.exec(`cd "${path.resolve(appPath, 'admin')}" && npm link strapi-helper-plugin && npm link strapi-utils`, {
|
||||||
|
silent
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
shell.exec(`cd "${path.resolve(appPath, 'admin', 'node_modules', 'strapi-helper-plugin')}" && npm install`, {
|
||||||
|
silent
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
shell.echo('Packaged installed successfully');
|
||||||
@ -1,44 +1,15 @@
|
|||||||
|
const fs = require('fs');
|
||||||
const shell = require('shelljs');
|
const shell = require('shelljs');
|
||||||
const path = require('path');
|
const path = require('path');
|
||||||
const _ = require('lodash');
|
const _ = require('lodash');
|
||||||
|
|
||||||
shell.echo('');
|
|
||||||
shell.echo('🕓 The setup process can take few minutes.');
|
|
||||||
shell.echo('');
|
|
||||||
shell.echo('🔸 Administration Panel');
|
|
||||||
shell.echo('📦 Installing packages...');
|
|
||||||
|
|
||||||
const pwd = shell.pwd();
|
const pwd = shell.pwd();
|
||||||
|
|
||||||
const silent = process.env.npm_config_debug !== 'true';
|
const silent = process.env.npm_config_debug !== 'true';
|
||||||
const isDevelopmentMode = path.resolve(pwd.stdout).indexOf('strapi-admin') !== -1;
|
const isDevelopmentMode = path.resolve(pwd.stdout).indexOf('strapi-admin') !== -1;
|
||||||
const appPath = isDevelopmentMode ? path.resolve(process.env.PWD, '..') : path.resolve(pwd.stdout, '..');
|
const appPath = isDevelopmentMode ? path.resolve(process.env.PWD, '..') : path.resolve(pwd.stdout, '..');
|
||||||
|
|
||||||
// Remove package-lock.json.
|
shell.echo('🏗 Building the admin...');
|
||||||
shell.rm('-rf', path.resolve(appPath, 'package-lock.json'));
|
|
||||||
shell.rm('-rf', path.resolve(appPath, 'admin', 'package-lock.json'));
|
|
||||||
|
|
||||||
// Install the project dependencies.
|
|
||||||
shell.exec(`cd "${appPath}" && npm install --ignore-scripts`, {
|
|
||||||
silent
|
|
||||||
});
|
|
||||||
|
|
||||||
// Install the administration dependencies.
|
|
||||||
shell.exec(`cd "${path.resolve(appPath, 'admin')}" && npm install`, {
|
|
||||||
silent
|
|
||||||
});
|
|
||||||
|
|
||||||
if (isDevelopmentMode) {
|
|
||||||
shell.exec(`cd "${path.resolve(appPath, 'admin')}" && npm link strapi-helper-plugin && npm link strapi-utils`, {
|
|
||||||
silent
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
shell.exec(`cd "${path.resolve(appPath, 'admin', 'node_modules', 'strapi-helper-plugin')}" && npm install`, {
|
|
||||||
silent
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
shell.echo('🏗 Building...');
|
|
||||||
|
|
||||||
const build = shell.exec(`cd "${path.resolve(appPath, 'admin')}" && APP_PATH="${appPath}" npm run build`, {
|
const build = shell.exec(`cd "${path.resolve(appPath, 'admin')}" && APP_PATH="${appPath}" npm run build`, {
|
||||||
silent
|
silent
|
||||||
@ -55,7 +26,21 @@ shell.echo('');
|
|||||||
if (process.env.npm_config_plugins === 'true') {
|
if (process.env.npm_config_plugins === 'true') {
|
||||||
const plugins = path.resolve(appPath, 'plugins');
|
const plugins = path.resolve(appPath, 'plugins');
|
||||||
|
|
||||||
shell.ls('* -d', plugins).forEach(function (plugin) {
|
// TODO: build plugins in async
|
||||||
|
shell.ls('* -d', plugins)
|
||||||
|
.filter(x => {
|
||||||
|
let hasAdminFolder;
|
||||||
|
|
||||||
|
try {
|
||||||
|
fs.accessSync(path.resolve(appPath, 'plugins', x, 'admin', 'src', 'containers', 'App'));
|
||||||
|
hasAdminFolder = true;
|
||||||
|
} catch(err) {
|
||||||
|
hasAdminFolder = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return hasAdminFolder;
|
||||||
|
})
|
||||||
|
.forEach(function (plugin) {
|
||||||
shell.echo(`🔸 Plugin - ${_.upperFirst(plugin)}`);
|
shell.echo(`🔸 Plugin - ${_.upperFirst(plugin)}`);
|
||||||
shell.echo('📦 Installing packages...');
|
shell.echo('📦 Installing packages...');
|
||||||
shell.exec(`cd "${path.resolve(plugins, plugin)}" && npm install`, {
|
shell.exec(`cd "${path.resolve(plugins, plugin)}" && npm install`, {
|
||||||
|
|||||||
@ -40,9 +40,11 @@ module.exports = function(strapi) {
|
|||||||
* Initialize the hook
|
* Initialize the hook
|
||||||
*/
|
*/
|
||||||
|
|
||||||
initialize: cb => {
|
initialize: async cb => {
|
||||||
const connections = _.pickBy(strapi.config.connections, { connector: 'strapi-bookshelf' });
|
const connections = _.pickBy(strapi.config.connections, { connector: 'strapi-bookshelf' });
|
||||||
|
|
||||||
|
const databaseUpdate = [];
|
||||||
|
|
||||||
_.forEach(connections, (connection, connectionName) => {
|
_.forEach(connections, (connection, connectionName) => {
|
||||||
// Apply defaults
|
// Apply defaults
|
||||||
_.defaults(connection.settings, strapi.config.hook.settings.bookshelf);
|
_.defaults(connection.settings, strapi.config.hook.settings.bookshelf);
|
||||||
@ -307,6 +309,233 @@ module.exports = function(strapi) {
|
|||||||
// Push attributes to be aware of model schema.
|
// Push attributes to be aware of model schema.
|
||||||
target[model]._attributes = definition.attributes;
|
target[model]._attributes = definition.attributes;
|
||||||
|
|
||||||
|
databaseUpdate.push(new Promise(async (resolve) => {
|
||||||
|
// Equilize database tables
|
||||||
|
const handler = async (table, attributes) => {
|
||||||
|
const tableExist = await ORM.knex.schema.hasTable(table);
|
||||||
|
|
||||||
|
const getType = (attribute, name) => {
|
||||||
|
let type;
|
||||||
|
|
||||||
|
if (!attribute.type) {
|
||||||
|
// Add integer value if there is a relation
|
||||||
|
const relation = definition.associations.find((association) => {
|
||||||
|
return association.alias === name;
|
||||||
|
});
|
||||||
|
|
||||||
|
switch (relation.nature) {
|
||||||
|
case 'oneToOne':
|
||||||
|
case 'manyToOne':
|
||||||
|
type = definition.client === 'pg' ? 'integer' : 'int';
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
switch (attribute.type) {
|
||||||
|
case 'text':
|
||||||
|
case 'json':
|
||||||
|
type = 'text';
|
||||||
|
break;
|
||||||
|
case 'string':
|
||||||
|
case 'password':
|
||||||
|
case 'email':
|
||||||
|
type = 'varchar(255)';
|
||||||
|
break;
|
||||||
|
case 'integer':
|
||||||
|
case 'biginteger':
|
||||||
|
type = definition.client === 'pg' ? 'integer' : 'int';
|
||||||
|
break;
|
||||||
|
case 'float':
|
||||||
|
case 'decimal':
|
||||||
|
type = attribute.type;
|
||||||
|
break;
|
||||||
|
case 'date':
|
||||||
|
case 'time':
|
||||||
|
case 'datetime':
|
||||||
|
case 'timestamp':
|
||||||
|
type = definition.client === 'pg' ? 'timestamp with time zone' : 'timestamp DEFAULT CURRENT_TIMESTAMP';
|
||||||
|
break;
|
||||||
|
case 'timestampUpdate':
|
||||||
|
type = definition.client === 'pg' ? 'timestamp with time zone' : 'timestamp DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP';
|
||||||
|
break;
|
||||||
|
case 'boolean':
|
||||||
|
type = 'boolean';
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return type;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Apply field type of attributes definition
|
||||||
|
const generateColumns = (attrs, start) => {
|
||||||
|
return Object.keys(attrs).reduce((acc, attr) => {
|
||||||
|
const attribute = attributes[attr];
|
||||||
|
|
||||||
|
const type = getType(attribute, attr);
|
||||||
|
|
||||||
|
if (type) {
|
||||||
|
acc.push(`${quote}${attr}${quote} ${type}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
return acc;
|
||||||
|
}, start);
|
||||||
|
};
|
||||||
|
|
||||||
|
if (!tableExist) {
|
||||||
|
const columns = generateColumns(attributes, [`id ${definition.client === 'pg' ? 'SERIAL' : 'INT AUTO_INCREMENT'} NOT NULL PRIMARY KEY`]).join(',\n\r');
|
||||||
|
|
||||||
|
// Create table
|
||||||
|
await ORM.knex.raw(`
|
||||||
|
CREATE TABLE ${quote}${table}${quote} (
|
||||||
|
${columns}
|
||||||
|
)
|
||||||
|
`);
|
||||||
|
} else {
|
||||||
|
const columns = Object.keys(attributes);
|
||||||
|
|
||||||
|
// Fetch existing column
|
||||||
|
const columnsExist = await Promise.all(columns.map(attribute =>
|
||||||
|
ORM.knex.schema.hasColumn(table, attribute)
|
||||||
|
));
|
||||||
|
|
||||||
|
const columnsToAdd = {};
|
||||||
|
|
||||||
|
// Get columns to add
|
||||||
|
columnsExist.forEach((columnExist, index) => {
|
||||||
|
const attribute = attributes[columns[index]];
|
||||||
|
|
||||||
|
if (!columnExist) {
|
||||||
|
columnsToAdd[columns[index]] = attribute;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Generate and execute query to add missing column
|
||||||
|
if (Object.keys(columnsToAdd).length > 0) {
|
||||||
|
const columns = generateColumns(columnsToAdd, []);
|
||||||
|
const queries = columns.reduce((acc, attribute) => {
|
||||||
|
acc.push(`ALTER TABLE ${quote}${table}${quote} ADD ${attribute};`)
|
||||||
|
return acc;
|
||||||
|
}, []).join('\n\r');
|
||||||
|
|
||||||
|
await ORM.knex.raw(queries);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Execute query to update column type
|
||||||
|
await Promise.all(columns.map(attribute =>
|
||||||
|
new Promise(async (resolve) => {
|
||||||
|
const type = getType(attributes[attribute], attribute);
|
||||||
|
|
||||||
|
if (type) {
|
||||||
|
const changeType = definition.client === 'pg'
|
||||||
|
? `ALTER COLUMN ${quote}${attribute}${quote} TYPE ${type} USING ${quote}${attribute}${quote}::${type}`
|
||||||
|
: `CHANGE ${quote}${attribute}${quote} ${quote}${attribute}${quote} ${type} `;
|
||||||
|
|
||||||
|
const changeRequired = definition.client === 'pg'
|
||||||
|
? `ALTER COLUMN ${quote}${attribute}${quote} ${attributes[attribute].required ? 'SET' : 'DROP'} NOT NULL`
|
||||||
|
: `CHANGE ${quote}${attribute}${quote} ${quote}${attribute}${quote} ${type} ${attributes[attribute].required ? 'NOT' : ''} NULL`;
|
||||||
|
|
||||||
|
await ORM.knex.raw(`ALTER TABLE ${quote}${table}${quote} ${changeType}`);
|
||||||
|
await ORM.knex.raw(`ALTER TABLE ${quote}${table}${quote} ${changeRequired}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
resolve();
|
||||||
|
})
|
||||||
|
));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const quote = definition.client === 'pg' ? '"' : '`';
|
||||||
|
|
||||||
|
// Add created_at and updated_at field if timestamp option is true
|
||||||
|
if (loadedModel.hasTimestamps) {
|
||||||
|
definition.attributes['created_at'] = {
|
||||||
|
type: 'timestamp'
|
||||||
|
};
|
||||||
|
definition.attributes['updated_at'] = {
|
||||||
|
type: 'timestampUpdate'
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// Equilize tables
|
||||||
|
await handler(loadedModel.tableName, definition.attributes);
|
||||||
|
|
||||||
|
// Equilize polymorphic releations
|
||||||
|
const morphRelations = definition.associations.find((association) => {
|
||||||
|
return association.nature.toLowerCase().includes('morphto');
|
||||||
|
});
|
||||||
|
|
||||||
|
if (morphRelations) {
|
||||||
|
const attributes = {
|
||||||
|
[`${loadedModel.tableName}_id`]: {
|
||||||
|
type: 'integer'
|
||||||
|
},
|
||||||
|
[`${morphRelations.alias}_id`]: {
|
||||||
|
type: 'integer'
|
||||||
|
},
|
||||||
|
[`${morphRelations.alias}_type`]: {
|
||||||
|
type: 'text'
|
||||||
|
},
|
||||||
|
[definition.attributes[morphRelations.alias].filter]: {
|
||||||
|
type: 'text'
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
await handler(`${loadedModel.tableName}_morph`, attributes);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Equilize many to many releations
|
||||||
|
const manyRelations = definition.associations.find((association) => {
|
||||||
|
return association.nature === 'manyToMany';
|
||||||
|
});
|
||||||
|
|
||||||
|
if (manyRelations && manyRelations.dominant) {
|
||||||
|
const collection = manyRelations.plugin ?
|
||||||
|
strapi.plugins[manyRelations.plugin].models[manyRelations.collection]:
|
||||||
|
strapi.models[manyRelations.collection];
|
||||||
|
|
||||||
|
const attributes = {
|
||||||
|
[`${pluralize.singular(manyRelations.collection)}_id`]: {
|
||||||
|
type: 'integer'
|
||||||
|
},
|
||||||
|
[`${pluralize.singular(definition.globalId.toLowerCase())}_id`]: {
|
||||||
|
type: 'integer'
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const table = _.get(manyRelations, 'collectionName') ||
|
||||||
|
_.map(
|
||||||
|
_.sortBy(
|
||||||
|
[
|
||||||
|
collection.attributes[
|
||||||
|
manyRelations.via
|
||||||
|
],
|
||||||
|
manyRelations
|
||||||
|
],
|
||||||
|
'collection'
|
||||||
|
),
|
||||||
|
table => {
|
||||||
|
return _.snakeCase(
|
||||||
|
pluralize.plural(table.collection) +
|
||||||
|
' ' +
|
||||||
|
pluralize.plural(table.via)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
).join('__');
|
||||||
|
|
||||||
|
await handler(table, attributes);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Remove from attributes (auto handled by bookshlef and not displayed on ctb)
|
||||||
|
if (loadedModel.hasTimestamps) {
|
||||||
|
delete definition.attributes['created_at'];
|
||||||
|
delete definition.attributes['updated_at'];
|
||||||
|
}
|
||||||
|
|
||||||
|
resolve();
|
||||||
|
}));
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
strapi.log.error('Impossible to register the `' + model + '` model.');
|
strapi.log.error('Impossible to register the `' + model + '` model.');
|
||||||
strapi.log.error(err);
|
strapi.log.error(err);
|
||||||
@ -602,6 +831,8 @@ module.exports = function(strapi) {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
await Promise.all(databaseUpdate);
|
||||||
|
|
||||||
cb();
|
cb();
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|||||||
@ -4,6 +4,9 @@
|
|||||||
const execSync = require('child_process').execSync;
|
const execSync = require('child_process').execSync;
|
||||||
const path = require('path');
|
const path = require('path');
|
||||||
|
|
||||||
|
// Public node modules
|
||||||
|
const inquirer = require('inquirer');
|
||||||
|
|
||||||
// Logger.
|
// Logger.
|
||||||
const logger = require('strapi-utils').logger;
|
const logger = require('strapi-utils').logger;
|
||||||
|
|
||||||
@ -17,15 +20,45 @@ module.exports = (scope, success, error) => {
|
|||||||
|
|
||||||
knex.raw('select 1+1 as result').then(() => {
|
knex.raw('select 1+1 as result').then(() => {
|
||||||
logger.info('The app has been connected to the database successfully');
|
logger.info('The app has been connected to the database successfully');
|
||||||
|
|
||||||
|
knex.raw(scope.client.database === 'postgres' ? "SELECT tablename FROM pg_tables WHERE schemaname='public'" : 'SELECT * FROM information_schema.tables').then((tables) => {
|
||||||
knex.destroy();
|
knex.destroy();
|
||||||
|
|
||||||
|
const next = () => {
|
||||||
execSync(`rm -r "${scope.tmpPath}"`);
|
execSync(`rm -r "${scope.tmpPath}"`);
|
||||||
|
|
||||||
logger.info('Copying the dashboard...');
|
logger.info('Copying the dashboard...');
|
||||||
|
|
||||||
success();
|
success();
|
||||||
|
};
|
||||||
|
|
||||||
|
if (tables.rows.length !== 0) {
|
||||||
|
logger.warn('It seems that your database is not empty. Be aware that Strapi is going to automatically creates tables & columns, and might update columns which can corrupt data or cause data loss.');
|
||||||
|
|
||||||
|
inquirer.prompt([{
|
||||||
|
type: 'confirm',
|
||||||
|
prefix: '',
|
||||||
|
name: 'confirm',
|
||||||
|
message: `Are you sure you want to continue with the ${scope.database.settings.database} database:`,
|
||||||
|
}])
|
||||||
|
.then(({confirm}) => {
|
||||||
|
if (confirm) {
|
||||||
|
next();
|
||||||
|
} else {
|
||||||
|
error();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
next();
|
||||||
|
}
|
||||||
|
});
|
||||||
})
|
})
|
||||||
.catch(() => {
|
.catch((err) => {
|
||||||
logger.warn('Database connection has failed! Make sure your database is running.');
|
if (err.sql) {
|
||||||
|
logger.warn('Server connection has failed! Make sure your database server is running.');
|
||||||
|
} else {
|
||||||
|
logger.warn(`Database connection has failed! Make sure your "${scope.database.settings.database}" database exist.`);
|
||||||
|
}
|
||||||
error();
|
error();
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|||||||
@ -17,6 +17,7 @@
|
|||||||
"main": "./lib",
|
"main": "./lib",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"bookshelf": "^0.12.1",
|
"bookshelf": "^0.12.1",
|
||||||
|
"inquirer": "^5.2.0",
|
||||||
"lodash": "^4.17.4",
|
"lodash": "^4.17.4",
|
||||||
"pluralize": "^6.0.0",
|
"pluralize": "^6.0.0",
|
||||||
"strapi-knex": "3.0.0-alpha.12",
|
"strapi-knex": "3.0.0-alpha.12",
|
||||||
|
|||||||
@ -10,11 +10,12 @@
|
|||||||
"port": "${process.env.DATABASE_PORT || 27017}",
|
"port": "${process.env.DATABASE_PORT || 27017}",
|
||||||
"database": "${process.env.DATABASE_NAME || 'strapi-production'}",
|
"database": "${process.env.DATABASE_NAME || 'strapi-production'}",
|
||||||
"username": "${process.env.DATABASE_USERNAME || ''}",
|
"username": "${process.env.DATABASE_USERNAME || ''}",
|
||||||
"password": "${process.env.DATABASE_PASSWORD || ''}",
|
"password": "${process.env.DATABASE_PASSWORD || ''}"
|
||||||
|
},
|
||||||
|
"options": {
|
||||||
"ssl": "${process.env.DATABASE_SSL || false}",
|
"ssl": "${process.env.DATABASE_SSL || false}",
|
||||||
"authenticationDatabase": "${process.env.DATABASE_AUTHENTICATION_DATABASE || ''}"
|
"authenticationDatabase": "${process.env.DATABASE_AUTHENTICATION_DATABASE || ''}"
|
||||||
},
|
}
|
||||||
"options": {}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -10,11 +10,12 @@
|
|||||||
"port": "${process.env.DATABASE_PORT || 27017}",
|
"port": "${process.env.DATABASE_PORT || 27017}",
|
||||||
"database": "${process.env.DATABASE_NAME || 'strapi-staging'}",
|
"database": "${process.env.DATABASE_NAME || 'strapi-staging'}",
|
||||||
"username": "${process.env.DATABASE_USERNAME || ''}",
|
"username": "${process.env.DATABASE_USERNAME || ''}",
|
||||||
"password": "${process.env.DATABASE_PASSWORD || ''}",
|
"password": "${process.env.DATABASE_PASSWORD || ''}"
|
||||||
|
},
|
||||||
|
"options": {
|
||||||
"ssl": "${process.env.DATABASE_SSL || false}",
|
"ssl": "${process.env.DATABASE_SSL || false}",
|
||||||
"authenticationDatabase": "${process.env.DATABASE_AUTHENTICATION_DATABASE || ''}"
|
"authenticationDatabase": "${process.env.DATABASE_AUTHENTICATION_DATABASE || ''}"
|
||||||
},
|
}
|
||||||
"options": {}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -83,21 +83,6 @@ module.exports = (scope, cb) => {
|
|||||||
connector: 'strapi-bookshelf',
|
connector: 'strapi-bookshelf',
|
||||||
module: 'mysql'
|
module: 'mysql'
|
||||||
}
|
}
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'Sqlite3',
|
|
||||||
value: {
|
|
||||||
database: 'sqlite3',
|
|
||||||
connector: 'strapi-bookshelf',
|
|
||||||
module: 'sqlite3'
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'Redis',
|
|
||||||
value: {
|
|
||||||
database: 'redis',
|
|
||||||
connector: 'strapi-redis'
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
];
|
];
|
||||||
|
|
||||||
@ -169,9 +154,7 @@ module.exports = (scope, cb) => {
|
|||||||
const ports = {
|
const ports = {
|
||||||
mongo: 27017,
|
mongo: 27017,
|
||||||
postgres: 5432,
|
postgres: 5432,
|
||||||
mysql: 3306,
|
mysql: 3306
|
||||||
sqlite3: 1433,
|
|
||||||
redis: 6379
|
|
||||||
};
|
};
|
||||||
|
|
||||||
return ports[scope.client.database];
|
return ports[scope.client.database];
|
||||||
@ -212,7 +195,6 @@ module.exports = (scope, cb) => {
|
|||||||
}
|
}
|
||||||
])
|
])
|
||||||
.then(answers => {
|
.then(answers => {
|
||||||
|
|
||||||
if (hasDatabaseConfig) {
|
if (hasDatabaseConfig) {
|
||||||
answers = _.omit(scope.database.settings, ['client'])
|
answers = _.omit(scope.database.settings, ['client'])
|
||||||
}
|
}
|
||||||
@ -222,8 +204,8 @@ module.exports = (scope, cb) => {
|
|||||||
scope.database.settings.database = answers.database;
|
scope.database.settings.database = answers.database;
|
||||||
scope.database.settings.username = answers.username;
|
scope.database.settings.username = answers.username;
|
||||||
scope.database.settings.password = answers.password;
|
scope.database.settings.password = answers.password;
|
||||||
scope.database.settings.authenticationDatabase = answers.authenticationDatabase;
|
scope.database.options.authenticationDatabase = answers.authenticationDatabase;
|
||||||
scope.database.settings.ssl = answers.ssl;
|
scope.database.options.ssl = _.toString(answers.ssl) === 'true';
|
||||||
|
|
||||||
logger.info('Testing database connection...');
|
logger.info('Testing database connection...');
|
||||||
|
|
||||||
|
|||||||
@ -0,0 +1,22 @@
|
|||||||
|
const path = require('path');
|
||||||
|
const shell = require('shelljs');
|
||||||
|
|
||||||
|
const pwd = shell.pwd();
|
||||||
|
const isDevelopmentMode = path.resolve(pwd.stdout).indexOf('strapi-admin') !== -1;
|
||||||
|
const appPath = isDevelopmentMode ? path.resolve(process.env.PWD, '..') : path.resolve(pwd.stdout, '..');
|
||||||
|
const isSetup = path.resolve(process.env.PWD, '..', '..') === path.resolve(process.env.INIT_CWD);
|
||||||
|
|
||||||
|
// Load the app configurations only when :
|
||||||
|
// - starting the app in dev mode
|
||||||
|
// - building the admin from an existing app (`npm run setup` at the root of the project)
|
||||||
|
if (!isSetup) {
|
||||||
|
const strapi = require(path.join(appPath, 'node_modules', 'strapi'));
|
||||||
|
strapi.config.appPath = appPath;
|
||||||
|
strapi.log.level = 'silent';
|
||||||
|
|
||||||
|
(async () => {
|
||||||
|
await strapi.load({
|
||||||
|
environment: process.env.NODE_ENV,
|
||||||
|
});
|
||||||
|
})();
|
||||||
|
}
|
||||||
@ -12,6 +12,8 @@ const pkg = require(path.resolve(process.cwd(), 'package.json'));
|
|||||||
const pluginId = pkg.name.replace(/^strapi-/i, '');
|
const pluginId = pkg.name.replace(/^strapi-/i, '');
|
||||||
const isAdmin = process.env.IS_ADMIN === 'true';
|
const isAdmin = process.env.IS_ADMIN === 'true';
|
||||||
|
|
||||||
|
const ExtractTextPlugin = require('extract-text-webpack-plugin');
|
||||||
|
|
||||||
const appPath = (() => {
|
const appPath = (() => {
|
||||||
if (process.env.APP_PATH) {
|
if (process.env.APP_PATH) {
|
||||||
return process.env.APP_PATH;
|
return process.env.APP_PATH;
|
||||||
@ -28,25 +30,6 @@ const adminPath = (() => {
|
|||||||
return path.resolve(process.env.PWD);
|
return path.resolve(process.env.PWD);
|
||||||
})();
|
})();
|
||||||
|
|
||||||
if (!isSetup) {
|
|
||||||
try {
|
|
||||||
// Load app' configurations to update `plugins.json` automatically.
|
|
||||||
const strapi = require(path.join(appPath, 'node_modules', 'strapi'));
|
|
||||||
|
|
||||||
strapi.config.appPath = appPath;
|
|
||||||
strapi.log.level = 'silent';
|
|
||||||
|
|
||||||
(async () => {
|
|
||||||
await strapi.load({
|
|
||||||
environment: process.env.NODE_ENV,
|
|
||||||
});
|
|
||||||
})();
|
|
||||||
} catch (e) {
|
|
||||||
console.log(e);
|
|
||||||
throw new Error(`You need to start the WebPack server from the /admin or /plugins/**/admin directories in a Strapi's project.`);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Define remote and backend URLs.
|
// Define remote and backend URLs.
|
||||||
const URLs = {
|
const URLs = {
|
||||||
host: '/admin',
|
host: '/admin',
|
||||||
@ -100,7 +83,9 @@ if (process.env.npm_lifecycle_event === 'start') {
|
|||||||
plugins.exist = true;
|
plugins.exist = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Read `plugins` directory and check if the plugin comes with an UI.
|
// Read `plugins` directory and check if the plugin comes with an UI (it has an App container).
|
||||||
|
// If we don't do this check webpack expects the plugin to have a containers/App/reducer.js to create
|
||||||
|
// the plugin's store (redux).
|
||||||
plugins.src = isAdmin && !plugins.exist ? fs.readdirSync(path.resolve(appPath, 'plugins')).filter(x => {
|
plugins.src = isAdmin && !plugins.exist ? fs.readdirSync(path.resolve(appPath, 'plugins')).filter(x => {
|
||||||
let hasAdminFolder;
|
let hasAdminFolder;
|
||||||
|
|
||||||
@ -121,16 +106,39 @@ if (process.env.npm_lifecycle_event === 'start') {
|
|||||||
}, {});
|
}, {});
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = (options) => ({
|
// Tell webpack to use a loader only for those files
|
||||||
|
const foldersToInclude = [path.join(adminPath, 'admin', 'src')]
|
||||||
|
.concat(plugins.src.reduce((acc, current) => {
|
||||||
|
acc.push(path.resolve(appPath, 'plugins', current, 'admin', 'src'), plugins.folders[current]);
|
||||||
|
|
||||||
|
return acc;
|
||||||
|
}, []))
|
||||||
|
.concat([path.join(adminPath, 'node_modules', 'strapi-helper-plugin', 'lib', 'src')]);
|
||||||
|
|
||||||
|
module.exports = (options) => {
|
||||||
|
// The disable option is only for production
|
||||||
|
// Config from https://github.com/facebook/create-react-app/blob/next/packages/react-scripts/config/webpack.config.prod.js
|
||||||
|
const extractSass = new ExtractTextPlugin({
|
||||||
|
filename: '[name].[contenthash].css',
|
||||||
|
disable: options.disableExtractTextPlugin || true,
|
||||||
|
});
|
||||||
|
|
||||||
|
return {
|
||||||
entry: options.entry,
|
entry: options.entry,
|
||||||
output: Object.assign({ // Compile into js/build.js
|
output: Object.assign({ // Compile into js/build.js
|
||||||
path: path.join(adminPath, 'admin', 'build'),
|
path: path.join(adminPath, 'admin', 'build'),
|
||||||
}, options.output), // Merge with env dependent settings
|
}, options.output), // Merge with env dependent settings
|
||||||
module: {
|
module: {
|
||||||
loaders: [{
|
rules: [ // TODO: add eslint formatter
|
||||||
|
{
|
||||||
|
// "oneOf" will traverse all following loaders until one will
|
||||||
|
// match the requirements. When no loader matches it will fall
|
||||||
|
// back to the "file" loader at the end of the loader list.
|
||||||
|
oneOf: [
|
||||||
|
{
|
||||||
test: /\.js$/, // Transform all .js files required somewhere with Babel,
|
test: /\.js$/, // Transform all .js files required somewhere with Babel,
|
||||||
use: {
|
loader: require.resolve('babel-loader'),
|
||||||
loader: 'babel-loader',
|
include: foldersToInclude,
|
||||||
options: {
|
options: {
|
||||||
presets: options.babelPresets,
|
presets: options.babelPresets,
|
||||||
env: {
|
env: {
|
||||||
@ -155,61 +163,82 @@ module.exports = (options) => ({
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
include: [path.join(adminPath, 'admin', 'src')]
|
// The notation here is somewhat confusing.
|
||||||
.concat(plugins.src.reduce((acc, current) => {
|
// "postcss" loader applies autoprefixer to our CSS.
|
||||||
acc.push(path.resolve(appPath, 'plugins', current, 'admin', 'src'), plugins.folders[current]);
|
// "css" loader resolves paths in CSS and adds assets as dependencies.
|
||||||
|
// "style" loader normally turns CSS into JS modules injecting <style>,
|
||||||
return acc;
|
// but unlike in development configuration, we do something different.
|
||||||
}, []))
|
// `ExtractTextPlugin` first applies the "postcss" and "css" loaders
|
||||||
.concat([path.join(adminPath, 'node_modules', 'strapi-helper-plugin', 'lib', 'src')]),
|
// (second argument), then grabs the result CSS and puts it into a
|
||||||
}, {
|
// separate file in our build process. This way we actually ship
|
||||||
// Transform our own .scss files
|
// a single CSS file in production instead of JS code injecting <style>
|
||||||
test: /\.scss$/,
|
// tags. If you use code splitting, however, any async bundles will still
|
||||||
use: [{
|
// use the "style" loader inside the async code so CSS from them won't be
|
||||||
loader: 'style-loader',
|
// in the main CSS file.
|
||||||
}, {
|
{
|
||||||
loader: 'css-loader',
|
test: /\.css$/,
|
||||||
|
include: /node_modules/,
|
||||||
|
use: extractSass.extract({
|
||||||
|
fallback: require.resolve('style-loader'),
|
||||||
|
use: [
|
||||||
|
{
|
||||||
|
loader: require.resolve('css-loader'),
|
||||||
options: {
|
options: {
|
||||||
localIdentName: `${pluginId}[local]__[path][name]__[hash:base64:5]`,
|
|
||||||
modules: true,
|
|
||||||
importLoaders: 1,
|
|
||||||
sourceMap: true,
|
|
||||||
minimize: process.env.NODE_ENV === 'production',
|
minimize: process.env.NODE_ENV === 'production',
|
||||||
|
sourceMap: false,
|
||||||
},
|
},
|
||||||
}, {
|
},
|
||||||
loader: 'postcss-loader',
|
{
|
||||||
|
loader: require.resolve('postcss-loader'),
|
||||||
options: {
|
options: {
|
||||||
config: {
|
config: {
|
||||||
path: path.resolve(__dirname, '..', 'postcss', 'postcss.config.js'),
|
path: path.resolve(__dirname, '..', 'postcss', 'postcss.config.js'),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}, {
|
|
||||||
loader: 'sass-loader',
|
|
||||||
}],
|
|
||||||
}, {
|
|
||||||
// Do not transform vendor's CSS with CSS-modules
|
|
||||||
// The point is that they remain in global scope.
|
|
||||||
// Since we require these CSS files in our JS or CSS files,
|
|
||||||
// they will be a part of our compilation either way.
|
|
||||||
// So, no need for ExtractTextPlugin here.
|
|
||||||
test: /\.css$/,
|
|
||||||
include: /node_modules/,
|
|
||||||
loaders: ['style-loader', {
|
|
||||||
loader: 'css-loader',
|
|
||||||
options: {
|
|
||||||
minimize: process.env.NODE_ENV === 'production',
|
|
||||||
sourceMap: true,
|
|
||||||
},
|
},
|
||||||
}],
|
],
|
||||||
}, {
|
}),
|
||||||
test: /\.(eot|svg|ttf|woff|woff2)$/,
|
},
|
||||||
loader: 'file-loader',
|
{
|
||||||
}, {
|
test: /\.scss$/,
|
||||||
|
include: foldersToInclude,
|
||||||
|
use: extractSass.extract({
|
||||||
|
use: [
|
||||||
|
{
|
||||||
|
loader: require.resolve('css-loader'),
|
||||||
|
options: {
|
||||||
|
localIdentName: `${pluginId}[local]__[path][name]__[hash:base64:5]`,
|
||||||
|
modules: true,
|
||||||
|
importLoaders: 1,
|
||||||
|
sourceMap: false,
|
||||||
|
minimize: process.env.NODE_ENV === 'production',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
loader: require.resolve('postcss-loader'),
|
||||||
|
options: {
|
||||||
|
config: {
|
||||||
|
path: path.resolve(__dirname, '..', 'postcss', 'postcss.config.js'),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
loader: 'sass-loader',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
fallback: require.resolve('style-loader'),
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
test: /\.(eot|svg|otf|ttf|woff|woff2)$/,
|
||||||
|
use: 'file-loader',
|
||||||
|
},
|
||||||
|
{
|
||||||
test: /\.(jpg|png|gif)$/,
|
test: /\.(jpg|png|gif)$/,
|
||||||
loaders: [
|
loaders: [
|
||||||
'file-loader',
|
require.resolve('file-loader'),
|
||||||
{
|
{
|
||||||
loader: 'image-webpack-loader',
|
loader: require.resolve('image-webpack-loader'),
|
||||||
query: {
|
query: {
|
||||||
mozjpeg: {
|
mozjpeg: {
|
||||||
progressive: true,
|
progressive: true,
|
||||||
@ -227,13 +256,22 @@ module.exports = (options) => ({
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
}, {
|
},
|
||||||
|
{
|
||||||
test: /\.html$/,
|
test: /\.html$/,
|
||||||
loader: 'html-loader',
|
include: [path.join(adminPath, 'admin', 'src')],
|
||||||
}, {
|
use: require.resolve('html-loader'),
|
||||||
|
},
|
||||||
|
{
|
||||||
test: /\.(mp4|webm)$/,
|
test: /\.(mp4|webm)$/,
|
||||||
loader: 'url-loader?limit=10000',
|
loader: require.resolve('url-loader'),
|
||||||
}],
|
options: {
|
||||||
|
limit: 10000,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
},
|
},
|
||||||
plugins: [
|
plugins: [
|
||||||
new webpack.ProvidePlugin({
|
new webpack.ProvidePlugin({
|
||||||
@ -253,6 +291,7 @@ module.exports = (options) => ({
|
|||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
new webpack.NamedModulesPlugin(),
|
new webpack.NamedModulesPlugin(),
|
||||||
|
extractSass,
|
||||||
].concat(options.plugins),
|
].concat(options.plugins),
|
||||||
resolve: {
|
resolve: {
|
||||||
modules: [
|
modules: [
|
||||||
@ -283,4 +322,5 @@ module.exports = (options) => ({
|
|||||||
},
|
},
|
||||||
devtool: options.devtool,
|
devtool: options.devtool,
|
||||||
target: 'web', // Make web variables accessible to webpack, e.g. window,
|
target: 'web', // Make web variables accessible to webpack, e.g. window,
|
||||||
});
|
};
|
||||||
|
};
|
||||||
|
|||||||
@ -49,6 +49,7 @@ if (process.env.npm_lifecycle_event === 'start') {
|
|||||||
plugins.src = process.env.IS_ADMIN === 'true' && !plugins.exist ? fs.readdirSync(path.resolve(appPath, 'plugins')).filter(x => {
|
plugins.src = process.env.IS_ADMIN === 'true' && !plugins.exist ? fs.readdirSync(path.resolve(appPath, 'plugins')).filter(x => {
|
||||||
let hasAdminFolder;
|
let hasAdminFolder;
|
||||||
|
|
||||||
|
// Don't inject the plugins that don't have an admin into the app
|
||||||
try {
|
try {
|
||||||
fs.accessSync(path.resolve(appPath, 'plugins', x, 'admin', 'src', 'containers', 'App'));
|
fs.accessSync(path.resolve(appPath, 'plugins', x, 'admin', 'src', 'containers', 'App'));
|
||||||
hasAdminFolder = true;
|
hasAdminFolder = true;
|
||||||
|
|||||||
@ -3,7 +3,6 @@ const path = require('path');
|
|||||||
const _ = require('lodash');
|
const _ = require('lodash');
|
||||||
|
|
||||||
const HtmlWebpackPlugin = require('html-webpack-plugin');
|
const HtmlWebpackPlugin = require('html-webpack-plugin');
|
||||||
const ExtractTextPlugin = require('extract-text-webpack-plugin');
|
|
||||||
const cssnext = require('postcss-cssnext');
|
const cssnext = require('postcss-cssnext');
|
||||||
const postcssFocus = require('postcss-focus');
|
const postcssFocus = require('postcss-focus');
|
||||||
const postcssReporter = require('postcss-reporter');
|
const postcssReporter = require('postcss-reporter');
|
||||||
@ -14,10 +13,6 @@ const CopyWebpackPlugin = require('copy-webpack-plugin');
|
|||||||
|
|
||||||
const base = require('./webpack.base.babel');
|
const base = require('./webpack.base.babel');
|
||||||
|
|
||||||
// const pkg = require(path.resolve(process.cwd(), 'package.json'));
|
|
||||||
// const pluginId = pkg.name.replace(/^strapi-plugin-/i, '');
|
|
||||||
// const dllPlugin = pkg.dllPlugin;
|
|
||||||
|
|
||||||
const isAdmin = process.env.IS_ADMIN === 'true';
|
const isAdmin = process.env.IS_ADMIN === 'true';
|
||||||
const isSetup = path.resolve(process.env.PWD, '..', '..') === path.resolve(process.env.INIT_CWD);
|
const isSetup = path.resolve(process.env.PWD, '..', '..') === path.resolve(process.env.INIT_CWD);
|
||||||
const appPath = (() => {
|
const appPath = (() => {
|
||||||
@ -105,7 +100,6 @@ if (isAdmin) {
|
|||||||
chunks: ['main'],
|
chunks: ['main'],
|
||||||
inject: true,
|
inject: true,
|
||||||
}));
|
}));
|
||||||
plugins.push(new ExtractTextPlugin('[name].[contenthash].css'));
|
|
||||||
plugins.push(new AddAssetHtmlPlugin({
|
plugins.push(new AddAssetHtmlPlugin({
|
||||||
filepath: path.resolve(__dirname, 'dist/*.dll.js'),
|
filepath: path.resolve(__dirname, 'dist/*.dll.js'),
|
||||||
}));
|
}));
|
||||||
@ -180,4 +174,5 @@ module.exports = base({
|
|||||||
},
|
},
|
||||||
|
|
||||||
devtool: 'cheap-module-source-map',
|
devtool: 'cheap-module-source-map',
|
||||||
|
disableExtractTextPlugin: false,
|
||||||
});
|
});
|
||||||
|
|||||||
@ -7,7 +7,7 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import moment from 'moment';
|
import moment from 'moment';
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
// import DateTimeStyle from 'react-datetime/css/react-datetime.css';
|
import DateTimeStyle from 'react-datetime/css/react-datetime.css'; /* eslint-disable-line no-unused-vars */
|
||||||
import DateTime from 'react-datetime';
|
import DateTime from 'react-datetime';
|
||||||
import { FormattedMessage } from 'react-intl';
|
import { FormattedMessage } from 'react-intl';
|
||||||
import { isEmpty, isObject } from 'lodash';
|
import { isEmpty, isObject } from 'lodash';
|
||||||
|
|||||||
@ -590,22 +590,40 @@ class Wysiwyg extends React.Component {
|
|||||||
'X-Forwarded-Host': 'strapi',
|
'X-Forwarded-Host': 'strapi',
|
||||||
};
|
};
|
||||||
|
|
||||||
|
let newEditorState = this.getEditorState();
|
||||||
|
|
||||||
|
const nextBlocks = getNextBlocksList(newEditorState, this.getSelection().getStartKey());
|
||||||
|
// Loop to update each block after the inserted li
|
||||||
|
nextBlocks.map((block, index) => {
|
||||||
|
// Update the current block
|
||||||
|
const nextBlockText = index === 0 ? `![Uploading ${files[0].name}]()` : nextBlocks.get(index - 1).getText();
|
||||||
|
const newBlock = createNewBlock(nextBlockText, 'unstyled', block.getKey());
|
||||||
|
// Update the contentState
|
||||||
const newContentState = this.createNewContentStateFromBlock(
|
const newContentState = this.createNewContentStateFromBlock(
|
||||||
createNewBlock(`![Uploading ${files[0].name}]()`),
|
newBlock,
|
||||||
|
newEditorState.getCurrentContent(),
|
||||||
);
|
);
|
||||||
const newEditorState = EditorState.push(this.getEditorState(), newContentState);
|
newEditorState = EditorState.push(newEditorState, newContentState);
|
||||||
this.setState({ editorState: newEditorState });
|
});
|
||||||
|
|
||||||
|
const offset = `![Uploading ${files[0].name}]()`.length;
|
||||||
|
const updatedSelection = updateSelection(this.getSelection(), nextBlocks, offset);
|
||||||
|
this.setState({ editorState: EditorState.acceptSelection(newEditorState, updatedSelection) });
|
||||||
|
|
||||||
return request('/upload', { method: 'POST', headers, body: formData }, false, false)
|
return request('/upload', { method: 'POST', headers, body: formData }, false, false)
|
||||||
.then(response => {
|
.then(response => {
|
||||||
const lastBlock = this.getEditorState()
|
const nextBlockKey = newEditorState
|
||||||
.getCurrentContent()
|
.getCurrentContent()
|
||||||
.getLastBlock();
|
.getKeyAfter(newEditorState.getSelection().getStartKey());
|
||||||
|
const content = ``;
|
||||||
const newContentState = this.createNewContentStateFromBlock(
|
const newContentState = this.createNewContentStateFromBlock(
|
||||||
createNewBlock(``, 'unstyled', lastBlock.getKey()),
|
createNewBlock(content, 'unstyled', nextBlockKey),
|
||||||
);
|
);
|
||||||
const newEditorState = EditorState.push(this.getEditorState(), newContentState);
|
|
||||||
this.setState({ editorState: EditorState.moveFocusToEnd(newEditorState) });
|
newEditorState = EditorState.push(newEditorState, newContentState);
|
||||||
|
const updatedSelection = updateSelection(this.getSelection(), nextBlocks, 2);
|
||||||
|
|
||||||
|
this.setState({ editorState: EditorState.acceptSelection(newEditorState, updatedSelection) });
|
||||||
this.sendData(newEditorState);
|
this.sendData(newEditorState);
|
||||||
})
|
})
|
||||||
.catch(() => {
|
.catch(() => {
|
||||||
|
|||||||
@ -43,19 +43,24 @@ module.exports = function (strapi) {
|
|||||||
initialize: cb => {
|
initialize: cb => {
|
||||||
_.forEach(_.pickBy(strapi.config.connections, {connector: 'strapi-mongoose'}), (connection, connectionName) => {
|
_.forEach(_.pickBy(strapi.config.connections, {connector: 'strapi-mongoose'}), (connection, connectionName) => {
|
||||||
const instance = new Mongoose();
|
const instance = new Mongoose();
|
||||||
const { uri, host, port, username, password, database, authenticationDatabase, ssl } = _.defaults(connection.settings, strapi.config.hook.settings.mongoose);
|
const { uri, host, port, username, password, database } = _.defaults(connection.settings, strapi.config.hook.settings.mongoose);
|
||||||
|
const { authenticationDatabase, ssl } = _.defaults(connection.options, strapi.config.hook.settings.mongoose);
|
||||||
|
|
||||||
// Connect to mongo database
|
// Connect to mongo database
|
||||||
const connectOptions = {}
|
const connectOptions = {}
|
||||||
|
|
||||||
if (!_.isEmpty(username)) {
|
if (!_.isEmpty(username)) {
|
||||||
connectOptions.user = username
|
connectOptions.user = username;
|
||||||
|
|
||||||
if (!_.isEmpty(password)) {
|
if (!_.isEmpty(password)) {
|
||||||
connectOptions.pass = password
|
connectOptions.pass = password;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!_.isEmpty(authenticationDatabase)) {
|
if (!_.isEmpty(authenticationDatabase)) {
|
||||||
connectOptions.authSource = authenticationDatabase;
|
connectOptions.authSource = authenticationDatabase;
|
||||||
}
|
}
|
||||||
|
|
||||||
connectOptions.ssl = ssl === true || ssl === 'true';
|
connectOptions.ssl = ssl === true || ssl === 'true';
|
||||||
|
|
||||||
instance.connect(uri || `mongodb://${host}:${port}/${database}`, connectOptions);
|
instance.connect(uri || `mongodb://${host}:${port}/${database}`, connectOptions);
|
||||||
|
|||||||
@ -10,18 +10,27 @@ const logger = require('strapi-utils').logger;
|
|||||||
module.exports = (scope, success, error) => {
|
module.exports = (scope, success, error) => {
|
||||||
const Mongoose = require(path.resolve(`${scope.tmpPath}/node_modules/mongoose`));
|
const Mongoose = require(path.resolve(`${scope.tmpPath}/node_modules/mongoose`));
|
||||||
|
|
||||||
const { username, password, authenticationDatabase, ssl } = scope.database.settings
|
const { username, password } = scope.database.settings;
|
||||||
const connectOptions = {}
|
const { authenticationDatabase, ssl } = scope.database.options;
|
||||||
|
|
||||||
|
const connectOptions = {};
|
||||||
|
|
||||||
if (username) {
|
if (username) {
|
||||||
connectOptions.user = username
|
connectOptions.user = username;
|
||||||
|
|
||||||
if (password) {
|
if (password) {
|
||||||
connectOptions.pass = password
|
connectOptions.pass = password;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (authenticationDatabase) {
|
if (authenticationDatabase) {
|
||||||
connectOptions.authSource = authenticationDatabase;
|
connectOptions.authSource = authenticationDatabase;
|
||||||
}
|
}
|
||||||
connectOptions.ssl = ssl ? true : false
|
|
||||||
|
connectOptions.ssl = ssl ? true : false;
|
||||||
|
|
||||||
|
console.log(connectOptions);
|
||||||
|
|
||||||
Mongoose.connect(`mongodb://${scope.database.settings.host}:${scope.database.settings.port}/${scope.database.settings.database}`, connectOptions, function (err) {
|
Mongoose.connect(`mongodb://${scope.database.settings.host}:${scope.database.settings.port}/${scope.database.settings.database}`, connectOptions, function (err) {
|
||||||
if (err) {
|
if (err) {
|
||||||
logger.warn('Database connection has failed! Make sure your database is running.');
|
logger.warn('Database connection has failed! Make sure your database is running.');
|
||||||
|
|||||||
@ -16,7 +16,7 @@
|
|||||||
"main": "./lib",
|
"main": "./lib",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"lodash": "^4.17.4",
|
"lodash": "^4.17.4",
|
||||||
"mongoose": "^5.0.15",
|
"mongoose": "^5.0.16",
|
||||||
"mongoose-float": "^1.0.2",
|
"mongoose-float": "^1.0.2",
|
||||||
"pluralize": "^6.0.0",
|
"pluralize": "^6.0.0",
|
||||||
"strapi-utils": "3.0.0-alpha.12"
|
"strapi-utils": "3.0.0-alpha.12"
|
||||||
|
|||||||
@ -78,7 +78,7 @@ module.exports = {
|
|||||||
return acc;
|
return acc;
|
||||||
}, {});
|
}, {});
|
||||||
|
|
||||||
const entry = await this
|
const request = await this
|
||||||
.forge(values)
|
.forge(values)
|
||||||
.save()
|
.save()
|
||||||
.catch((err) => {
|
.catch((err) => {
|
||||||
@ -90,11 +90,13 @@ module.exports = {
|
|||||||
throw err;
|
throw err;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const entry = request.toJSON ? request.toJSON() : request;
|
||||||
|
|
||||||
return module.exports.update.call(this, {
|
return module.exports.update.call(this, {
|
||||||
[this.primaryKey]: entry[this.primaryKey],
|
[this.primaryKey]: entry[this.primaryKey],
|
||||||
values: _.merge({
|
values: _.assign({
|
||||||
id: entry[this.primaryKey]
|
id: entry[this.primaryKey]
|
||||||
}, params.values)
|
}, params.values, entry)
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
@ -167,9 +169,7 @@ module.exports = {
|
|||||||
case 'oneToMany':
|
case 'oneToMany':
|
||||||
case 'manyToOne':
|
case 'manyToOne':
|
||||||
case 'manyToMany':
|
case 'manyToMany':
|
||||||
if (association.nature === 'manyToMany' && details.dominant === true) {
|
if (response[current] && _.isArray(response[current]) && current !== 'id') {
|
||||||
acc[current] = params.values[current];
|
|
||||||
} else if (response[current] && _.isArray(response[current]) && current !== 'id') {
|
|
||||||
// Records to add in the relation.
|
// Records to add in the relation.
|
||||||
const toAdd = _.differenceWith(params.values[current], response[current], (a, b) =>
|
const toAdd = _.differenceWith(params.values[current], response[current], (a, b) =>
|
||||||
a[this.primaryKey].toString() === b[this.primaryKey].toString()
|
a[this.primaryKey].toString() === b[this.primaryKey].toString()
|
||||||
|
|||||||
@ -35,7 +35,7 @@ module.exports = {
|
|||||||
return acc;
|
return acc;
|
||||||
}, {});
|
}, {});
|
||||||
|
|
||||||
const entry = await this.create(values)
|
const request = await this.create(values)
|
||||||
.catch((err) => {
|
.catch((err) => {
|
||||||
const message = err.message.split('index:');
|
const message = err.message.split('index:');
|
||||||
const field = _.words(_.last(message).split('_')[0]);
|
const field = _.words(_.last(message).split('_')[0]);
|
||||||
@ -44,11 +44,13 @@ module.exports = {
|
|||||||
throw error;
|
throw error;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const entry = request.toJSON ? request.toJSON() : request;
|
||||||
|
|
||||||
return module.exports.update.call(this, {
|
return module.exports.update.call(this, {
|
||||||
[this.primaryKey]: entry[this.primaryKey],
|
[this.primaryKey]: entry[this.primaryKey],
|
||||||
values: _.merge({
|
values: _.assign({
|
||||||
id: entry[this.primaryKey]
|
id: entry[this.primaryKey]
|
||||||
}, params.values)
|
}, params.values, entry)
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|||||||
@ -81,7 +81,9 @@ function formReducer(state = initialState, action) {
|
|||||||
case RESET_FORM_ERRORS:
|
case RESET_FORM_ERRORS:
|
||||||
return state.set('formErrors', List());
|
return state.set('formErrors', List());
|
||||||
case RESET_IS_FORM_SET:
|
case RESET_IS_FORM_SET:
|
||||||
return state.set('isFormSet', false);
|
return state
|
||||||
|
.set('isFormSet', false)
|
||||||
|
.update('modifiedData', () => Map({}));
|
||||||
case SET_ATTRIBUTE_FORM: {
|
case SET_ATTRIBUTE_FORM: {
|
||||||
if (state.get('isFormSet')) {
|
if (state.get('isFormSet')) {
|
||||||
return state
|
return state
|
||||||
|
|||||||
@ -4,7 +4,8 @@ export default function checkAttributeValidations(errors) {
|
|||||||
|
|
||||||
const attributeIndex = split(this.props.hash, '::')[3];
|
const attributeIndex = split(this.props.hash, '::')[3];
|
||||||
const sameAttributes = filter(this.props.contentTypeData.attributes, (attr) => attr.name === this.props.modifiedDataAttribute.name);
|
const sameAttributes = filter(this.props.contentTypeData.attributes, (attr) => attr.name === this.props.modifiedDataAttribute.name);
|
||||||
const sameParamsKey = filter(this.props.contentTypeData.attributes, (attr) => attr.params.key === this.props.modifiedDataAttribute.params.key);
|
const sameParamsKey = filter(this.props.contentTypeData.attributes, (attr) =>
|
||||||
|
attr.params.key === this.props.modifiedDataAttribute.params.key && attr.params.target === this.props.modifiedDataAttribute.params.target);
|
||||||
const sameParamsKeyAndName = filter(this.props.contentTypeData.attributes, (attr) => attr.name === this.props.modifiedDataAttribute.params.key);
|
const sameParamsKeyAndName = filter(this.props.contentTypeData.attributes, (attr) => attr.name === this.props.modifiedDataAttribute.params.key);
|
||||||
const formErrors = concat(errors, hasNestedValue(this.props.modifiedDataAttribute));
|
const formErrors = concat(errors, hasNestedValue(this.props.modifiedDataAttribute));
|
||||||
const isEditingParamsKey = this.props.modifiedDataAttribute.params.key !== get(this.props.contentTypeData.attributes, [attributeIndex, 'params', 'key']);
|
const isEditingParamsKey = this.props.modifiedDataAttribute.params.key !== get(this.props.contentTypeData.attributes, [attributeIndex, 'params', 'key']);
|
||||||
|
|||||||
@ -115,13 +115,13 @@ module.exports = {
|
|||||||
try {
|
try {
|
||||||
const modelJSON = _.cloneDeep(require(modelFilePath));
|
const modelJSON = _.cloneDeep(require(modelFilePath));
|
||||||
|
|
||||||
modelJSON.attributes = formatedAttributes;
|
modelJSON.connection = connection;
|
||||||
|
modelJSON.collectionName = collectionName;
|
||||||
modelJSON.info = {
|
modelJSON.info = {
|
||||||
name,
|
name,
|
||||||
description
|
description
|
||||||
};
|
};
|
||||||
modelJSON.connection = connection;
|
modelJSON.attributes = formatedAttributes;
|
||||||
modelJSON.collectionName = collectionName;
|
|
||||||
|
|
||||||
const clearRelationsErrors = Service.clearRelations(model, plugin);
|
const clearRelationsErrors = Service.clearRelations(model, plugin);
|
||||||
|
|
||||||
|
|||||||
@ -181,7 +181,7 @@ module.exports = {
|
|||||||
|
|
||||||
_.forEach(attributesConfigurable, attribute => {
|
_.forEach(attributesConfigurable, attribute => {
|
||||||
if (_.has(attribute, 'params.type')) {
|
if (_.has(attribute, 'params.type')) {
|
||||||
attrs[attribute.name] = attribute.params;
|
attrs[attribute.name] = _.omit(attribute.params, 'multiple');
|
||||||
|
|
||||||
if (attribute.params.type === 'media') {
|
if (attribute.params.type === 'media') {
|
||||||
const via = _.findKey(strapi.plugins.upload.models.file.attributes, {collection: '*'});
|
const via = _.findKey(strapi.plugins.upload.models.file.attributes, {collection: '*'});
|
||||||
|
|||||||
@ -34,7 +34,6 @@
|
|||||||
"form.database.item.provider.mongo": "Mongo",
|
"form.database.item.provider.mongo": "Mongo",
|
||||||
"form.database.item.provider.postgres": "PostgreSQL",
|
"form.database.item.provider.postgres": "PostgreSQL",
|
||||||
"form.database.item.provider.mysql": "MySQL",
|
"form.database.item.provider.mysql": "MySQL",
|
||||||
"form.database.item.provider.sqlite3": "SQlite3",
|
|
||||||
"form.database.item.provider.redis": "Redis",
|
"form.database.item.provider.redis": "Redis",
|
||||||
|
|
||||||
"form.application.name": "Anwendung",
|
"form.application.name": "Anwendung",
|
||||||
|
|||||||
@ -34,7 +34,6 @@
|
|||||||
"form.database.item.provider.mongo": "Mongo",
|
"form.database.item.provider.mongo": "Mongo",
|
||||||
"form.database.item.provider.postgres": "PostgresSQL",
|
"form.database.item.provider.postgres": "PostgresSQL",
|
||||||
"form.database.item.provider.mysql": "MySQL",
|
"form.database.item.provider.mysql": "MySQL",
|
||||||
"form.database.item.provider.sqlite3": "SQlite3",
|
|
||||||
"form.database.item.provider.redis": "Redis",
|
"form.database.item.provider.redis": "Redis",
|
||||||
|
|
||||||
"form.application.name": "Application",
|
"form.application.name": "Application",
|
||||||
|
|||||||
@ -34,7 +34,6 @@
|
|||||||
"form.database.item.provider.mongo": "Mongo",
|
"form.database.item.provider.mongo": "Mongo",
|
||||||
"form.database.item.provider.postgres": "PostgresSQL",
|
"form.database.item.provider.postgres": "PostgresSQL",
|
||||||
"form.database.item.provider.mysql": "MySQL",
|
"form.database.item.provider.mysql": "MySQL",
|
||||||
"form.database.item.provider.sqlite3": "SQlite3",
|
|
||||||
"form.database.item.provider.redis": "Redis",
|
"form.database.item.provider.redis": "Redis",
|
||||||
|
|
||||||
"form.application.name": "Application",
|
"form.application.name": "Application",
|
||||||
|
|||||||
@ -34,7 +34,6 @@
|
|||||||
"form.database.item.provider.mongo": "Mongo",
|
"form.database.item.provider.mongo": "Mongo",
|
||||||
"form.database.item.provider.postgres": "PostgresSQL",
|
"form.database.item.provider.postgres": "PostgresSQL",
|
||||||
"form.database.item.provider.mysql": "MySQL",
|
"form.database.item.provider.mysql": "MySQL",
|
||||||
"form.database.item.provider.sqlite3": "SQlite3",
|
|
||||||
"form.database.item.provider.redis": "Redis",
|
"form.database.item.provider.redis": "Redis",
|
||||||
|
|
||||||
"form.application.name": "Aplikacja",
|
"form.application.name": "Aplikacja",
|
||||||
|
|||||||
@ -34,7 +34,6 @@
|
|||||||
"form.database.item.provider.mongo": "Mongo",
|
"form.database.item.provider.mongo": "Mongo",
|
||||||
"form.database.item.provider.postgres": "PostgresSQL",
|
"form.database.item.provider.postgres": "PostgresSQL",
|
||||||
"form.database.item.provider.mysql": "MySQL",
|
"form.database.item.provider.mysql": "MySQL",
|
||||||
"form.database.item.provider.sqlite3": "SQlite3",
|
|
||||||
"form.database.item.provider.redis": "Redis",
|
"form.database.item.provider.redis": "Redis",
|
||||||
|
|
||||||
"form.application.name": "Приложение",
|
"form.application.name": "Приложение",
|
||||||
@ -652,4 +651,4 @@
|
|||||||
"language.zu_ZA": "isiZulu (iNingizimu Afrika)",
|
"language.zu_ZA": "isiZulu (iNingizimu Afrika)",
|
||||||
|
|
||||||
"pageNotFound": "Cтраница не найдена"
|
"pageNotFound": "Cтраница не найдена"
|
||||||
}
|
}
|
||||||
|
|||||||
@ -34,7 +34,6 @@
|
|||||||
"form.database.item.provider.mongo": "Mongo",
|
"form.database.item.provider.mongo": "Mongo",
|
||||||
"form.database.item.provider.postgres": "PostgresSQL",
|
"form.database.item.provider.postgres": "PostgresSQL",
|
||||||
"form.database.item.provider.mysql": "MySQL",
|
"form.database.item.provider.mysql": "MySQL",
|
||||||
"form.database.item.provider.sqlite3": "SQlite3",
|
|
||||||
"form.database.item.provider.redis": "Redis",
|
"form.database.item.provider.redis": "Redis",
|
||||||
|
|
||||||
"form.application.name": "Uygulama",
|
"form.application.name": "Uygulama",
|
||||||
|
|||||||
@ -34,7 +34,6 @@
|
|||||||
"form.database.item.provider.mongo": "Mongo",
|
"form.database.item.provider.mongo": "Mongo",
|
||||||
"form.database.item.provider.postgres": "PostgresSQL",
|
"form.database.item.provider.postgres": "PostgresSQL",
|
||||||
"form.database.item.provider.mysql": "MySQL",
|
"form.database.item.provider.mysql": "MySQL",
|
||||||
"form.database.item.provider.sqlite3": "SQlite3",
|
|
||||||
"form.database.item.provider.redis": "Redis",
|
"form.database.item.provider.redis": "Redis",
|
||||||
|
|
||||||
"form.application.name": "應用程式",
|
"form.application.name": "應用程式",
|
||||||
|
|||||||
@ -137,6 +137,7 @@ module.exports = {
|
|||||||
fs.unlinkSync(filePath);
|
fs.unlinkSync(filePath);
|
||||||
|
|
||||||
ctx.send({ ok: true });
|
ctx.send({ ok: true });
|
||||||
|
strapi.reload();
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
ctx.badRequest(null, Service.formatErrors([{
|
ctx.badRequest(null, Service.formatErrors([{
|
||||||
target: 'name',
|
target: 'name',
|
||||||
|
|||||||
@ -520,11 +520,6 @@ module.exports = {
|
|||||||
value: 'mysql',
|
value: 'mysql',
|
||||||
port: 3306
|
port: 3306
|
||||||
},
|
},
|
||||||
{
|
|
||||||
name: 'form.database.item.provider.sqlite3',
|
|
||||||
value: 'sqlite3',
|
|
||||||
port: 1433
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
name: 'form.database.item.provider.redis',
|
name: 'form.database.item.provider.redis',
|
||||||
value: 'redis',
|
value: 'redis',
|
||||||
@ -636,7 +631,7 @@ module.exports = {
|
|||||||
},
|
},
|
||||||
|
|
||||||
getClientConnector: client => {
|
getClientConnector: client => {
|
||||||
const bookshelfClients = ['postgres', 'mysql', 'sqlite3'];
|
const bookshelfClients = ['postgres', 'mysql'];
|
||||||
const mongooseClients = ['mongo'];
|
const mongooseClients = ['mongo'];
|
||||||
const redisClients = ['redis'];
|
const redisClients = ['redis'];
|
||||||
|
|
||||||
@ -662,9 +657,6 @@ module.exports = {
|
|||||||
case 'mongo':
|
case 'mongo':
|
||||||
return '#43b121';
|
return '#43b121';
|
||||||
break;
|
break;
|
||||||
case 'sqlite3':
|
|
||||||
return '#006fff';
|
|
||||||
break;
|
|
||||||
default:
|
default:
|
||||||
return '#000000';
|
return '#000000';
|
||||||
}
|
}
|
||||||
@ -885,8 +877,7 @@ module.exports = {
|
|||||||
installDependency: (params, name) => {
|
installDependency: (params, name) => {
|
||||||
const clientsDependencies = {
|
const clientsDependencies = {
|
||||||
postgres: 'pg',
|
postgres: 'pg',
|
||||||
mysql: 'mysql',
|
mysql: 'mysql'
|
||||||
sqlite3: 'sqlite3'
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const client = _.get(clientsDependencies, _.get(params, `database.connections.${name}.settings.client`));
|
const client = _.get(clientsDependencies, _.get(params, `database.connections.${name}.settings.client`));
|
||||||
|
|||||||
@ -13,48 +13,6 @@ const _ = require('lodash');
|
|||||||
const fs = require('fs');
|
const fs = require('fs');
|
||||||
|
|
||||||
module.exports = async cb => {
|
module.exports = async cb => {
|
||||||
const Model = strapi.plugins.upload.models.file;
|
|
||||||
|
|
||||||
if (Model.orm === 'bookshelf') {
|
|
||||||
const hasTable = await strapi.connections[Model.connection].schema.hasTable(Model.tableName || Model.collectionName);
|
|
||||||
|
|
||||||
if (!hasTable) {
|
|
||||||
const quote = Model.client === 'pg' ? '"' : '`';
|
|
||||||
|
|
||||||
strapi.log.warn(`
|
|
||||||
⚠️ TABLE \`upload_file\` DOESN'T EXIST
|
|
||||||
⚠️ TABLE \`upload_file_morph\` DOESN'T EXIST
|
|
||||||
|
|
||||||
CREATE TABLE ${quote}${Model.tableName || Model.collectionName}${quote} (
|
|
||||||
id ${Model.client === 'pg' ? 'SERIAL' : 'INT AUTO_INCREMENT'} NOT NULL PRIMARY KEY,
|
|
||||||
name text,
|
|
||||||
hash text,
|
|
||||||
ext text,
|
|
||||||
mime text,
|
|
||||||
size text,
|
|
||||||
url text,
|
|
||||||
provider text,
|
|
||||||
updated_at ${Model.client === 'pg' ? 'timestamp with time zone' : 'timestamp DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP'},
|
|
||||||
created_at ${Model.client === 'pg' ? 'timestamp with time zone' : 'timestamp DEFAULT CURRENT_TIMESTAMP'}
|
|
||||||
);
|
|
||||||
|
|
||||||
CREATE TABLE ${quote}upload_file_morph${quote} (
|
|
||||||
id ${Model.client === 'pg' ? 'SERIAL' : 'INT AUTO_INCREMENT'} NOT NULL PRIMARY KEY,
|
|
||||||
upload_file_id ${Model.client === 'pg' ? 'integer' : 'int'},
|
|
||||||
related_id ${Model.client === 'pg' ? 'integer' : 'int'},
|
|
||||||
related_type text,
|
|
||||||
field text
|
|
||||||
);
|
|
||||||
|
|
||||||
1️⃣ EXECUTE THE FOLLOWING SQL QUERY
|
|
||||||
|
|
||||||
2️⃣ RESTART YOUR SERVER
|
|
||||||
`);
|
|
||||||
|
|
||||||
strapi.stop();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// set plugin store
|
// set plugin store
|
||||||
const pluginStore = strapi.store({
|
const pluginStore = strapi.store({
|
||||||
environment: strapi.config.environment,
|
environment: strapi.config.environment,
|
||||||
|
|||||||
@ -28,7 +28,7 @@
|
|||||||
"required": true
|
"required": true
|
||||||
},
|
},
|
||||||
"size": {
|
"size": {
|
||||||
"type": "float",
|
"type": "string",
|
||||||
"configurable": false,
|
"configurable": false,
|
||||||
"required": true
|
"required": true
|
||||||
},
|
},
|
||||||
|
|||||||
@ -74,7 +74,7 @@ module.exports = async cb => {
|
|||||||
callback: '/auth/twitter/callback'
|
callback: '/auth/twitter/callback'
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
const prevGrantConfig = await pluginStore.get({key: 'grant'})
|
const prevGrantConfig = await pluginStore.get({key: 'grant'}) || {};
|
||||||
// store grant auth config to db
|
// store grant auth config to db
|
||||||
// when plugin_users-permissions_grant is not existed in db
|
// when plugin_users-permissions_grant is not existed in db
|
||||||
// or we have added/deleted provider here.
|
// or we have added/deleted provider here.
|
||||||
@ -124,7 +124,5 @@ module.exports = async cb => {
|
|||||||
await pluginStore.set({key: 'advanced', value});
|
await pluginStore.set({key: 'advanced', value});
|
||||||
}
|
}
|
||||||
|
|
||||||
strapi.plugins['users-permissions'].services.userspermissions.syncSchema(() => {
|
|
||||||
strapi.plugins['users-permissions'].services.userspermissions.initialize(cb);
|
strapi.plugins['users-permissions'].services.userspermissions.initialize(cb);
|
||||||
});
|
|
||||||
};
|
};
|
||||||
|
|||||||
@ -4,7 +4,13 @@ module.exports = {
|
|||||||
find: async function (params = {}, populate) {
|
find: async function (params = {}, populate) {
|
||||||
const records = await this.query(function(qb) {
|
const records = await this.query(function(qb) {
|
||||||
_.forEach(params.where, (where, key) => {
|
_.forEach(params.where, (where, key) => {
|
||||||
qb.where(key, where[0].symbol, where[0].value);
|
if (_.isArray(where.value)) {
|
||||||
|
for (const value in where.value) {
|
||||||
|
qb[value ? 'where' : 'orWhere'](key, where.symbol, where.value[value])
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
qb.where(key, where.symbol, where.value);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
if (params.sort) {
|
if (params.sort) {
|
||||||
|
|||||||
@ -401,179 +401,6 @@ module.exports = {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
syncSchema: async (cb) => {
|
|
||||||
if (strapi.plugins['users-permissions'].models.user.orm !== 'bookshelf') {
|
|
||||||
return cb();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Extract necessary information from plugin's models.
|
|
||||||
const {
|
|
||||||
user: { collectionName: userTableName, connection: userConnection, client: userClient },
|
|
||||||
role: { collectionName: roleTableName, connection: roleConnection, client: roleClient },
|
|
||||||
permission: { collectionName: permissionTableName, connection: permissionConnection, client: permissionClient }
|
|
||||||
} = strapi.plugins['users-permissions'].models;
|
|
||||||
|
|
||||||
const details = {
|
|
||||||
user: {
|
|
||||||
tableName: userTableName,
|
|
||||||
connection: userConnection,
|
|
||||||
client: userClient
|
|
||||||
},
|
|
||||||
role: {
|
|
||||||
tableName: roleTableName,
|
|
||||||
connection: roleConnection,
|
|
||||||
client: roleClient
|
|
||||||
},
|
|
||||||
permission: {
|
|
||||||
tableName: permissionTableName,
|
|
||||||
connection: permissionConnection,
|
|
||||||
client: permissionClient
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// Check if the tables are existing.
|
|
||||||
const hasTables = await Promise.all(Object.keys(details).map(name =>
|
|
||||||
strapi.connections[details[name].connection].schema.hasTable(details[name].tableName)
|
|
||||||
));
|
|
||||||
|
|
||||||
const missingTables = [];
|
|
||||||
const tablesToCreate = [];
|
|
||||||
|
|
||||||
for (let index = 0; index < hasTables.length; ++index) {
|
|
||||||
const hasTable = hasTables[index];
|
|
||||||
const currentModel = Object.keys(details)[index];
|
|
||||||
const quote = details[currentModel].client === 'pg' ? '"' : '`';
|
|
||||||
|
|
||||||
if (!hasTable) {
|
|
||||||
missingTables.push(`
|
|
||||||
⚠️ TABLE \`${details[currentModel].tableName}\` DOESN'T EXIST`);
|
|
||||||
|
|
||||||
switch (currentModel) {
|
|
||||||
case 'user':
|
|
||||||
tablesToCreate.push(`
|
|
||||||
|
|
||||||
CREATE TABLE ${quote}${details[currentModel].tableName}${quote} (
|
|
||||||
id ${details[currentModel].client === 'pg' ? 'SERIAL' : 'INT AUTO_INCREMENT'} NOT NULL PRIMARY KEY,
|
|
||||||
username text,
|
|
||||||
email text,
|
|
||||||
provider text,
|
|
||||||
role ${details[currentModel].client === 'pg' ? 'integer' : 'int'},
|
|
||||||
${quote}resetPasswordToken${quote} text,
|
|
||||||
password text,
|
|
||||||
updated_at ${details[currentModel].client === 'pg' ? 'timestamp with time zone' : 'timestamp DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP'},
|
|
||||||
created_at ${details[currentModel].client === 'pg' ? 'timestamp with time zone' : 'timestamp DEFAULT CURRENT_TIMESTAMP'}
|
|
||||||
);`);
|
|
||||||
break;
|
|
||||||
case 'role':
|
|
||||||
tablesToCreate.push(`
|
|
||||||
|
|
||||||
CREATE TABLE ${quote}${details[currentModel].tableName}${quote} (
|
|
||||||
id ${details[currentModel].client === 'pg' ? 'SERIAL' : 'INT AUTO_INCREMENT'} NOT NULL PRIMARY KEY,
|
|
||||||
name text,
|
|
||||||
description text,
|
|
||||||
type text
|
|
||||||
);`);
|
|
||||||
break;
|
|
||||||
case 'permission':
|
|
||||||
tablesToCreate.push(`
|
|
||||||
|
|
||||||
CREATE TABLE ${quote}${details[currentModel].tableName}${quote} (
|
|
||||||
id ${details[currentModel].client === 'pg' ? 'SERIAL' : 'INT AUTO_INCREMENT'} NOT NULL PRIMARY KEY,
|
|
||||||
role ${details[currentModel].client === 'pg' ? 'integer' : 'int'},
|
|
||||||
type text,
|
|
||||||
controller text,
|
|
||||||
action text,
|
|
||||||
enabled boolean,
|
|
||||||
policy text
|
|
||||||
);`);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!_.isEmpty(tablesToCreate)) {
|
|
||||||
tablesToCreate.unshift(`
|
|
||||||
|
|
||||||
1️⃣ EXECUTE THE FOLLOWING SQL QUERY`);
|
|
||||||
|
|
||||||
tablesToCreate.push(`
|
|
||||||
|
|
||||||
2️⃣ RESTART YOUR SERVER`)
|
|
||||||
strapi.log.warn(missingTables.concat(tablesToCreate).join(''));
|
|
||||||
|
|
||||||
// Stop the server.
|
|
||||||
strapi.stop();
|
|
||||||
}
|
|
||||||
|
|
||||||
const missingColumns = [];
|
|
||||||
const tablesToAlter = [];
|
|
||||||
|
|
||||||
for (let index = 0; index < hasTables.length; ++index) {
|
|
||||||
const currentModel = Object.keys(details)[index];
|
|
||||||
const quote = details[currentModel].client === 'pg' ? '"' : '`';
|
|
||||||
const attributes = {
|
|
||||||
id: {
|
|
||||||
type: details[currentModel].client === 'pg' ? 'integer' : 'int'
|
|
||||||
},
|
|
||||||
..._.cloneDeep(strapi.plugins['users-permissions'].models[currentModel].attributes)
|
|
||||||
};
|
|
||||||
|
|
||||||
// Add created_at and updated_at attributes for the model User.
|
|
||||||
if (currentModel === 'user') {
|
|
||||||
Object.assign(attributes, {
|
|
||||||
created_at: {
|
|
||||||
type: details[currentModel].client === 'pg' ? 'timestamp with time zone' : 'timestamp'
|
|
||||||
},
|
|
||||||
updated_at: {
|
|
||||||
type: details[currentModel].client === 'pg' ? 'timestamp with time zone' : 'timestamp'
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
const columns = Object.keys(attributes);
|
|
||||||
|
|
||||||
// Check if there are the required attributes.
|
|
||||||
const hasColumns = await Promise.all(columns.map(attribute =>
|
|
||||||
strapi.connections[details[currentModel].connection].schema.hasColumn(details[currentModel].tableName, attribute)
|
|
||||||
));
|
|
||||||
|
|
||||||
hasColumns.forEach((hasColumn, index) => {
|
|
||||||
const currentColumn = columns[index];
|
|
||||||
const attribute = attributes[currentColumn];
|
|
||||||
|
|
||||||
if (!hasColumn && !attribute.collection) {
|
|
||||||
const currentType = attribute.model ? 'integer' : attribute.type;
|
|
||||||
const type = currentType === 'string' ? 'text' : currentType;
|
|
||||||
|
|
||||||
missingColumns.push(`
|
|
||||||
⚠️ TABLE \`${details[currentModel].tableName}\` HAS MISSING COLUMNS`);
|
|
||||||
|
|
||||||
tablesToAlter.push(`
|
|
||||||
|
|
||||||
ALTER TABLE ${quote}${details[currentModel].tableName}${quote} ADD ${details[currentModel].client === 'pg' ? `${quote}${currentColumn}${quote}` : `${currentColumn}`} ${type};`);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!_.isEmpty(tablesToAlter)) {
|
|
||||||
tablesToAlter.unshift(`
|
|
||||||
|
|
||||||
1️⃣ EXECUTE THE FOLLOWING SQL QUERIES`);
|
|
||||||
|
|
||||||
tablesToAlter.push(`
|
|
||||||
|
|
||||||
2️⃣ RESTART YOUR SERVER`)
|
|
||||||
strapi.log.warn(missingColumns.concat(tablesToAlter).join(''));
|
|
||||||
|
|
||||||
// Stop the server.
|
|
||||||
return strapi.stop();
|
|
||||||
}
|
|
||||||
|
|
||||||
cb();
|
|
||||||
},
|
|
||||||
|
|
||||||
template: (layout, data) => {
|
template: (layout, data) => {
|
||||||
const compiledObject = _.template(layout);
|
const compiledObject = _.template(layout);
|
||||||
return compiledObject(data);
|
return compiledObject(data);
|
||||||
|
|||||||
@ -27,6 +27,11 @@ const { cli, logger } = require('strapi-utils');
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
module.exports = function() {
|
module.exports = function() {
|
||||||
|
// Check that we're in a valid Strapi project.
|
||||||
|
if (!cli.isStrapiApp()) {
|
||||||
|
return logger.error('This command can only be used inside a Strapi project.');
|
||||||
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const strapi = function () {
|
const strapi = function () {
|
||||||
try {
|
try {
|
||||||
|
|||||||
@ -176,6 +176,8 @@ class Strapi extends EventEmitter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async load() {
|
async load() {
|
||||||
|
await this.enhancer();
|
||||||
|
|
||||||
this.app.use(async (ctx, next) => {
|
this.app.use(async (ctx, next) => {
|
||||||
if (ctx.request.url === '/_health' && ctx.request.method === 'HEAD') {
|
if (ctx.request.url === '/_health' && ctx.request.method === 'HEAD') {
|
||||||
ctx.set('strapi', 'You are so French!');
|
ctx.set('strapi', 'You are so French!');
|
||||||
@ -199,8 +201,8 @@ class Strapi extends EventEmitter {
|
|||||||
// Usage.
|
// Usage.
|
||||||
await utils.usage.call(this);
|
await utils.usage.call(this);
|
||||||
|
|
||||||
// Init core store manager
|
// Init core store
|
||||||
await store.pre.call(this);
|
await store.call(this);
|
||||||
|
|
||||||
// Initialize hooks and middlewares.
|
// Initialize hooks and middlewares.
|
||||||
await Promise.all([
|
await Promise.all([
|
||||||
@ -208,9 +210,6 @@ class Strapi extends EventEmitter {
|
|||||||
initializeHooks.call(this)
|
initializeHooks.call(this)
|
||||||
]);
|
]);
|
||||||
|
|
||||||
// Core store post middleware and hooks init validation.
|
|
||||||
await store.post.call(this);
|
|
||||||
|
|
||||||
// Harmonize plugins configuration.
|
// Harmonize plugins configuration.
|
||||||
await plugins.call(this);
|
await plugins.call(this);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -327,6 +327,7 @@ module.exports.app = async function() {
|
|||||||
}, {});
|
}, {});
|
||||||
|
|
||||||
this.config.port = get(this.config.currentEnvironment, 'server.port') || this.config.port;
|
this.config.port = get(this.config.currentEnvironment, 'server.port') || this.config.port;
|
||||||
|
this.config.host = get(this.config.currentEnvironment, 'server.host') || this.config.host;
|
||||||
this.config.url = `http://${this.config.host}:${this.config.port}`;
|
this.config.url = `http://${this.config.host}:${this.config.port}`;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@ -1,7 +1,6 @@
|
|||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
module.exports = {
|
module.exports = function () {
|
||||||
pre: function () {
|
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
this.models['core_store'] = {
|
this.models['core_store'] = {
|
||||||
connection: 'default',
|
connection: 'default',
|
||||||
@ -14,7 +13,7 @@ module.exports = {
|
|||||||
type: 'string'
|
type: 'string'
|
||||||
},
|
},
|
||||||
value: {
|
value: {
|
||||||
type: 'string'
|
type: 'text'
|
||||||
},
|
},
|
||||||
type: {
|
type: {
|
||||||
type: 'string'
|
type: 'string'
|
||||||
@ -135,44 +134,4 @@ module.exports = {
|
|||||||
|
|
||||||
resolve();
|
resolve();
|
||||||
});
|
});
|
||||||
},
|
|
||||||
post: function () {
|
|
||||||
return new Promise(async (resolve, reject) => {
|
|
||||||
const Model = this.models['core_store'];
|
|
||||||
|
|
||||||
if (Model.orm !== 'bookshelf') {
|
|
||||||
return resolve();
|
|
||||||
}
|
|
||||||
|
|
||||||
const hasTable = await this.connections[Model.connection].schema.hasTable(Model.tableName || Model.collectionName);
|
|
||||||
|
|
||||||
if (!hasTable) {
|
|
||||||
const quote = Model.client === 'pg' ? '"' : '`';
|
|
||||||
|
|
||||||
this.log.warn(`
|
|
||||||
⚠️ TABLE \`core_store\` DOESN'T EXIST
|
|
||||||
|
|
||||||
CREATE TABLE ${quote}${Model.tableName || Model.collectionName}${quote} (
|
|
||||||
id ${Model.client === 'pg' ? 'SERIAL' : 'INT AUTO_INCREMENT'} NOT NULL PRIMARY KEY,
|
|
||||||
${quote}key${quote} text,
|
|
||||||
${quote}value${quote} text,
|
|
||||||
environment text,
|
|
||||||
type text,
|
|
||||||
tag text
|
|
||||||
);
|
|
||||||
|
|
||||||
ALTER TABLE ${quote}${Model.tableName || Model.collectionName}${quote} ADD COLUMN ${quote}parent${quote} integer, ADD FOREIGN KEY (${quote}parent${quote}) REFERENCES ${quote}${Model.tableName || Model.collectionName}${quote}(${quote}id${quote});
|
|
||||||
|
|
||||||
1️⃣ EXECUTE THE FOLLOWING SQL QUERY
|
|
||||||
|
|
||||||
2️⃣ RESTART YOUR SERVER
|
|
||||||
`);
|
|
||||||
|
|
||||||
// Stop the server.
|
|
||||||
return this.stop();
|
|
||||||
}
|
|
||||||
|
|
||||||
resolve();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user