From 961b4aab93af68cb8c3b4a37b6c450507cba1aa8 Mon Sep 17 00:00:00 2001 From: julien vdb Date: Sun, 6 Apr 2025 22:30:47 +0200 Subject: [PATCH] Add updateMe endpoint and user fiels --- .../content-types/user/schema.json | 57 ++++++++++++ .../users-permissions/strapi-server.ts | 87 +++++++++++++++++++ types/generated/contentTypes.d.ts | 15 ++++ 3 files changed, 159 insertions(+) diff --git a/src/extensions/users-permissions/content-types/user/schema.json b/src/extensions/users-permissions/content-types/user/schema.json index 167bd2c..a993f07 100644 --- a/src/extensions/users-permissions/content-types/user/schema.json +++ b/src/extensions/users-permissions/content-types/user/schema.json @@ -106,6 +106,63 @@ "relation": "manyToMany", "target": "api::choral.choral", "mappedBy": "users" + }, + "board": { + "type": "relation", + "relation": "oneToOne", + "target": "api::board.board" + }, + "background": { + "type": "media", + "multiple": false, + "required": false, + "allowedTypes": [ + "images", + "files", + "videos", + "audios" + ] + }, + "name": { + "type": "string" + }, + "surname": { + "type": "string" + }, + "address": { + "type": "text" + }, + "gender": { + "type": "enumeration", + "enum": [ + "men", + "women", + "none" + ] + }, + "job": { + "type": "enumeration", + "enum": [ + "choir_director", + "choir_addict", + "choir_master", + "choir_singer", + "none" + ] + }, + "voice": { + "type": "enumeration", + "enum": [ + "soprano", + "mezzo-soprano", + "alto", + "tenor", + "baryton", + "basse" + ] + }, + "dob": { + "type": "date" } } } diff --git a/src/extensions/users-permissions/strapi-server.ts b/src/extensions/users-permissions/strapi-server.ts index 0db6276..1584955 100644 --- a/src/extensions/users-permissions/strapi-server.ts +++ b/src/extensions/users-permissions/strapi-server.ts @@ -93,6 +93,93 @@ module.exports = (plugin) => { }; }; + const uploadImage = async (ctx, label: string, username: string) => { + const key = `${label}Image`; + if (ctx.request.files[key]) { + const files = Array.isArray(ctx.request.files[key]) + ? ctx.request.files[key][0] + : ctx.request.files[key]; + const extension = files.originalFilename.match(/\.[0-9a-z]+$/i); + const payload = { + fileInfo: { + caption: "undefined", + alternativeText: username || "", + name: `${username}_avatar${extension}`, + }, + }; + const asset = await strapi.services["plugin::upload.upload"].upload({ + data: payload, + files, + }); + return asset[0].id; + } + + return 0; + }; + plugin.services.providers = providers; + + plugin.controllers.user.updateMe = async (ctx) => { + const user = ctx.state.user; + + // User has to be logged in to update themselves + if (!user) { + return ctx.unauthorized(); + } + + const data = JSON.parse(ctx.request.body.data); + + const newData = lod.pick(data, [ + "email", + "username", + "name", + "surname", + "address", + "gender", + "voice", + "job", + "dob", + ]); + + // Make sure there is no duplicate user with the same username + if (newData.username) { + const userWithSameUsername = await strapi + .query("plugin::users-permissions.user") + .findOne({ where: { username: newData.username } }); + + if (userWithSameUsername && userWithSameUsername.id != user.id) { + return ctx.badRequest("Username already taken"); + } + } + + // Make sure there is no duplicate user with the same email + if (newData.email) { + const userWithSameEmail = await strapi + .query("plugin::users-permissions.user") + .findOne({ where: { email: newData.email.toLowerCase() } }); + + if (userWithSameEmail && userWithSameEmail.id != user.id) { + return ctx.badRequest("Email already taken"); + } + newData.email = newData.email.toLowerCase(); + } + + ctx.request.body = newData; + ctx.params = { id: user.id }; + + const avatarId = await uploadImage(ctx, "avatar", newData.username); + if (avatarId != 0) ctx.request.body.avatar = avatarId; + const backgroundId = await uploadImage(ctx, "background", newData.username); + if (backgroundId != 0) ctx.request.body.background = backgroundId; + + return plugin.controllers.user.update(ctx); + }; + + plugin.routes["content-api"].routes.push({ + method: "PUT", + path: "/users/me", + handler: "user.updateMe", + }); + return plugin; }; diff --git a/types/generated/contentTypes.d.ts b/types/generated/contentTypes.d.ts index d14aef4..4768a95 100644 --- a/types/generated/contentTypes.d.ts +++ b/types/generated/contentTypes.d.ts @@ -1010,8 +1010,13 @@ export interface PluginUsersPermissionsUser draftAndPublish: false; }; attributes: { + address: Schema.Attribute.Text; avatar: Schema.Attribute.Media<'images'>; + background: Schema.Attribute.Media< + 'images' | 'files' | 'videos' | 'audios' + >; blocked: Schema.Attribute.Boolean & Schema.Attribute.DefaultTo; + board: Schema.Attribute.Relation<'oneToOne', 'api::board.board'>; choralAdmin: Schema.Attribute.Relation<'manyToMany', 'api::choral.choral'>; choralOwner: Schema.Attribute.Relation<'oneToOne', 'api::choral.choral'>; chorals: Schema.Attribute.Relation<'manyToMany', 'api::choral.choral'>; @@ -1020,17 +1025,23 @@ export interface PluginUsersPermissionsUser createdAt: Schema.Attribute.DateTime; createdBy: Schema.Attribute.Relation<'oneToOne', 'admin::user'> & Schema.Attribute.Private; + dob: Schema.Attribute.Date; email: Schema.Attribute.Email & Schema.Attribute.Required & Schema.Attribute.SetMinMaxLength<{ minLength: 6; }>; + gender: Schema.Attribute.Enumeration<['men', 'women', 'none']>; + job: Schema.Attribute.Enumeration< + ['choir_director', 'choir_addict', 'choir_master', 'choir_singer', 'none'] + >; locale: Schema.Attribute.String & Schema.Attribute.Private; localizations: Schema.Attribute.Relation< 'oneToMany', 'plugin::users-permissions.user' > & Schema.Attribute.Private; + name: Schema.Attribute.String; nbFollowers: Schema.Attribute.Integer & Schema.Attribute.DefaultTo<0>; nbFollowing: Schema.Attribute.Integer & Schema.Attribute.DefaultTo<0>; nbPosts: Schema.Attribute.Integer & Schema.Attribute.DefaultTo<0>; @@ -1047,6 +1058,7 @@ export interface PluginUsersPermissionsUser 'manyToOne', 'plugin::users-permissions.role' >; + surname: Schema.Attribute.String; updatedAt: Schema.Attribute.DateTime; updatedBy: Schema.Attribute.Relation<'oneToOne', 'admin::user'> & Schema.Attribute.Private; @@ -1056,6 +1068,9 @@ export interface PluginUsersPermissionsUser Schema.Attribute.SetMinMaxLength<{ minLength: 3; }>; + voice: Schema.Attribute.Enumeration< + ['soprano', 'mezzo-soprano', 'alto', 'tenor', 'baryton', 'basse'] + >; }; }