There is a massive issue with the code you provide: the already existing data in your user will be overwritten by the PUT/update. So username, email or first and last names that where already there for example if you just registered, now they are deleted by the update, because the { } in the payload doesn't consider previous data (which obviously the user wont want to change) and sets it to null or undefined. So here is the code change to the code he shared in the video. Following is the code I've used. Create a file called strapi-server.js in the folder: extensions>users-permissions. module.exports = (plugin) => { plugin.controllers.user.updateMe = async (ctx) => { if (!ctx.state.user || !ctx.state.user.id) { return ctx.response.status = 401; } // Extract only the fields that need to be updated from the request body const updatedUserData = { // ...ctx.request.body, firstname: (ctx.state.user.firstname || ctx.request.body.firstname), lastname: ctx.state.user.lastname || ctx.request.body.lastname, username: ctx.state.user.username || ctx.request.body.username, email: ctx.state.user.email || ctx.request.body.email, // change the above code to reflect the fields you want the user to be able to update. }; try { // Update the user data in the database await strapi.query('plugin::users-permissions.user').update({ where: { id: ctx.state.user.id }, data: updatedUserData, }); ctx.response.status = 200; } catch (error) { console.error('Error updating user data:', error); ctx.response.status = 500; } }; plugin.routes['content-api'].routes.push( { method: "PUT", path: "/user/me", handler: "user.updateMe", config: { prefix: "", policies: [] } }); return plugin; }
Heyo, just so you know you could use /users/me but instead of .push you use .unshift to put it at the top of the routes array. Since koa routes use regex matching, it won't conflict then with the regular put methods.
This works, however, the user is now able to change the username even if it already exists. How can we prevent the user from updating to a username that already exists?
You can do it by destructuring the certain properties from ctx.request.body and setting them back in ctx.request.body. But I am concerned about the default update method, there you can change anything, role username password everything and anyones credentials. Is there any way to overwrite the default routes instead of creating a new one?
Agreed. There is a huge issue here, all already existing data in the user/me is overwritten by the PUT. So username, email or first and last names that where already there from registration; now they are deleted by the update, because the { } in the payload doesn't consider previous data and sets it to null or undefined.
I just wanted to let you know that I'm not at the moment. But that is great feedback. We try to keep our example using JS to make it more accessible to folk of different levels. But we should consider making more Strapi TS examples.
I have a problem.. I use typescript and I am unable to start my server if i call the strapi entity service inside the strapi-server.ts file. In order to get it to work, I have to add this comment above the query call // @ts-ignore. Is there a better way to do this in a TS file?
Use Strapis Entity Service API instead of query. Unfortunately Strapi gives a s# on updating their guides. Its a big mess and faaaaar away from out of the box. I would recommend using strapi but not within the next three years.
How is this not implemented by default..
How are this channel videos not getting enough traction. It is so helpful. Keep it going man. Know you are helping me out.
dont work this implementation in last version of strapi? why?
Entity Service Api
@@st_bakerino please expain more.
@@xnomycc.4701 Strapi V5 now use document service api instead of entity service api
here's version for Strapi V5:
```
export default (plugin) => {
plugin.controllers.user.updateMe = async (ctx) => {
try {
const user = ctx.state.user;
if (!user) {
return ctx.unauthorized(
"You must be logged in to update your profile."
);
}
const data = ctx.request.body;
const updatedUser = await strapi
.documents("plugin::users-permissions.user")
.update({
documentId: user.documentId,
data,
});
return ctx.send(updatedUser);
} catch (err) {
console.error("Error updating user:", err);
return ctx.badRequest("Unable to update user.");
}
};
plugin.routes["content-api"].routes.push({
method: "PUT",
path: "/user/me",
handler: "user.updateMe",
config: {
prefix: "",
policies: [],
},
});
return plugin;
};
```
@@andrej.surfer Thanks, man! You're a timesaver))
There is a massive issue with the code you provide: the already existing data in your user will be overwritten by the PUT/update. So username, email or first and last names that where already there for example if you just registered, now they are deleted by the update, because the { } in the payload doesn't consider previous data (which obviously the user wont want to change) and sets it to null or undefined.
So here is the code change to the code he shared in the video. Following is the code I've used. Create a file called strapi-server.js in the folder: extensions>users-permissions.
module.exports = (plugin) => {
plugin.controllers.user.updateMe = async (ctx) => {
if (!ctx.state.user || !ctx.state.user.id) {
return ctx.response.status = 401;
}
// Extract only the fields that need to be updated from the request body
const updatedUserData = {
// ...ctx.request.body,
firstname: (ctx.state.user.firstname || ctx.request.body.firstname),
lastname: ctx.state.user.lastname || ctx.request.body.lastname,
username: ctx.state.user.username || ctx.request.body.username,
email: ctx.state.user.email || ctx.request.body.email,
// change the above code to reflect the fields you want the user to be able to update.
};
try {
// Update the user data in the database
await strapi.query('plugin::users-permissions.user').update({
where: { id: ctx.state.user.id },
data: updatedUserData,
});
ctx.response.status = 200;
} catch (error) {
console.error('Error updating user data:', error);
ctx.response.status = 500;
}
};
plugin.routes['content-api'].routes.push(
{
method: "PUT",
path: "/user/me",
handler: "user.updateMe",
config: {
prefix: "",
policies: []
}
});
return plugin;
}
I think this can be solved by simply calling patch instead
Heyo, just so you know you could use /users/me but instead of .push you use .unshift to put it at the top of the routes array. Since koa routes use regex matching, it won't conflict then with the regular put methods.
it's work! now
I would be very grateful if you could tell me how to upload my profile picture, even if it is just a link to a document.
It's working in Strapi 4, but the url in API is: '/api/users-permissions/user/me' not '/api/user/me', at least in my case. I don't have any TS issues
It works for me! Thanks a lot!
Can you guys link the project repo in the video pls? It would be helpful.
thanks. how can i do this with graphql?
This works, however, the user is now able to change the username even if it already exists. How can we prevent the user from updating to a username that already exists?
You can do it by destructuring the certain properties from ctx.request.body and setting them back in ctx.request.body.
But I am concerned about the default update method, there you can change anything, role username password everything and anyones credentials. Is there any way to overwrite the default routes instead of creating a new one?
Agreed. There is a huge issue here, all already existing data in the user/me is overwritten by the PUT. So username, email or first and last names that where already there from registration; now they are deleted by the update, because the { } in the payload doesn't consider previous data and sets it to null or undefined.
Is there an example of this in TypeScript?
I just wanted to let you know that I'm not at the moment. But that is great feedback. We try to keep our example using JS to make it more accessible to folk of different levels. But we should consider making more Strapi TS examples.
@@Strapi that's great, thanks for taking on the feedback, I wouldn't mind trying to contribute to those examples if I could
I have a problem.. I use typescript and I am unable to start my server if i call the strapi entity service inside the strapi-server.ts file. In order to get it to work, I have to add this comment above the query call // @ts-ignore.
Is there a better way to do this in a TS file?
not working anymore😡
did you find the solution for this ?
Yes I get a TypeError: strapiServer is not a function
Use Strapis Entity Service API instead of query.
Unfortunately Strapi gives a s# on updating their guides. Its a big mess and faaaaar away from out of the box. I would recommend using strapi but not within the next three years.
Be careful, it can change sensitive data also like username and password
It is not working. There is no updateMe method
are you using js or ts?
you created the file in content-type whereas you should have created it in users-permission
thanks.
Yes or you can create a policy which is more reusable