Closed abdonrd closed 4 years ago
Hello @abdonrd , can you please share a use case.
Right now, we have an application where the users do not have email. They only have name and username.
Okay and you want this feature available from the admin panel.
The workaround is to customize the extensions/users-permissions/models/User.settings.json
and to set the required value of email to false.
Then to customize the register function and remove the email validation.
Marking as closed as this is a niche use-case that will always require customization as we need to have one main required field for the user. Most of the code-base uses email (including the admin panel, where the username is not required).
In the case of 3rd party auth, email is almost exclusively unique and usernames are not.
Why don't you just make the User table fully customizable? I really don't understand why it is completely locked I am doing an application where i really don't even want an User table with this format and it is a bit annoying that it can't be easily changed
I do support last comment
I also. I'm making an app, and I don't need an email. It would be a lot easier for me If I could just remove all the email stuff.
After change as you mention, in strapi version 4.1.12 when create user show again error the email required
Did anyone find a solution in Strapi 4 to set username not required?
In my application, I create users via telegram by phone number, the user's email also interferes.
I have some applications using MetaMask authentication and therefore there is no need for an email. Also have some applications where I just don't need a username - only email and password.
Does anyone have a solution for this problem in 2023?
Only changing the schema.json on "src/extensions/users-permissions/content-types/user/schema.json" doesn't work anymore
I tried to change to "required": false
or "unique": false,
, but the admin interface seems to change but the validation still occours
Does anyone have a solution for this problem in 2023?
Only changing the schema.json on "src/extensions/users-permissions/content-types/user/schema.json" doesn't work anymore
I tried to change to
"required": false
or"unique": false,
, but the admin interface seems to change but the validation still occours
have you tried running yarn build
/ npm run build
after you've changed the schema.json
?
Build doesn't do anything for the backend, all it does is build the admin panel.
Currently it isn't really possible to completely disable it as it's basically hard coded into the plugin to require it but we are working on plans to build an entirely new plugin that will replace the current one.
When you build an entirely new plugin, please also add support for adding or saving metadata from OAuth's to the user. For example: When a user logging in using discord I'd like to get and safe his discord_id in some way. Currently I have to patch the user-permissions plugin to be able to which isn't that cool tbh 💀
Yeah. The issue with is that so need a required, unique filed, and currently it is the email field. I think that in the new version strapi should allow editing the User table, and just required the admin to set a field which will be used to identify a user. As you saw in the comments it doesn't need to be an email and possibilities are endless, it could ba a phone number, some id, unique tag etc.
If I can set the email to not be unique, I can make a workaround and put some admin email in always account, but even that I can't do, and it's complicated if you are doing some other use cases and your users don't have emails.
I think if we can choose to email not be unique, we can make a workaround and don't need to do a big modification on the plugin, because email will continue to be required.
It's 2024 and this is still a very much needed customization. I don't agree that it's niche - there are many applications I can think of that do not and should not require an email to use
I found a workaround if anyone is interested:
Change configurable
to false and required
to true in server/src/extensions/users-permissions/content-types/user/schema.json
and then go into the admin portal and delete the email field. Allow the server to restart, then re-add the email field but keep "Unique field" unchecked.
I found a workaround if anyone is interested:如果有人感兴趣,我找到了一个解决方法:
Change
configurable
to false andrequired
to true inserver/src/extensions/users-permissions/content-types/user/schema.json
and then go into the admin portal and delete the email field. Allow the server to restart, then re-add the email field but keep "Unique field" unchecked.更改configurable
为 false 和required
true inserver/src/extensions/users-permissions/content-types/user/schema.json
,然后进入管理门户并删除电子邮件字段。允许服务器重新启动,然后重新添加电子邮件字段,但保持“唯一字段”未选中。
此方法不管用了,我的Strapi版本是4.14.4
Hey I was able to solve this using these workaround. My answer may not be much well written because this is my first time I am answering somewhere but yeah it will surely help you.
So firstly change the node_modules\@strapi\plugin-users-permissions\server\content-types\user\index.js
file
username: {
type: 'string',
minLength: 3,
unique: true,
configurable: false,
required: false,
},
email: {
type: 'email',
minLength: 6,
configurable: false,
required: false,
},
Next in file node_modules\@strapi\plugin-users-permissions\server\controllers\content-manager-user.js
Update this file as (Just commenting out some code related to email and username validation)
'use strict';
const _ = require('lodash');
const { contentTypes: contentTypesUtils } = require('@strapi/utils');
const { ApplicationError, ValidationError, NotFoundError, ForbiddenError } =
require('@strapi/utils').errors;
const { validateCreateUserBody, validateUpdateUserBody } = require('./validation/user');
const { UPDATED_BY_ATTRIBUTE, CREATED_BY_ATTRIBUTE } = contentTypesUtils.constants;
const userModel = 'plugin::users-permissions.user';
const ACTIONS = {
read: 'plugin::content-manager.explorer.read',
create: 'plugin::content-manager.explorer.create',
edit: 'plugin::content-manager.explorer.update',
delete: 'plugin::content-manager.explorer.delete',
};
const findEntityAndCheckPermissions = async (ability, action, model, id) => {
const entity = await strapi.query(userModel).findOne({
where: { id },
populate: [`${CREATED_BY_ATTRIBUTE}.roles`],
});
if (_.isNil(entity)) {
throw new NotFoundError();
}
const pm = strapi.admin.services.permission.createPermissionsManager({ ability, action, model });
if (pm.ability.cannot(pm.action, pm.toSubject(entity))) {
throw new ForbiddenError();
}
const entityWithoutCreatorRoles = _.omit(entity, `${CREATED_BY_ATTRIBUTE}.roles`);
return { pm, entity: entityWithoutCreatorRoles };
};
module.exports = {
/**
* Create a/an user record.
* @return {Object}
*/
async create(ctx) {
const { body } = ctx.request;
const { user: admin, userAbility } = ctx.state;
const pm = strapi.admin.services.permission.createPermissionsManager({
ability: userAbility,
action: ACTIONS.create,
model: userModel,
});
if (!pm.isAllowed) {
return ctx.forbidden();
}
const sanitizedBody = await pm.pickPermittedFieldsOf(body, { subject: userModel });
const advanced = await strapi
.store({ type: 'plugin', name: 'users-permissions', key: 'advanced' })
.get();
// await validateCreateUserBody(ctx.request.body);
// const userWithSameUsername = await strapi
// .query('plugin::users-permissions.user')
// .findOne({ where: { username } });
// if (userWithSameUsername) {
// throw new ApplicationError('Username already taken');
// }
// if (advanced.unique_email) {
// const userWithSameEmail = await strapi
// .query('plugin::users-permissions.user')
// .findOne({ where: { email: email.toLowerCase() } });
// if (userWithSameEmail) {
// throw new ApplicationError('Email already taken');
// }
// }
const user = {
...sanitizedBody,
provider: 'local',
[CREATED_BY_ATTRIBUTE]: admin.id,
[UPDATED_BY_ATTRIBUTE]: admin.id,
};
// user.email = _.toLower(user.email);
if (!user.role) {
const defaultRole = await strapi
.query('plugin::users-permissions.role')
.findOne({ where: { type: advanced.default_role } });
user.role = defaultRole.id;
}
try {
const data = await strapi
.service('plugin::content-manager.entity-manager')
.create(user, userModel);
const sanitizedData = await pm.sanitizeOutput(data, { action: ACTIONS.read });
ctx.created(sanitizedData);
} catch (error) {
throw new ApplicationError(error.message);
}
},
/**
* Update a/an user record.
* @return {Object}
*/
async update(ctx) {
const { id } = ctx.params;
const { body } = ctx.request;
const { user: admin, userAbility } = ctx.state;
const advancedConfigs = await strapi
.store({ type: 'plugin', name: 'users-permissions', key: 'advanced' })
.get();
// const { email, username, password } = body;
const { pm, entity } = await findEntityAndCheckPermissions(
userAbility,
ACTIONS.edit,
userModel,
id
);
const user = entity;
// await validateUpdateUserBody(ctx.request.body);
// if (_.has(body, 'password') && !password && user.provider === 'local') {
// throw new ValidationError('password.notNull');
// }
// if (_.has(body, 'username')) {
// const userWithSameUsername = await strapi
// .query('plugin::users-permissions.user')
// .findOne({ where: { username } });
// if (userWithSameUsername && _.toString(userWithSameUsername.id) !== _.toString(id)) {
// throw new ApplicationError('Username already taken');
// }
// }
// if (_.has(body, 'email') && advancedConfigs.unique_email) {
// const userWithSameEmail = await strapi
// .query('plugin::users-permissions.user')
// .findOne({ where: { email: _.toLower(email) } });
// if (userWithSameEmail && _.toString(userWithSameEmail.id) !== _.toString(id)) {
// throw new ApplicationError('Email already taken');
// }
// body.email = _.toLower(body.email);
// }
const sanitizedData = await pm.pickPermittedFieldsOf(body, { subject: pm.toSubject(user) });
const updateData = _.omit({ ...sanitizedData, updatedBy: admin.id }, 'createdBy');
const data = await strapi
.service('plugin::content-manager.entity-manager')
.update({ id }, updateData, userModel);
ctx.body = await pm.sanitizeOutput(data, { action: ACTIONS.read });
},
};
Now we can update the code in node_modules\@strapi\plugin-users-permissions\server\content-types\user\index.js
file
I dont think this step is necessary as we have already commented out the code using functions from this file but still there may be any other file using this functions, so I still changed it
'use strict';
const { yup, validateYupSchema } = require('@strapi/utils');
const deleteRoleSchema = yup.object().shape({
role: yup.strapiID().required(),
});
const createUserBodySchema = yup.object().shape({
email: yup.string().email().optional(),
username: yup.string().optional(),
password: yup.string().optional(),
role: yup.lazy((value) =>
typeof value === 'object'
? yup
.object()
.shape({
connect: yup
.array()
.of(yup.object().shape({ id: yup.strapiID().required() }))
.min(1, 'Users must have a role')
.required(),
})
.required()
: yup.strapiID().required()
),
});
const updateUserBodySchema = yup.object().shape({
email: yup.string().email().optional(),
username: yup.string().optional(),
password: yup.string().optional(),
role: yup.lazy((value) =>
typeof value === 'object'
? yup.object().shape({
connect: yup
.array()
.of(yup.object().shape({ id: yup.strapiID().required() }))
.required(),
disconnect: yup
.array()
.test('CheckDisconnect', 'Cannot remove role', function test(disconnectValue) {
if (value.connect.length === 0 && disconnectValue.length > 0) {
return false;
}
return true;
})
.required(),
})
: yup.strapiID()
),
});
module.exports = {
validateCreateUserBody: validateYupSchema(createUserBodySchema),
validateUpdateUserBody: validateYupSchema(updateUserBodySchema),
validateDeleteRoleBody: validateYupSchema(deleteRoleSchema),
};
Please describe your feature request:
Allow change user email as non required field.