Merge branch 'develop' of github.com:strapi/strapi into features/media-lib

This commit is contained in:
soupette 2020-03-26 08:01:22 +01:00
commit 38b7823b34
40 changed files with 381 additions and 322 deletions

View File

@ -484,6 +484,7 @@ module.exports = ({ model, modelKey, strapi }) => {
const filters = modelUtils.convertParams(modelKey, params);
const $or = buildSearchOr(model, params._q);
if ($or.length === 0) return Promise.resolve([]);
return model
.find({ $or })
@ -496,6 +497,7 @@ module.exports = ({ model, modelKey, strapi }) => {
function countSearch(params) {
const $or = buildSearchOr(model, params._q);
if ($or.length === 0) return Promise.resolve(0);
return model.find({ $or }).countDocuments();
}
@ -525,6 +527,7 @@ const buildSearchOr = (model, query) => {
case 'string':
case 'text':
case 'password':
case 'uid':
return acc.concat({ [curr]: { $regex: query, $options: 'i' } });
case 'boolean':
if (query === 'true' || query === 'false') {

View File

@ -97,46 +97,19 @@ function generateCollectionTypeRoutes({ route, name }) {
*/
module.exports = scope => {
const routes =
let routes = [];
if (!scope.args.plugin) {
routes =
scope.contentTypeKind === 'singleType'
? generateSingleTypeRoutes({
route: scope.route,
name: scope.name,
})
: generateCollectionTypeRoutes({
route: scope.route,
name: scope.name,
});
? generateSingleTypeRoutes({ route: scope.route, name: scope.name })
: generateCollectionTypeRoutes({ route: scope.route, name: scope.name });
}
// We have to delete current file
// if routes.json already exists, then merge
if (fs.existsSync(scope.rootPath)) {
let current;
try {
// Copy current routes.json
current = require(scope.rootPath);
// Remove current routes.json
let current = require(scope.rootPath);
fs.unlinkSync(scope.rootPath);
} catch (e) {
console.error(e);
current = {
routes: [],
};
}
try {
_.set(
current,
'routes',
_.concat(routes, _.differenceWith(current.routes, routes, _.isEqual))
);
return current;
} catch (e) {
console.error(e);
return;
}
routes = _.concat(routes, _.differenceWith(current.routes, routes, _.isEqual));
}
return { routes };

View File

@ -11,6 +11,7 @@ const path = require('path');
// Public node modules.
const _ = require('lodash');
const pluralize = require('pluralize');
const { nameToSlug } = require('strapi-utils');
/**
* This `before` function is run before generating targets.
@ -26,7 +27,7 @@ module.exports = (scope, cb) => {
}
// Format `id`.
const name = scope.name || _.trim(_.camelCase(scope.id));
const name = scope.name || nameToSlug(scope.id);
const environment = process.env.NODE_ENV || 'development';
scope.contentTypeKind = scope.args.kind || 'collectionType';
@ -58,12 +59,6 @@ module.exports = (scope, cb) => {
filePath,
});
// Humanize output.
_.defaults(scope, {
humanizeId: name,
humanizedPath: filePath,
});
// Validate optional attribute arguments.
const invalidAttributes = [];

View File

@ -14,7 +14,8 @@
},
"dependencies": {
"lodash": "^4.17.11",
"pluralize": "^7.0.0"
"pluralize": "^7.0.0",
"strapi-utils": "^3.0.0-beta.19.3"
},
"scripts": {
"test": "echo \"no tests yet\""

View File

@ -6,6 +6,7 @@
// Public node modules.
const _ = require('lodash');
const { nameToSlug } = require('strapi-utils');
/* eslint-disable prefer-template */
/**
* This `before` function is run before generating targets.
@ -22,18 +23,15 @@ module.exports = (scope, cb) => {
);
}
// Format `id`.
const name = scope.name || nameToSlug(scope.id);
// `scope.args` are the raw command line arguments.
_.defaults(scope, {
id: _.trim(_.deburr(scope.id)),
name,
api: scope.id,
});
// Determine default values based on the available scope.
_.defaults(scope, {
globalID: _.upperFirst(_.camelCase(scope.id)),
ext: '.js',
});
// Determine the destination path.
let filePath;
if (scope.args.api) {
@ -43,20 +41,14 @@ module.exports = (scope, cb) => {
} else if (scope.args.extend) {
filePath = `./extensions/${scope.args.extend}/controllers`;
} else {
filePath = `./api/${scope.id}/controllers`;
filePath = `./api/${name}/controllers`;
}
// Take another pass to take advantage of the defaults absorbed in previous passes.
_.defaults(scope, {
rootPath: scope.rootPath,
filePath,
filename: scope.globalID + scope.ext,
});
// Humanize output.
_.defaults(scope, {
humanizeId: _.camelCase(scope.id).toLowerCase(),
humanizedPath: '`' + scope.filePath + '`',
filename: `${name}.js`,
});
// Trigger callback with no error to proceed.

View File

@ -14,7 +14,8 @@
"lib": "./lib"
},
"dependencies": {
"lodash": "^4.17.11"
"lodash": "^4.17.11",
"strapi-utils": "^3.0.0-beta.19.3"
},
"scripts": {
"test": "echo \"no tests yet\""

View File

@ -1,7 +1,7 @@
'use strict';
/**
* A set of functions called "actions" for `<%= globalID %>`
* A set of functions called "actions" for `<%= name %>`
*/
module.exports = {

View File

@ -11,6 +11,7 @@ const path = require('path');
// Public node modules.
const _ = require('lodash');
const pluralize = require('pluralize');
const { nameToSlug, nameToCollectionName } = require('strapi-utils');
// Fetch stub attribute template on initial load.
const attributeTemplate = fs.readFileSync(
@ -34,41 +35,31 @@ module.exports = (scope, cb) => {
);
}
// Format `id`.
const name = scope.name || nameToSlug(scope.id);
// `scope.args` are the raw command line arguments.
_.defaults(scope, {
id: _.trim(_.deburr(scope.id)),
idPluralized: pluralize.plural(_.trim(_.deburr(scope.id))),
name,
environment: process.env.NODE_ENV || 'development',
});
// Determine default values based on the available scope.
_.defaults(scope, {
globalID: _.upperFirst(_.camelCase(scope.id)),
ext: '.js',
});
// Determine the destination path.
let filePath;
if (scope.args.api) {
filePath = `./api/${scope.args.api}`;
filePath = `./api/${scope.args.api}/models`;
} else if (scope.args.plugin) {
filePath = `./plugins/${scope.args.plugin}/models`;
} else {
filePath = `./api/${scope.id}`;
filePath = `./api/${name}/models`;
}
// Take another pass to take advantage of the defaults absorbed in previous passes.
_.defaults(scope, {
rootPath: scope.rootPath,
filePath,
filename: scope.globalID + scope.ext,
filenameSettings: scope.globalID + '.settings.json',
});
// Humanize output.
_.defaults(scope, {
humanizeId: _.camelCase(scope.id).toLowerCase(),
humanizedPath: '`' + scope.filePath + '`',
filename: `${name}.js`,
filenameSettings: `${name}.settings.json`,
});
// Validate optional attribute arguments.
@ -82,9 +73,7 @@ module.exports = (scope, cb) => {
// Handle invalid attributes.
if (!parts[1] || !parts[0]) {
invalidAttributes.push(
'Error: Invalid attribute notation `' + attribute + '`.'
);
invalidAttributes.push('Error: Invalid attribute notation `' + attribute + '`.');
return;
}
@ -97,12 +86,10 @@ module.exports = (scope, cb) => {
// Set collectionName
scope.collectionName = _.has(scope.args, 'collectionName')
? scope.args.collectionName
: undefined;
: nameToCollectionName(pluralize(scope.id));
// Set description
scope.description = _.has(scope.args, 'description')
? scope.args.description
: undefined;
scope.description = _.has(scope.args, 'description') ? scope.args.description : undefined;
// Handle invalid action arguments.
// Send back invalidActions.
@ -141,13 +128,7 @@ module.exports = (scope, cb) => {
scope.args.connection ||
JSON.parse(
fs.readFileSync(
path.resolve(
scope.rootPath,
'config',
'environments',
scope.environment,
'database.json'
)
path.resolve(scope.rootPath, 'config', 'environments', scope.environment, 'database.json')
)
).defaultConnection ||
'';

View File

@ -16,7 +16,10 @@ module.exports = {
templatesDirectory: scope => {
try {
// Try to reach the path. If it fail, throw an error.
fs.accessSync(path.resolve(__dirname, '..', 'templates', scope.args.tpl), fs.constants.R_OK | fs.constants.W_OK);
fs.accessSync(
path.resolve(__dirname, '..', 'templates', scope.args.tpl),
fs.constants.R_OK | fs.constants.W_OK
);
return path.resolve(__dirname, '..', 'templates', scope.args.tpl);
} catch (e) {
@ -26,11 +29,11 @@ module.exports = {
},
before: require('./before'),
targets: {
':filePath/models/:filename': {
template: 'model.template'
':filePath/:filename': {
template: 'model.template',
},
':filePath/:filenameSettings': {
template: 'model.settings.template',
},
},
':filePath/models/:filenameSettings': {
template: 'model.settings.template'
}
}
};

View File

@ -15,7 +15,8 @@
},
"dependencies": {
"lodash": "^4.17.11",
"pluralize": "^7.0.0"
"pluralize": "^7.0.0",
"strapi-utils": "^3.0.0-beta.19.3"
},
"scripts": {
"test": "echo \"no tests yet\""

View File

@ -1,6 +1,7 @@
{
"kind": "collectionType",
"connection": "<%= connection %>",
"collectionName": "<%= collectionName || idPluralized %>",
"collectionName": "<%= collectionName %>",
"info": {
"name": "<%= id %>",
"description": "<%= description %>"

View File

@ -1,7 +1,7 @@
'use strict';
/**
* Lifecycle callbacks for the `<%= globalID %>` model.
* Lifecycle callbacks for the `<%= name %>` model.
*/
module.exports = {

View File

@ -1,6 +1,7 @@
{
"kind": "collectionType",
"connection": "<%= connection %>",
"collectionName": "<%= collectionName || '' %>",
"collectionName": "<%= collectionName %>",
"info": {
"name": "<%= id %>",
"description": "<%= description %>"

View File

@ -1,7 +1,7 @@
'use strict';
/**
* Lifecycle callbacks for the `<%= globalID %>` model.
* Lifecycle callbacks for the `<%= name %>` model.
*/
module.exports = {

View File

@ -7,14 +7,16 @@
module.exports = scope => {
function generateRoutes() {
return {
routes: [{
routes: [
{
method: 'GET',
path: '/',
handler: scope.globalID + '.index',
handler: scope.name + '.index',
config: {
policies: []
}
}]
policies: [],
},
},
],
};
}

View File

@ -8,6 +8,7 @@
const path = require('path');
const fs = require('fs-extra');
const _ = require('lodash');
const { nameToSlug } = require('strapi-utils');
/**
* This `before` function is run before generating targets.
@ -22,20 +23,12 @@ module.exports = (scope, cb) => {
return cb.invalid('Usage: `$ strapi generate:plugin pluginName`');
}
// `scope.args` are the raw command line arguments.
_.defaults(scope, {
id: _.trim(_.deburr(scope.id)),
});
// Determine default values based on the available scope.
_.defaults(scope, {
globalID: _.upperFirst(_.camelCase(scope.id)),
ext: '.js',
});
// Format `id`.
const name = scope.name || nameToSlug(scope.id);
// Plugin info.
_.defaults(scope, {
name: scope.args.name || scope.id,
name,
author: scope.author || 'A Strapi developer',
email: scope.email || '',
year: new Date().getFullYear(),
@ -44,23 +37,15 @@ module.exports = (scope, cb) => {
// Take another pass to take advantage of the defaults absorbed in previous passes.
_.defaults(scope, {
filename: `${scope.globalID}${scope.ext}`,
});
// Humanize output.
_.defaults(scope, {
humanizeId: scope.id.toLowerCase(),
humanizedPath: '`./plugins`',
filename: `${name}.js`,
filePath: './plugins',
});
const pluginDir = path.resolve(scope.rootPath, 'plugins');
fs.ensureDirSync(pluginDir);
// Copy the admin files.
fs.copySync(
path.resolve(__dirname, '..', 'files'),
path.resolve(pluginDir, scope.humanizeId)
);
fs.copySync(path.resolve(__dirname, '..', 'files'), path.resolve(pluginDir, name));
// Trigger callback with no error to proceed.
return cb.success();

View File

@ -19,42 +19,42 @@ module.exports = {
templatesDirectory: path.resolve(__dirname, '..', 'templates'),
before: require('./before'),
targets: {
'plugins/:humanizeId/.gitignore': {
'plugins/:name/.gitignore': {
copy: 'gitignore',
},
// Use the default `controller` file as a template for
// every generated controller.
'plugins/:humanizeId/controllers/:filename': {
'plugins/:name/controllers/:filename': {
template: 'controller.template',
},
// every generated controller.
'plugins/:humanizeId/services/:filename': {
'plugins/:name/services/:filename': {
template: 'service.template',
},
// Generate routes.
'plugins/:humanizeId/config/routes.json': {
'plugins/:name/config/routes.json': {
jsonfile: routesJSON,
},
// Main package.
'plugins/:humanizeId/package.json': {
'plugins/:name/package.json': {
jsonfile: packageJSON,
},
// Copy dot files.
'plugins/:humanizeId/.editorconfig': {
'plugins/:name/.editorconfig': {
copy: 'editorconfig',
},
'plugins/:humanizeId/.gitattributes': {
'plugins/:name/.gitattributes': {
copy: 'gitattributes',
},
// Copy Markdown files with some information.
'plugins/:humanizeId/README.md': {
'plugins/:name/README.md': {
template: 'README.md',
},
},

View File

@ -14,7 +14,8 @@
},
"dependencies": {
"fs-extra": "^8.0.1",
"lodash": "^4.17.11"
"lodash": "^4.17.11",
"strapi-utils": "^3.0.0-beta.19.3"
},
"scripts": {
"test": "echo \"no tests yet\""

View File

@ -3,7 +3,7 @@
/**
* <%= filename %> controller
*
* @description: A set of functions called "actions" of the `<%= humanizeId %>` plugin.
* @description: A set of functions called "actions" of the `<%= name %>` plugin.
*/
module.exports = {

View File

@ -6,6 +6,7 @@
// Public node modules.
const _ = require('lodash');
const { nameToSlug } = require('strapi-utils');
/**
* This `before` function is run before generating targets.
@ -18,9 +19,14 @@ const _ = require('lodash');
/* eslint-disable prefer-template */
module.exports = (scope, cb) => {
if (!scope.rootPath || !scope.id) {
return cb.invalid('Usage: `$ strapi generate:policy policyName --api apiName --plugin pluginName`');
return cb.invalid(
'Usage: `$ strapi generate:policy policyName --api apiName --plugin pluginName`'
);
}
// Format `id`.
const name = scope.name || nameToSlug(scope.id);
let filePath;
if (scope.args.api) {
filePath = `./api/${scope.args.api}/config/policies`;
@ -30,21 +36,11 @@ module.exports = (scope, cb) => {
filePath = './config/policies';
}
// Determine default values based on the available scope.
_.defaults(scope, {
ext: '.js'
});
// Take another pass to take advantage of the defaults absorbed in previous passes.
_.defaults(scope, {
name,
filePath,
filename: scope.id + scope.ext
});
// Humanize output.
_.defaults(scope, {
humanizeId: scope.id,
humanizedPath: '`' + scope.filePath + '`'
filename: `${name}.js`,
});
// Trigger callback with no error to proceed.

View File

@ -14,7 +14,8 @@
"lib": "./lib"
},
"dependencies": {
"lodash": "^4.17.11"
"lodash": "^4.17.11",
"strapi-utils": "^3.0.0-beta.19.3"
},
"scripts": {
"test": "echo \"no tests yet\""

View File

@ -6,6 +6,7 @@
// Public node modules.
const _ = require('lodash');
const { nameToSlug } = require('strapi-utils');
/**
* This `before` function is run before generating targets.
@ -18,19 +19,18 @@ const _ = require('lodash');
/* eslint-disable prefer-template */
module.exports = (scope, cb) => {
if (!scope.rootPath || !scope.id) {
return cb.invalid('Usage: `$ strapi generate:service serviceName --api apiName --plugin pluginName`');
return cb.invalid(
'Usage: `$ strapi generate:service serviceName --api apiName --plugin pluginName`'
);
}
// Format `id`.
const name = scope.name || nameToSlug(scope.id);
// `scope.args` are the raw command line arguments.
_.defaults(scope, {
id: _.trim(_.deburr(scope.id)),
api: scope.args.api || scope.id
});
// Determine default values based on the available scope.
_.defaults(scope, {
globalID: _.upperFirst(_.camelCase(scope.id)),
ext: '.js'
name,
api: scope.args.api || scope.id,
});
// Determine the destination path.
@ -40,20 +40,14 @@ module.exports = (scope, cb) => {
} else if (scope.args.plugin) {
filePath = `./plugins/${scope.args.plugin}/services`;
} else {
filePath = `./api/${scope.id}/services`;
filePath = `./api/${name}/services`;
}
// Take another pass to take advantage of the defaults absorbed in previous passes.
_.defaults(scope, {
rootPath: scope.rootPath,
filePath,
filename: scope.globalID + scope.ext
});
// Humanize output.
_.defaults(scope, {
humanizeId: _.camelCase(scope.id).toLowerCase(),
humanizedPath: '`' + scope.filePath + '`'
filename: `${name}.js`,
});
// Trigger callback with no error to proceed.

View File

@ -16,7 +16,10 @@ module.exports = {
templatesDirectory: scope => {
try {
// Try to reach the path. If it fail, throw an error.
fs.accessSync(path.resolve(__dirname, '..', 'templates', scope.args.tpl), fs.constants.R_OK | fs.constants.W_OK);
fs.accessSync(
path.resolve(__dirname, '..', 'templates', scope.args.tpl),
fs.constants.R_OK | fs.constants.W_OK
);
return path.resolve(__dirname, '..', 'templates', scope.args.tpl);
} catch (e) {
@ -26,8 +29,8 @@ module.exports = {
},
before: require('./before'),
targets: {
'api/:api/services/:filename': {
template: 'service.template'
}
}
':filePath/:filename': {
template: 'service.template',
},
},
};

View File

@ -14,7 +14,8 @@
"lib": "./lib"
},
"dependencies": {
"lodash": "^4.17.11"
"lodash": "^4.17.11",
"strapi-utils": "^3.0.0-beta.19.3"
},
"scripts": {
"test": "echo \"no tests yet\""

View File

@ -1,7 +1,7 @@
'use strict';
/**
* `<%= globalID %>` service.
* `<%= name %>` service.
*/
module.exports = {

View File

@ -1,7 +1,7 @@
'use strict';
/**
* `<%= globalID %>` service.
* `<%= name %>` service.
*/
module.exports = {

View File

@ -30,7 +30,7 @@ function generate(generator, scope, cb) {
const sb = reportback.extend(cb, {
error: cb.error,
invalid: cb.invalid,
alreadyExists: 'error'
alreadyExists: 'error',
});
// Resolve string shorthand for generator defs
@ -38,18 +38,21 @@ function generate(generator, scope, cb) {
if (typeof generator === 'string') {
const generatorName = generator;
generator = {
generator: generatorName
generator: generatorName,
};
}
// Run the generator's `before()` method proceeding.
generator.before(scope, reportback.extend({
generator.before(
scope,
reportback.extend({
error: sb.error,
invalid: sb.invalid,
success: () => {
// Process all of the generator's targets concurrently.
async.each(Object.keys(generator.targets), (keyPath, asyncEachCb) => {
async.each(
Object.keys(generator.targets),
(keyPath, asyncEachCb) => {
const asyncEachSb = reportback.extend(asyncEachCb);
// Create a new scope object for this target,
@ -59,7 +62,11 @@ function generate(generator, scope, cb) {
// the base `generate` method to allow for recursive generators.
const target = generator.targets[keyPath];
if (!target) {
return asyncEachSb(new Error('Error: Invalid target: {"' + keyPath + '": ' + util.inspect(target) + '}'));
return asyncEachSb(
new Error(
'Error: Invalid target: {"' + keyPath + '": ' + util.inspect(target) + '}'
)
);
}
// Input tolerance.
@ -72,7 +79,9 @@ function generate(generator, scope, cb) {
const params = [];
pathRegexp(keyPath, params);
let err;
const parsedKeyPath = _.reduce(params, (memoKeyPath, param) => {
const parsedKeyPath = _.reduce(
params,
(memoKeyPath, param) => {
if (err) {
return false;
}
@ -83,8 +92,14 @@ function generate(generator, scope, cb) {
if (!actualParamValue) {
err = new Error(
'generator error:\n' +
'A scope variable (`' + param.name + '`) was referenced in target: `' + memoKeyPath + '`,\n' +
'but `' + param.name + '` does not exist in the generator\'s scope.'
'A scope variable (`' +
param.name +
'`) was referenced in target: `' +
memoKeyPath +
'`,\n' +
'but `' +
param.name +
"` does not exist in the generator's scope."
);
return false;
}
@ -96,7 +111,9 @@ function generate(generator, scope, cb) {
err.message = e;
return false;
}
}, keyPath);
},
keyPath
);
if (!parsedKeyPath) {
return asyncEachSb(err);
}
@ -108,49 +125,64 @@ function generate(generator, scope, cb) {
rootPath: path.resolve(scope.rootPath, parsedKeyPath),
// Include reference to original keypath for error reporting.
keyPath
keyPath,
});
// If `target` is an array, run each item.
if (_.isArray(target)) {
async.eachSeries(target, (targetItem, asyncEachSeriesCb) => {
generateTarget({
async.eachSeries(
target,
(targetItem, asyncEachSeriesCb) => {
generateTarget(
{
target: targetItem,
parent: generator,
scope: _.cloneDeep(targetScope),
recursiveGenerate: generate
}, asyncEachSeriesCb);
}, asyncEachSb);
recursiveGenerate: generate,
},
asyncEachSeriesCb
);
},
asyncEachSb
);
return;
}
// Otherwise, just run the single target generator/helper.
generateTarget({
generateTarget(
{
target,
parent: generator,
scope: targetScope,
recursiveGenerate: generate
}, asyncEachSb);
recursiveGenerate: generate,
},
asyncEachSb
);
},
err => {
// Expose a `error` handler in generators.
if (err) {
const errorFn = generator.error || function defaultError(err, scope, _cb) {
const errorFn =
generator.error ||
function defaultError(err, scope, _cb) {
return _cb(err);
};
return errorFn(err, scope, sb);
}
// Expose a `after` handler in generators (on success only).
const afterFn = generator.after || function defaultAfter(scope, _cb) {
const afterFn =
generator.after ||
function defaultAfter(scope, _cb) {
return _cb();
};
return afterFn(scope, sb);
});
}
}));
);
},
})
);
}
module.exports = generate;

View File

@ -2,7 +2,7 @@
const { join } = require('path');
const { nameToSlug } = require('../utils/helpers');
const { nameToSlug } = require('strapi-utils');
const createBuilder = require('./schema-builder');
/**

View File

@ -7,7 +7,7 @@ const generator = require('strapi-generate');
const createBuilder = require('./schema-builder');
const apiHandler = require('./api-handler');
const { formatAttributes, replaceTemporaryUIDs } = require('../utils/attributes');
const { nameToSlug } = require('../utils/helpers');
const { nameToSlug } = require('strapi-utils');
/**
* Format a contentType info to be used by the front-end

View File

@ -5,7 +5,7 @@ const _ = require('lodash');
const pluralize = require('pluralize');
const { isConfigurable } = require('../../utils/attributes');
const { nameToSlug, nameToCollectionName } = require('../../utils/helpers');
const { nameToSlug, nameToCollectionName } = require('strapi-utils');
const createSchemaHandler = require('./schema-handler');
module.exports = function createComponentBuilder() {

View File

@ -5,7 +5,7 @@ const _ = require('lodash');
const pluralize = require('pluralize');
const { isRelation, toUID, isConfigurable } = require('../../utils/attributes');
const { nameToSlug, nameToCollectionName } = require('../../utils/helpers');
const { nameToSlug, nameToCollectionName } = require('strapi-utils');
const { typeKinds } = require('../../controllers/validation/constants');
const createSchemaHandler = require('./schema-handler');

View File

@ -1,7 +1,5 @@
'use strict';
const slugify = require('@sindresorhus/slugify');
const escapeNewlines = (content = '', placeholder = '\n') => {
return content.replace(/[\r\n]+/g, placeholder);
};
@ -26,13 +24,8 @@ const deepTrimObject = attribute => {
* Converts a name to a slug
* @param {string} name a name to convert
*/
const nameToSlug = name => slugify(name, { separator: '-' });
const nameToCollectionName = name => slugify(name, { separator: '_' });
module.exports = {
escapeNewlines,
deepTrimObject,
nameToSlug,
nameToCollectionName,
};

View File

@ -44,6 +44,10 @@ module.exports = {
jwt: String!
user: UsersPermissionsMe!
}
type ForgotPassword {
ok: Boolean
}
`,
query: `
me: UsersPermissionsMe
@ -51,6 +55,9 @@ module.exports = {
mutation: `
login(input: UsersPermissionsLoginInput!): UsersPermissionsLoginPayload!
register(input: UserInput!): UsersPermissionsLoginPayload!
forgotPassword(email: String!): ForgotPassword
changePassword(password: String!, passwordConfirmation: String!, code: String!): UsersPermissionsLoginPayload
emailConfirmation(confirmation: String!): UsersPermissionsLoginPayload
`,
resolver: {
Query: {
@ -199,6 +206,56 @@ module.exports = {
};
},
},
forgotPassword: {
description: 'Request a reset password token',
resolverOf: 'plugins::users-permissions.auth.forgotPassword',
resolver: async (obj, options, { context }) => {
context.request.body = _.toPlainObject(options);
await strapi.plugins['users-permissions'].controllers.auth.forgotPassword(context);
let output = context.body.toJSON ? context.body.toJSON() : context.body;
checkBadRequest(output);
return {
ok: output.ok || output
};
}
},
changePassword: {
description: 'Change your password based on a code',
resolverOf: 'plugins::users-permissions.auth.changePassword',
resolver: async (obj, options, { context }) => {
context.request.body = _.toPlainObject(options);
await strapi.plugins['users-permissions'].controllers.auth.changePassword(context);
let output = context.body.toJSON ? context.body.toJSON() : context.body;
checkBadRequest(output);
return {
user: output.user || output,
jwt: output.jwt
};
}
},
emailConfirmation: {
description: 'Confirm an email users email address',
resolverOf: 'plugins::users-permissions.auth.emailConfirmation',
resolver: async (obj, options, { context }) => {
context.query = _.toPlainObject(options);
await strapi.plugins['users-permissions'].controllers.auth.emailConfirmation(context, true);
let output = context.body.toJSON ? context.body.toJSON() : context.body;
checkBadRequest(output);
return {
user: output.user || output,
jwt: output.jwt
};
}
}
},
},
};

View File

@ -568,18 +568,28 @@ module.exports = {
}
},
async emailConfirmation(ctx) {
async emailConfirmation(ctx, returnUser) {
const params = ctx.query;
const decodedToken = await strapi.plugins['users-permissions'].services.jwt.verify(
params.confirmation
);
await strapi.plugins['users-permissions'].services.user.edit(
let user = await strapi.plugins['users-permissions'].services.user.edit(
{ id: decodedToken.id },
{ confirmed: true }
);
if(returnUser) {
ctx.send({
jwt: strapi.plugins['users-permissions'].services.jwt.issue({
id: user.id
}),
user: sanitizeEntity(user.toJSON ? user.toJSON() : user, {
model: strapi.query('user', 'users-permissions').model
})
});
} else {
const settings = await strapi
.store({
environment: '',
@ -590,6 +600,7 @@ module.exports = {
.get();
ctx.redirect(settings.email_confirmation_redirection || '/');
}
},
async sendEmailConfirmation(ctx) {

View File

@ -48,8 +48,8 @@ module.exports = {
return new Promise((resolve, reject) => {
// Default values.
options = _.isObject(options) ? options : {};
options.from = options.from || config.amazon_ses_default_from;
options.replyTo = options.replyTo || config.amazon_ses_default_replyto;
options.from = config.amazon_ses_default_from || options.from;
options.replyTo = config.amazon_ses_default_replyto || options.replyTo;
options.text = options.text || options.html;
options.html = options.html || options.text;

View File

@ -15,6 +15,7 @@ const models = require('./models');
const policy = require('./policy');
const templateConfiguration = require('./templateConfiguration');
const { yup, formatYupErrors } = require('./validators');
const { nameToSlug, nameToCollectionName } = require('./stringFormatting');
module.exports = {
yup,
@ -29,4 +30,6 @@ module.exports = {
parseMultipartData,
sanitizeEntity,
parseType,
nameToSlug,
nameToCollectionName,
};

View File

@ -0,0 +1,12 @@
'use strict';
const slugify = require('@sindresorhus/slugify');
const nameToSlug = name => slugify(name, { separator: '-' });
const nameToCollectionName = name => slugify(name, { separator: '_' });
module.exports = {
nameToSlug,
nameToCollectionName,
};

View File

@ -14,6 +14,7 @@
},
"main": "./lib",
"dependencies": {
"@sindresorhus/slugify": "^0.11.0",
"date-fns": "^2.8.1",
"lodash": "4.17.12",
"pino": "^4.7.1",

View File

@ -56,14 +56,8 @@ module.exports = function(id, cliArguments) {
if (scope.generatorType !== 'new') {
logger.info(
'Generated a new ' +
scope.generatorType +
' `' +
scope.humanizeId +
'` at ' +
scope.humanizedPath +
'.'
); // eslint-disable-line prefer-template
`Generated a new ${scope.generatorType} \`${scope.name}\` at \`${scope.filePath}\`.`
);
}
process.exit(0);

View File

@ -2410,6 +2410,22 @@
escape-string-regexp "^1.0.5"
lodash.deburr "^4.1.0"
"@sindresorhus/slugify@^0.11.0":
version "0.11.0"
resolved "https://registry.yarnpkg.com/@sindresorhus/slugify/-/slugify-0.11.0.tgz#642acb99adefa4187285fd17de88745afc161de8"
integrity sha512-ECTZT6z1hYDsopRh8GECaQ5L6hoJHVd4uq5hPi8se9GB31tgtZfnlM8G64hZVhJNmtJ9eIK0SuNhtsaPQStXEQ==
dependencies:
"@sindresorhus/transliterate" "^0.1.0"
escape-string-regexp "^2.0.0"
"@sindresorhus/transliterate@^0.1.0":
version "0.1.0"
resolved "https://registry.yarnpkg.com/@sindresorhus/transliterate/-/transliterate-0.1.0.tgz#c063bfc4102783fb19c91c2f8c1efb3adfb754be"
integrity sha512-bO6v0M0EuJPjm5Ntfow4nk+r3EZQ41n0ahvAmh766FzPqlm6V/2uDc01vZI3gLeI/1lgV2BTMb6QvxOk9z73ng==
dependencies:
escape-string-regexp "^2.0.0"
lodash.deburr "^4.1.0"
"@snyk/cli-interface@1.5.0":
version "1.5.0"
resolved "https://registry.yarnpkg.com/@snyk/cli-interface/-/cli-interface-1.5.0.tgz#b9dbe6ebfb86e67ffabf29d4e0d28a52670ac456"
@ -6964,6 +6980,11 @@ escape-string-regexp@^1.0.2, escape-string-regexp@^1.0.5:
resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4"
integrity sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=
escape-string-regexp@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz#a30304e99daa32e23b2fd20f51babd07cffca344"
integrity sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==
escodegen@1.8.x:
version "1.8.1"
resolved "https://registry.yarnpkg.com/escodegen/-/escodegen-1.8.1.tgz#5a5b53af4693110bebb0867aa3430dd3b70a1018"