mirror of
https://github.com/strapi/strapi.git
synced 2025-09-24 16:04:54 +00:00
Merge pull request #8311 from strapi/cli/reset-admin-pwd
Reset admin password CLI
This commit is contained in:
commit
8b212d1e87
@ -32,7 +32,9 @@ options: [--no-run|--use-npm|--debug|--quickstart|--dbclient=<dbclient> --dbhost
|
||||
- **<dbssl>** and **<dbauth>** are available only for `mongo` and are optional.
|
||||
- **--dbforce** Allows you to overwrite content if the provided database is not empty. Only available for `postgres`, `mysql`, and is optional.
|
||||
|
||||
## strapi develop|dev
|
||||
## strapi develop
|
||||
|
||||
**Alias**: `dev`
|
||||
|
||||
Start a Strapi application with autoReload enabled.
|
||||
|
||||
@ -89,7 +91,9 @@ options: [--no-optimization]
|
||||
- **strapi build --no-optimization**<br/>
|
||||
Builds the administration panel without minimizing the assets. The build duration is faster.
|
||||
|
||||
## strapi configuration:dump|config:dump
|
||||
## strapi configuration:dump
|
||||
|
||||
**Alias**: `config:dump`
|
||||
|
||||
Dumps configurations to a file or stdout to help you migrate to production.
|
||||
|
||||
@ -120,7 +124,9 @@ In case of doubt, you should avoid committing the dump file into a versioning sy
|
||||
|
||||
:::
|
||||
|
||||
## strapi configuration:restore|config:restore
|
||||
## strapi configuration:restore
|
||||
|
||||
**Alias**: `config:restore`
|
||||
|
||||
Restores a configuration dump into your application.
|
||||
|
||||
@ -151,6 +157,27 @@ When running the restore command, you can choose from three different strategies
|
||||
- **merge**: Will create missing keys and merge existing keys with their new value.
|
||||
- **keep**: Will create missing keys and keep existing keys as is.
|
||||
|
||||
## strapi admin:reset-user-password
|
||||
|
||||
**Alias** `admin:reset-password`
|
||||
|
||||
Reset an admin user's password.
|
||||
You can pass the email and new password as options or set them interactivly if you call the command without passing the options.
|
||||
|
||||
**Example**
|
||||
|
||||
```bash
|
||||
strapi admin:reset-user-password --email=chef@strapi.io --password=Gourmet1234
|
||||
```
|
||||
|
||||
**Options**
|
||||
|
||||
| Option | Type | Description |
|
||||
| -------------- | ------ | ------------------------- |
|
||||
| -e, --email | string | The user email |
|
||||
| -p, --password | string | New password for the user |
|
||||
| -h, --help | | display help for command |
|
||||
|
||||
## strapi generate:api
|
||||
|
||||
Scaffold a complete API with its configurations, controller, model and service.
|
||||
|
@ -20,7 +20,7 @@
|
||||
"index.js"
|
||||
],
|
||||
"dependencies": {
|
||||
"commander": "^2.20.0",
|
||||
"commander": "6.1.0",
|
||||
"strapi-generate-new": "3.2.3"
|
||||
},
|
||||
"scripts": {
|
||||
|
@ -744,4 +744,86 @@ describe('User', () => {
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe('resetPasswordByEmail', () => {
|
||||
test('Throws on missing user', async () => {
|
||||
const email = 'email@email.fr';
|
||||
const password = 'invalidpass';
|
||||
|
||||
const findOne = jest.fn(() => {
|
||||
return null;
|
||||
});
|
||||
|
||||
global.strapi = {
|
||||
query() {
|
||||
return {
|
||||
findOne,
|
||||
};
|
||||
},
|
||||
};
|
||||
|
||||
await expect(userService.resetPasswordByEmail(email, password)).rejects.toEqual(
|
||||
new Error(`User not found for email: ${email}`)
|
||||
);
|
||||
|
||||
expect(findOne).toHaveBeenCalledWith({ email }, undefined);
|
||||
});
|
||||
|
||||
test.each(['abc', 'Abcd', 'Abcdefgh', 'Abcd123'])(
|
||||
'Throws on invalid password',
|
||||
async password => {
|
||||
const email = 'email@email.fr';
|
||||
|
||||
const findOne = jest.fn(() => ({ id: 1 }));
|
||||
|
||||
global.strapi = {
|
||||
query() {
|
||||
return {
|
||||
findOne,
|
||||
};
|
||||
},
|
||||
};
|
||||
|
||||
await expect(userService.resetPasswordByEmail(email, password)).rejects.toEqual(
|
||||
new Error(
|
||||
'Invalid password. Expected a minimum of 8 characters with at least one number and one uppercase letter'
|
||||
)
|
||||
);
|
||||
|
||||
expect(findOne).toHaveBeenCalledWith({ email }, undefined);
|
||||
}
|
||||
);
|
||||
});
|
||||
|
||||
test('Call the update function with the expected params', async () => {
|
||||
const email = 'email@email.fr';
|
||||
const password = 'Testing1234';
|
||||
const hash = 'hash';
|
||||
const userId = 1;
|
||||
|
||||
const findOne = jest.fn(() => ({ id: userId }));
|
||||
const update = jest.fn();
|
||||
const hashPassword = jest.fn(() => hash);
|
||||
|
||||
global.strapi = {
|
||||
query() {
|
||||
return {
|
||||
findOne,
|
||||
update,
|
||||
};
|
||||
},
|
||||
admin: {
|
||||
services: {
|
||||
auth: {
|
||||
hashPassword,
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
await userService.resetPasswordByEmail(email, password);
|
||||
expect(findOne).toHaveBeenCalledWith({ email }, undefined);
|
||||
expect(update).toHaveBeenCalledWith({ id: userId }, { password: hash });
|
||||
expect(hashPassword).toHaveBeenCalledWith(password);
|
||||
});
|
||||
});
|
||||
|
@ -4,6 +4,7 @@ const _ = require('lodash');
|
||||
const { stringIncludes } = require('strapi-utils');
|
||||
const { createUser, hasSuperAdminRole } = require('../domain/user');
|
||||
const { SUPER_ADMIN_CODE } = require('./constants');
|
||||
const { password: passwordValidator } = require('../validation/common-validators');
|
||||
|
||||
const sanitizeUserRoles = role => _.pick(role, ['id', 'name', 'description', 'code']);
|
||||
|
||||
@ -43,7 +44,7 @@ const create = async attributes => {
|
||||
|
||||
/**
|
||||
* Update a user in database
|
||||
* @param params query params to find the user to update
|
||||
* @param id query params to find the user to update
|
||||
* @param attributes A partial user object
|
||||
* @returns {Promise<user>}
|
||||
*/
|
||||
@ -89,6 +90,29 @@ const updateById = async (id, attributes) => {
|
||||
return strapi.query('user', 'admin').update({ id }, attributes);
|
||||
};
|
||||
|
||||
/**
|
||||
* Reset a user password by email. (Used in admin:reset CLI)
|
||||
* @param {string} email - user email
|
||||
* @param {string} password - new password
|
||||
*/
|
||||
const resetPasswordByEmail = async (email, password) => {
|
||||
const user = await findOne({ email });
|
||||
|
||||
if (!user) {
|
||||
throw new Error(`User not found for email: ${email}`);
|
||||
}
|
||||
|
||||
try {
|
||||
await passwordValidator.validate(password);
|
||||
} catch (error) {
|
||||
throw new Error(
|
||||
'Invalid password. Expected a minimum of 8 characters with at least one number and one uppercase letter'
|
||||
);
|
||||
}
|
||||
|
||||
await updateById(user.id, { password });
|
||||
};
|
||||
|
||||
/**
|
||||
* Check if a user is the last super admin
|
||||
* @param {int|string} userId user's id to look for
|
||||
@ -320,4 +344,5 @@ module.exports = {
|
||||
assignARoleToAll,
|
||||
displayWarningIfUsersDontHaveRole,
|
||||
migrateUsers,
|
||||
resetPasswordByEmail,
|
||||
};
|
||||
|
@ -4,18 +4,11 @@
|
||||
const _ = require('lodash');
|
||||
const resolveCwd = require('resolve-cwd');
|
||||
const { yellow } = require('chalk');
|
||||
const program = require('commander');
|
||||
const { Command } = require('commander');
|
||||
const program = new Command();
|
||||
|
||||
const packageJSON = require('../package.json');
|
||||
|
||||
// Allow us to display `help()`, but omit the wildcard (`*`) command.
|
||||
program.Command.prototype.usageMinusWildcard = program.usageMinusWildcard = () => {
|
||||
program.commands = _.reject(program.commands, {
|
||||
_name: '*',
|
||||
});
|
||||
program.help();
|
||||
};
|
||||
|
||||
const checkCwdIsStrapiApp = name => {
|
||||
let logErrorAndExit = () => {
|
||||
console.log(
|
||||
@ -61,37 +54,29 @@ const getLocalScript = name => (...args) => {
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Normalize version argument
|
||||
*
|
||||
* `$ strapi -v`
|
||||
* `$ strapi -V`
|
||||
* `$ strapi --version`
|
||||
* `$ strapi version`
|
||||
*/
|
||||
// Initial program setup
|
||||
program
|
||||
.storeOptionsAsProperties(false)
|
||||
.passCommandToAction(false)
|
||||
.allowUnknownOption(true);
|
||||
|
||||
program.allowUnknownOption(true);
|
||||
|
||||
// Expose version.
|
||||
program.version(packageJSON.version, '-v, --version');
|
||||
|
||||
// Make `-v` option case-insensitive.
|
||||
process.argv = _.map(process.argv, arg => {
|
||||
return arg === '-V' ? '-v' : arg;
|
||||
});
|
||||
program.helpOption('-h, --help', 'Display help for command');
|
||||
program.addHelpCommand('help [command]', 'Display help for command');
|
||||
|
||||
// `$ strapi version` (--version synonym)
|
||||
program.option('-v, --version', 'Output the version number');
|
||||
program
|
||||
.command('version')
|
||||
.description('output your version of Strapi')
|
||||
.description('Output your version of Strapi')
|
||||
.action(() => {
|
||||
console.log(packageJSON.version);
|
||||
process.stdout.write(packageJSON.version + '\n');
|
||||
process.exit(0);
|
||||
});
|
||||
|
||||
// `$ strapi console`
|
||||
program
|
||||
.command('console')
|
||||
.description('open the Strapi framework console')
|
||||
.description('Open the Strapi framework console')
|
||||
.action(getLocalScript('console'));
|
||||
|
||||
// `$ strapi new`
|
||||
@ -112,7 +97,7 @@ program
|
||||
.option('--dbauth <dbauth>', 'Authentication Database')
|
||||
.option('--dbfile <dbfile>', 'Database file path for sqlite')
|
||||
.option('--dbforce', 'Overwrite database content if any')
|
||||
.description('create a new application')
|
||||
.description('Create a new application')
|
||||
.action(require('../lib/commands/new'));
|
||||
|
||||
// `$ strapi start`
|
||||
@ -125,8 +110,8 @@ program
|
||||
program
|
||||
.command('develop')
|
||||
.alias('dev')
|
||||
.option('--no-build', 'Disable build', false)
|
||||
.option('--watch-admin', 'Enable watch', true)
|
||||
.option('--no-build', 'Disable build')
|
||||
.option('--watch-admin', 'Enable watch', false)
|
||||
.option('--browser <name>', 'Open the browser', true)
|
||||
.description('Start your Strapi application in development mode')
|
||||
.action(getLocalScript('develop'));
|
||||
@ -138,8 +123,8 @@ program
|
||||
.option('-p, --plugin <api>', 'Name of the local plugin')
|
||||
.option('-e, --extend <api>', 'Name of the plugin to extend')
|
||||
.option('-c, --connection <connection>', 'The name of the connection to use')
|
||||
.option('--draft-and-publish <value>', 'Enable draft/publish', false)
|
||||
.description('generate a basic API')
|
||||
.option('--draft-and-publish', 'Enable draft/publish', false)
|
||||
.description('Generate a basic API')
|
||||
.action((id, attributes, cliArguments) => {
|
||||
cliArguments.attributes = attributes;
|
||||
getLocalScript('generate')(id, cliArguments);
|
||||
@ -151,7 +136,7 @@ program
|
||||
.option('-a, --api <api>', 'API name to generate the files in')
|
||||
.option('-p, --plugin <api>', 'Name of the local plugin')
|
||||
.option('-e, --extend <api>', 'Name of the plugin to extend')
|
||||
.description('generate a controller for an API')
|
||||
.description('Generate a controller for an API')
|
||||
.action(getLocalScript('generate'));
|
||||
|
||||
// `$ strapi generate:model`
|
||||
@ -160,8 +145,8 @@ program
|
||||
.option('-a, --api <api>', 'API name to generate a sub API')
|
||||
.option('-p, --plugin <api>', 'plugin name')
|
||||
.option('-c, --connection <connection>', 'The name of the connection to use')
|
||||
.option('--draft-and-publish <value>', 'Enable draft/publish', false)
|
||||
.description('generate a model for an API')
|
||||
.option('--draft-and-publish', 'Enable draft/publish', false)
|
||||
.description('Generate a model for an API')
|
||||
.action((id, attributes, cliArguments) => {
|
||||
cliArguments.attributes = attributes;
|
||||
getLocalScript('generate')(id, cliArguments);
|
||||
@ -172,7 +157,7 @@ program
|
||||
.command('generate:policy <id>')
|
||||
.option('-a, --api <api>', 'API name')
|
||||
.option('-p, --plugin <api>', 'plugin name')
|
||||
.description('generate a policy for an API')
|
||||
.description('Generate a policy for an API')
|
||||
.action(getLocalScript('generate'));
|
||||
|
||||
// `$ strapi generate:service`
|
||||
@ -181,33 +166,33 @@ program
|
||||
.option('-a, --api <api>', 'API name')
|
||||
.option('-p, --plugin <api>', 'plugin name')
|
||||
.option('-t, --tpl <template>', 'template name')
|
||||
.description('generate a service for an API')
|
||||
.description('Generate a service for an API')
|
||||
.action(getLocalScript('generate'));
|
||||
|
||||
// `$ strapi generate:plugin`
|
||||
program
|
||||
.command('generate:plugin <id>')
|
||||
.option('-n, --name <name>', 'Plugin name')
|
||||
.description('generate a basic plugin')
|
||||
.description('Generate a basic plugin')
|
||||
.action(getLocalScript('generate'));
|
||||
|
||||
program
|
||||
.command('build')
|
||||
.option('--clean', 'Remove the build and .cache folders', false)
|
||||
.option('--no-optimization', 'Build the Administration without assets optimization', false)
|
||||
.option('--no-optimization', 'Build the Administration without assets optimization')
|
||||
.description('Builds the strapi admin app')
|
||||
.action(getLocalScript('build'));
|
||||
|
||||
// `$ strapi install`
|
||||
program
|
||||
.command('install [plugins...]')
|
||||
.description('install a Strapi plugin')
|
||||
.description('Install a Strapi plugin')
|
||||
.action(getLocalScript('install'));
|
||||
|
||||
// `$ strapi uninstall`
|
||||
program
|
||||
.command('uninstall [plugins...]')
|
||||
.description('uninstall a Strapi plugin')
|
||||
.description('Uninstall a Strapi plugin')
|
||||
.option('-d, --delete-files', 'Delete files', false)
|
||||
.action(getLocalScript('uninstall'));
|
||||
|
||||
@ -221,38 +206,25 @@ program
|
||||
program
|
||||
.command('configuration:dump')
|
||||
.alias('config:dump')
|
||||
.description('Dump configurations of your application')
|
||||
.option('-f, --file <file>', 'Output file, default output is stdout')
|
||||
.action(getLocalScript('configurationDump'));
|
||||
|
||||
program
|
||||
.command('configuration:restore')
|
||||
.alias('config:restore')
|
||||
.description('Restore configurations of your application')
|
||||
.option('-f, --file <file>', 'Input file, default input is stdin')
|
||||
.option('-s, --strategy <strategy>', 'Strategy name, one of: "replace", "merge", "keep"')
|
||||
.action(getLocalScript('configurationRestore'));
|
||||
|
||||
/**
|
||||
* Normalize help argument
|
||||
*/
|
||||
|
||||
// `$ strapi help` (--help synonym)
|
||||
// Admin
|
||||
program
|
||||
.command('help')
|
||||
.description('output the help')
|
||||
.action(program.usageMinusWildcard);
|
||||
.command('admin:reset-user-password')
|
||||
.alias('admin:reset-password')
|
||||
.description("Reset an admin user's password")
|
||||
.option('-e, --email <email>', 'The user email')
|
||||
.option('-p, --password <password>', 'New password for the user')
|
||||
.action(getLocalScript('admin-reset'));
|
||||
|
||||
// `$ strapi <unrecognized_cmd>`
|
||||
// Mask the '*' in `help`.
|
||||
program.command('*').action(program.usageMinusWildcard);
|
||||
|
||||
// Don't balk at unknown options.
|
||||
|
||||
/**
|
||||
* `$ strapi`
|
||||
*/
|
||||
|
||||
program.parse(process.argv);
|
||||
const NO_COMMAND_SPECIFIED = program.args.length === 0;
|
||||
if (NO_COMMAND_SPECIFIED) {
|
||||
program.usageMinusWildcard();
|
||||
}
|
||||
program.parseAsync(process.argv);
|
||||
|
141
packages/strapi/lib/commands/__tests__/admin-reset.test.js
Normal file
141
packages/strapi/lib/commands/__tests__/admin-reset.test.js
Normal file
@ -0,0 +1,141 @@
|
||||
'use strict';
|
||||
|
||||
const load = jest.fn(() => mock);
|
||||
const resetPasswordByEmail = jest.fn();
|
||||
const admin = {
|
||||
services: {
|
||||
user: {
|
||||
resetPasswordByEmail,
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
const mock = {
|
||||
load,
|
||||
admin,
|
||||
};
|
||||
|
||||
jest.mock('../../index', () => {
|
||||
return jest.fn(() => mock);
|
||||
});
|
||||
|
||||
const inquirer = require('inquirer');
|
||||
const resetAdminPasswordCommand = require('../admin-reset');
|
||||
|
||||
describe('admin:reset-password command', () => {
|
||||
beforeEach(() => {
|
||||
load.mockClear();
|
||||
resetPasswordByEmail.mockClear();
|
||||
});
|
||||
|
||||
test('resetAdminPasswordCommand accepts direct input', async () => {
|
||||
const email = 'email@email.fr';
|
||||
const password = 'testPasword1234';
|
||||
|
||||
const mockExit = jest.spyOn(process, 'exit').mockImplementation(() => {});
|
||||
const consoleLog = jest.spyOn(console, 'log').mockImplementation(() => {});
|
||||
|
||||
await resetAdminPasswordCommand({ email, password });
|
||||
|
||||
expect(mockExit).toHaveBeenCalledWith(0);
|
||||
expect(consoleLog).toHaveBeenCalled();
|
||||
expect(load).toHaveBeenCalled();
|
||||
expect(resetPasswordByEmail).toHaveBeenCalledWith(email, password);
|
||||
|
||||
mockExit.mockRestore();
|
||||
consoleLog.mockRestore();
|
||||
});
|
||||
|
||||
describe('Handles prompt input', () => {
|
||||
test('Only prompt on TTY', async () => {
|
||||
const tmpTTY = process.stdin.isTTY;
|
||||
process.stdin.isTTY = false;
|
||||
|
||||
// throw so the code will stop executing
|
||||
const mockExit = jest.spyOn(process, 'exit').mockImplementation(() => {
|
||||
throw new Error('exit');
|
||||
});
|
||||
|
||||
const consoleError = jest.spyOn(console, 'error').mockImplementation(() => {});
|
||||
|
||||
await resetAdminPasswordCommand().catch(err => {
|
||||
expect(err).toEqual(new Error('exit'));
|
||||
});
|
||||
|
||||
expect(consoleError).toBeCalledWith('Missing required options `email` or `password`');
|
||||
expect(mockExit).toHaveBeenCalledWith(1);
|
||||
expect(load).not.toHaveBeenCalled();
|
||||
expect(resetPasswordByEmail).not.toHaveBeenCalled();
|
||||
|
||||
process.stdin.isTTY = tmpTTY;
|
||||
mockExit.mockRestore();
|
||||
consoleError.mockRestore();
|
||||
});
|
||||
|
||||
test('Stops if not confirmed', async () => {
|
||||
process.stdin.isTTY = true;
|
||||
const email = 'email@email.fr';
|
||||
const password = 'testPasword1234';
|
||||
|
||||
const mockInquiry = jest
|
||||
.spyOn(inquirer, 'prompt')
|
||||
.mockImplementationOnce(async () => ({ email, password, confirm: false }));
|
||||
|
||||
// throw so the code will stop executing
|
||||
const mockExit = jest.spyOn(process, 'exit').mockImplementation(() => {
|
||||
throw new Error('exit');
|
||||
});
|
||||
|
||||
await resetAdminPasswordCommand().catch(err => {
|
||||
expect(err).toEqual(new Error('exit'));
|
||||
});
|
||||
|
||||
expect(mockInquiry).toHaveBeenLastCalledWith([
|
||||
expect.objectContaining({
|
||||
message: expect.any(String),
|
||||
name: 'email',
|
||||
type: 'input',
|
||||
}),
|
||||
expect.objectContaining({
|
||||
message: expect.any(String),
|
||||
name: 'password',
|
||||
type: 'password',
|
||||
}),
|
||||
expect.objectContaining({
|
||||
message: expect.any(String),
|
||||
name: 'confirm',
|
||||
type: 'confirm',
|
||||
}),
|
||||
]);
|
||||
expect(mockExit).toHaveBeenCalledWith(0);
|
||||
expect(load).not.toHaveBeenCalled();
|
||||
expect(resetPasswordByEmail).not.toHaveBeenCalled();
|
||||
|
||||
mockExit.mockRestore();
|
||||
mockInquiry.mockRestore();
|
||||
});
|
||||
|
||||
test('Calls the reset method with user input', async () => {
|
||||
const email = 'email@email.fr';
|
||||
const password = 'testPasword1234';
|
||||
|
||||
const mockInquiry = jest
|
||||
.spyOn(inquirer, 'prompt')
|
||||
.mockImplementationOnce(async () => ({ email, password, confirm: true }));
|
||||
|
||||
const mockExit = jest.spyOn(process, 'exit').mockImplementation(() => {});
|
||||
const consoleLog = jest.spyOn(console, 'log').mockImplementation(() => {});
|
||||
|
||||
await resetAdminPasswordCommand();
|
||||
|
||||
expect(mockExit).toHaveBeenCalledWith(0);
|
||||
expect(consoleLog).toHaveBeenCalled();
|
||||
expect(load).toHaveBeenCalled();
|
||||
expect(resetPasswordByEmail).toHaveBeenCalledWith(email, password);
|
||||
|
||||
mockInquiry.mockRestore();
|
||||
mockExit.mockRestore();
|
||||
consoleLog.mockRestore();
|
||||
});
|
||||
});
|
||||
});
|
51
packages/strapi/lib/commands/admin-reset.js
Normal file
51
packages/strapi/lib/commands/admin-reset.js
Normal file
@ -0,0 +1,51 @@
|
||||
'use strict';
|
||||
|
||||
const _ = require('lodash');
|
||||
const inquirer = require('inquirer');
|
||||
const strapi = require('../index');
|
||||
|
||||
const promptQuestions = [
|
||||
{ type: 'input', name: 'email', message: 'User email?' },
|
||||
{ type: 'password', name: 'password', message: 'New password?' },
|
||||
{
|
||||
type: 'confirm',
|
||||
name: 'confirm',
|
||||
message: "Do you really want to reset this user's password?",
|
||||
},
|
||||
];
|
||||
|
||||
/**
|
||||
* Reset user's password
|
||||
* @param {Object} cmdOptions - command options
|
||||
* @param {string} cmdOptions.email - user's email
|
||||
* @param {string} cmdOptions.password - user's new password
|
||||
*/
|
||||
module.exports = async function(cmdOptions = {}) {
|
||||
const { email, password } = cmdOptions;
|
||||
|
||||
if (_.isEmpty(email) && _.isEmpty(password) && process.stdin.isTTY) {
|
||||
const inquiry = await inquirer.prompt(promptQuestions);
|
||||
|
||||
if (!inquiry.confirm) {
|
||||
process.exit(0);
|
||||
}
|
||||
|
||||
return changePassword(inquiry);
|
||||
}
|
||||
|
||||
if (_.isEmpty(email) || _.isEmpty(password)) {
|
||||
console.error('Missing required options `email` or `password`');
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
return changePassword({ email, password });
|
||||
};
|
||||
|
||||
async function changePassword({ email, password }) {
|
||||
const app = await strapi().load();
|
||||
|
||||
await app.admin.services.user.resetPasswordByEmail(email, password);
|
||||
|
||||
console.log(`Successfully reset user's password`);
|
||||
process.exit(0);
|
||||
}
|
@ -19,7 +19,7 @@
|
||||
"chokidar": "3.3.1",
|
||||
"ci-info": "2.0.0",
|
||||
"cli-table3": "^0.6.0",
|
||||
"commander": "^2.20.0",
|
||||
"commander": "6.1.0",
|
||||
"cross-spawn": "^6.0.5",
|
||||
"debug": "^4.1.1",
|
||||
"delegates": "^1.0.0",
|
||||
|
@ -5651,6 +5651,11 @@ commander@2.3.0:
|
||||
resolved "https://registry.yarnpkg.com/commander/-/commander-2.3.0.tgz#fd430e889832ec353b9acd1de217c11cb3eef873"
|
||||
integrity sha1-/UMOiJgy7DU7ms0d4hfBHLPu+HM=
|
||||
|
||||
commander@6.1.0:
|
||||
version "6.1.0"
|
||||
resolved "https://registry.yarnpkg.com/commander/-/commander-6.1.0.tgz#f8d722b78103141006b66f4c7ba1e97315ba75bc"
|
||||
integrity sha512-wl7PNrYWd2y5mp1OK/LhTlv8Ff4kQJQRXXAvF+uU/TPNiVJUxZLRYGj/B0y/lPGAVcSbJqH2Za/cvHmrPMC8mA==
|
||||
|
||||
commander@^2.19.0, commander@^2.20.0, commander@^2.20.3:
|
||||
version "2.20.3"
|
||||
resolved "https://registry.yarnpkg.com/commander/-/commander-2.20.3.tgz#fd485e84c03eb4881c20722ba48035e8531aeb33"
|
||||
|
Loading…
x
Reference in New Issue
Block a user