From f7f0ee17d7af27f9e7f388808c3e2576ed63a3e3 Mon Sep 17 00:00:00 2001 From: julien vdb Date: Tue, 14 Apr 2026 23:06:41 +0200 Subject: [PATCH] 0.13.10 : add fiels on message and channel --- package.json | 2 +- .../channel/content-types/channel/schema.json | 9 +- .../message/content-types/message/schema.json | 8 + src/api/message/controllers/message.ts | 127 ++- src/api/message/routes/01-custom-message.ts | 9 + .../1.0.0/full_documentation.json | 731 +++++++++++++++++- types/generated/contentTypes.d.ts | 8 + 7 files changed, 889 insertions(+), 5 deletions(-) create mode 100644 src/api/message/routes/01-custom-message.ts diff --git a/package.json b/package.json index e52fecd..8f79647 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "harmony-back", - "version": "0.13.9", + "version": "0.13.10", "private": true, "description": "A Strapi application", "scripts": { diff --git a/src/api/channel/content-types/channel/schema.json b/src/api/channel/content-types/channel/schema.json index b268b1c..efa31aa 100644 --- a/src/api/channel/content-types/channel/schema.json +++ b/src/api/channel/content-types/channel/schema.json @@ -4,7 +4,8 @@ "info": { "singularName": "channel", "pluralName": "channels", - "displayName": "Channel" + "displayName": "Channel", + "description": "" }, "options": { "draftAndPublish": false @@ -33,6 +34,12 @@ "relation": "oneToMany", "target": "api::message.message", "mappedBy": "channel" + }, + "description": { + "type": "text" + }, + "permissions": { + "type": "json" } } } diff --git a/src/api/message/content-types/message/schema.json b/src/api/message/content-types/message/schema.json index ddd5754..422eab9 100644 --- a/src/api/message/content-types/message/schema.json +++ b/src/api/message/content-types/message/schema.json @@ -33,6 +33,14 @@ "type": "relation", "relation": "oneToOne", "target": "api::choral.choral" + }, + "reactions": { + "type": "json" + }, + "parent_message": { + "type": "relation", + "relation": "oneToOne", + "target": "api::message.message" } } } diff --git a/src/api/message/controllers/message.ts b/src/api/message/controllers/message.ts index 3465e12..87d7f13 100644 --- a/src/api/message/controllers/message.ts +++ b/src/api/message/controllers/message.ts @@ -4,11 +4,134 @@ import { factories } from "@strapi/strapi"; +interface ChannelPermissions { + [roleName: string]: { + read: boolean; + write: boolean; + }; +} + +interface PopulatedChannel { + id: any; + permissions?: any; + choral?: { + id: any; + available_roles?: any[]; + }; +} + +interface ChoralMembership { + id: any; + role_id?: string; +} + export default factories.createCoreController( "api::message.message", ({ strapi }) => ({ async create(ctx) { - return super.create(ctx); + const { channel: channelId } = ctx.request.body.data; + const user = ctx.state.user; + + // 1. Récupérer les permissions du channel et son choral + const channel = (await strapi.entityService.findOne( + "api::channel.channel", + channelId, + { populate: ["choral"] }, + )) as unknown as PopulatedChannel; + + if (!channel || !channel.choral) { + return ctx.badRequest("Canal ou chorale introuvable."); + } + + // 2. Récupérer le membership du user pour cette chorale + const memberships = (await strapi.entityService.findMany( + "api::choral-membership.choral-membership", + { + filters: { + user: user.id, + choral: channel.choral.id, + }, + }, + )) as unknown as ChoralMembership[]; + + const membership = memberships?.[0]; + const userRoleId = membership?.role_id; + + // Résolution du nom du rôle à partir des available_roles de la chorale + const availableRoles = channel.choral.available_roles || []; + const userRoleName = availableRoles.find( + (r) => String(r.id) === String(userRoleId), + )?.name; + + // 3. Vérification "Write" (on vérifie le flag write pour le rôle spécifique) + const permissions = channel.permissions as unknown as ChannelPermissions; + const canWrite = + permissions?.[userRoleName]?.write === true || + userRoleId === "admin" || + userRoleName === "Admin"; + + if (!canWrite) { + return ctx.forbidden( + "Désolé, tu n'as pas le droit d'écrire dans ce salon.", + ); + } + + // 4. Procéder à la création si OK + return await super.create(ctx); }, - }) + + async addReaction(ctx) { + const { id } = ctx.params; + const { reaction } = ctx.request.body; + const user = ctx.state.user; + + if (!reaction) { + return ctx.badRequest("La réaction est requise."); + } + + // 1. Récupérer le message + const message = await strapi.entityService.findOne( + "api::message.message", + id + ); + + if (!message) { + return ctx.notFound("Message introuvable."); + } + + // 2. Gérer les réactions (toggle logic) + let reactions = (message.reactions as any) || {}; + if (typeof reactions !== "object") { + reactions = {}; + } + + if (!reactions[reaction]) { + reactions[reaction] = [user.id]; + } else { + const index = reactions[reaction].indexOf(user.id); + if (index > -1) { + // Si l'utilisateur a déjà réagi, on retire sa réaction + reactions[reaction].splice(index, 1); + // Si plus personne n'a réagi avec cet emoji, on retire l'entrée + if (reactions[reaction].length === 0) { + delete reactions[reaction]; + } + } else { + // Sinon on ajoute l'utilisateur + reactions[reaction].push(user.id); + } + } + + // 3. Mettre à jour le message + const updatedMessage = await strapi.entityService.update( + "api::message.message", + id, + { + data: { reactions }, + } + ); + + return updatedMessage; + }, + }), ); diff --git a/src/api/message/routes/01-custom-message.ts b/src/api/message/routes/01-custom-message.ts new file mode 100644 index 0000000..67e9871 --- /dev/null +++ b/src/api/message/routes/01-custom-message.ts @@ -0,0 +1,9 @@ +export default { + routes: [ + { + method: "POST", + path: "/messages/:id/react", + handler: "message.addReaction", + }, + ], +}; diff --git a/src/extensions/documentation/documentation/1.0.0/full_documentation.json b/src/extensions/documentation/documentation/1.0.0/full_documentation.json index af57b03..6993cad 100644 --- a/src/extensions/documentation/documentation/1.0.0/full_documentation.json +++ b/src/extensions/documentation/documentation/1.0.0/full_documentation.json @@ -14,7 +14,7 @@ "name": "Apache 2.0", "url": "https://www.apache.org/licenses/LICENSE-2.0.html" }, - "x-generation-date": "2026-04-13T19:55:11.976Z" + "x-generation-date": "2026-04-14T21:06:17.253Z" }, "x-strapi-config": { "plugins": [ @@ -20707,6 +20707,25 @@ } } }, + "reactions": {}, + "parent_message": { + "type": "object", + "properties": { + "id": { + "oneOf": [ + { + "type": "string" + }, + { + "type": "number" + } + ] + }, + "documentId": { + "type": "string" + } + } + }, "createdAt": { "type": "string", "format": "date-time" @@ -20782,6 +20801,10 @@ } } }, + "description": { + "type": "string" + }, + "permissions": {}, "createdAt": { "type": "string", "format": "date-time" @@ -29175,6 +29198,25 @@ } } }, + "reactions": {}, + "parent_message": { + "type": "object", + "properties": { + "id": { + "oneOf": [ + { + "type": "string" + }, + { + "type": "number" + } + ] + }, + "documentId": { + "type": "string" + } + } + }, "createdAt": { "type": "string", "format": "date-time" @@ -29250,6 +29292,10 @@ } } }, + "description": { + "type": "string" + }, + "permissions": {}, "createdAt": { "type": "string", "format": "date-time" @@ -34872,6 +34918,25 @@ } } }, + "reactions": {}, + "parent_message": { + "type": "object", + "properties": { + "id": { + "oneOf": [ + { + "type": "string" + }, + { + "type": "number" + } + ] + }, + "documentId": { + "type": "string" + } + } + }, "createdAt": { "type": "string", "format": "date-time" @@ -34947,6 +35012,10 @@ } } }, + "description": { + "type": "string" + }, + "permissions": {}, "createdAt": { "type": "string", "format": "date-time" @@ -39960,6 +40029,25 @@ } } }, + "reactions": {}, + "parent_message": { + "type": "object", + "properties": { + "id": { + "oneOf": [ + { + "type": "string" + }, + { + "type": "number" + } + ] + }, + "documentId": { + "type": "string" + } + } + }, "createdAt": { "type": "string", "format": "date-time" @@ -40035,6 +40123,10 @@ } } }, + "description": { + "type": "string" + }, + "permissions": {}, "createdAt": { "type": "string", "format": "date-time" @@ -45650,6 +45742,25 @@ } } }, + "reactions": {}, + "parent_message": { + "type": "object", + "properties": { + "id": { + "oneOf": [ + { + "type": "string" + }, + { + "type": "number" + } + ] + }, + "documentId": { + "type": "string" + } + } + }, "createdAt": { "type": "string", "format": "date-time" @@ -45725,6 +45836,10 @@ } } }, + "description": { + "type": "string" + }, + "permissions": {}, "createdAt": { "type": "string", "format": "date-time" @@ -46696,6 +46811,10 @@ "example": "string or id" } }, + "description": { + "type": "string" + }, + "permissions": {}, "locale": { "type": "string" }, @@ -51696,6 +51815,25 @@ } } }, + "reactions": {}, + "parent_message": { + "type": "object", + "properties": { + "id": { + "oneOf": [ + { + "type": "string" + }, + { + "type": "number" + } + ] + }, + "documentId": { + "type": "string" + } + } + }, "createdAt": { "type": "string", "format": "date-time" @@ -51771,6 +51909,10 @@ } } }, + "description": { + "type": "string" + }, + "permissions": {}, "createdAt": { "type": "string", "format": "date-time" @@ -52121,6 +52263,10 @@ } } }, + "description": { + "type": "string" + }, + "permissions": {}, "createdAt": { "type": "string", "format": "date-time" @@ -55123,6 +55269,25 @@ } } }, + "reactions": {}, + "parent_message": { + "type": "object", + "properties": { + "id": { + "oneOf": [ + { + "type": "string" + }, + { + "type": "number" + } + ] + }, + "documentId": { + "type": "string" + } + } + }, "createdAt": { "type": "string", "format": "date-time" @@ -55198,6 +55363,10 @@ } } }, + "description": { + "type": "string" + }, + "permissions": {}, "createdAt": { "type": "string", "format": "date-time" @@ -61099,6 +61268,25 @@ } } }, + "reactions": {}, + "parent_message": { + "type": "object", + "properties": { + "id": { + "oneOf": [ + { + "type": "string" + }, + { + "type": "number" + } + ] + }, + "documentId": { + "type": "string" + } + } + }, "createdAt": { "type": "string", "format": "date-time" @@ -61174,6 +61362,10 @@ } } }, + "description": { + "type": "string" + }, + "permissions": {}, "createdAt": { "type": "string", "format": "date-time" @@ -67191,6 +67383,25 @@ } } }, + "reactions": {}, + "parent_message": { + "type": "object", + "properties": { + "id": { + "oneOf": [ + { + "type": "string" + }, + { + "type": "number" + } + ] + }, + "documentId": { + "type": "string" + } + } + }, "createdAt": { "type": "string", "format": "date-time" @@ -67266,6 +67477,10 @@ } } }, + "description": { + "type": "string" + }, + "permissions": {}, "createdAt": { "type": "string", "format": "date-time" @@ -73495,6 +73710,25 @@ } } }, + "reactions": {}, + "parent_message": { + "type": "object", + "properties": { + "id": { + "oneOf": [ + { + "type": "string" + }, + { + "type": "number" + } + ] + }, + "documentId": { + "type": "string" + } + } + }, "createdAt": { "type": "string", "format": "date-time" @@ -73570,6 +73804,10 @@ } } }, + "description": { + "type": "string" + }, + "permissions": {}, "createdAt": { "type": "string", "format": "date-time" @@ -79396,6 +79634,25 @@ } } }, + "reactions": {}, + "parent_message": { + "type": "object", + "properties": { + "id": { + "oneOf": [ + { + "type": "string" + }, + { + "type": "number" + } + ] + }, + "documentId": { + "type": "string" + } + } + }, "createdAt": { "type": "string", "format": "date-time" @@ -79471,6 +79728,10 @@ } } }, + "description": { + "type": "string" + }, + "permissions": {}, "createdAt": { "type": "string", "format": "date-time" @@ -84970,6 +85231,25 @@ } } }, + "reactions": {}, + "parent_message": { + "type": "object", + "properties": { + "id": { + "oneOf": [ + { + "type": "string" + }, + { + "type": "number" + } + ] + }, + "documentId": { + "type": "string" + } + } + }, "createdAt": { "type": "string", "format": "date-time" @@ -85045,6 +85325,10 @@ } } }, + "description": { + "type": "string" + }, + "permissions": {}, "createdAt": { "type": "string", "format": "date-time" @@ -90504,6 +90788,25 @@ } } }, + "reactions": {}, + "parent_message": { + "type": "object", + "properties": { + "id": { + "oneOf": [ + { + "type": "string" + }, + { + "type": "number" + } + ] + }, + "documentId": { + "type": "string" + } + } + }, "createdAt": { "type": "string", "format": "date-time" @@ -90579,6 +90882,10 @@ } } }, + "description": { + "type": "string" + }, + "permissions": {}, "createdAt": { "type": "string", "format": "date-time" @@ -96088,6 +96395,25 @@ } } }, + "reactions": {}, + "parent_message": { + "type": "object", + "properties": { + "id": { + "oneOf": [ + { + "type": "string" + }, + { + "type": "number" + } + ] + }, + "documentId": { + "type": "string" + } + } + }, "createdAt": { "type": "string", "format": "date-time" @@ -96163,6 +96489,10 @@ } } }, + "description": { + "type": "string" + }, + "permissions": {}, "createdAt": { "type": "string", "format": "date-time" @@ -101679,6 +102009,25 @@ } } }, + "reactions": {}, + "parent_message": { + "type": "object", + "properties": { + "id": { + "oneOf": [ + { + "type": "string" + }, + { + "type": "number" + } + ] + }, + "documentId": { + "type": "string" + } + } + }, "createdAt": { "type": "string", "format": "date-time" @@ -101754,6 +102103,10 @@ } } }, + "description": { + "type": "string" + }, + "permissions": {}, "createdAt": { "type": "string", "format": "date-time" @@ -107210,6 +107563,25 @@ } } }, + "reactions": {}, + "parent_message": { + "type": "object", + "properties": { + "id": { + "oneOf": [ + { + "type": "string" + }, + { + "type": "number" + } + ] + }, + "documentId": { + "type": "string" + } + } + }, "createdAt": { "type": "string", "format": "date-time" @@ -107285,6 +107657,10 @@ } } }, + "description": { + "type": "string" + }, + "permissions": {}, "createdAt": { "type": "string", "format": "date-time" @@ -113013,6 +113389,25 @@ } } }, + "reactions": {}, + "parent_message": { + "type": "object", + "properties": { + "id": { + "oneOf": [ + { + "type": "string" + }, + { + "type": "number" + } + ] + }, + "documentId": { + "type": "string" + } + } + }, "createdAt": { "type": "string", "format": "date-time" @@ -113088,6 +113483,10 @@ } } }, + "description": { + "type": "string" + }, + "permissions": {}, "createdAt": { "type": "string", "format": "date-time" @@ -120981,6 +121380,25 @@ } } }, + "reactions": {}, + "parent_message": { + "type": "object", + "properties": { + "id": { + "oneOf": [ + { + "type": "string" + }, + { + "type": "number" + } + ] + }, + "documentId": { + "type": "string" + } + } + }, "createdAt": { "type": "string", "format": "date-time" @@ -121056,6 +121474,10 @@ } } }, + "description": { + "type": "string" + }, + "permissions": {}, "createdAt": { "type": "string", "format": "date-time" @@ -124428,6 +124850,25 @@ } } }, + "reactions": {}, + "parent_message": { + "type": "object", + "properties": { + "id": { + "oneOf": [ + { + "type": "string" + }, + { + "type": "number" + } + ] + }, + "documentId": { + "type": "string" + } + } + }, "createdAt": { "type": "string", "format": "date-time" @@ -124503,6 +124944,10 @@ } } }, + "description": { + "type": "string" + }, + "permissions": {}, "createdAt": { "type": "string", "format": "date-time" @@ -132457,6 +132902,25 @@ } } }, + "reactions": {}, + "parent_message": { + "type": "object", + "properties": { + "id": { + "oneOf": [ + { + "type": "string" + }, + { + "type": "number" + } + ] + }, + "documentId": { + "type": "string" + } + } + }, "createdAt": { "type": "string", "format": "date-time" @@ -132532,6 +132996,10 @@ } } }, + "description": { + "type": "string" + }, + "permissions": {}, "createdAt": { "type": "string", "format": "date-time" @@ -136393,6 +136861,25 @@ } } }, + "reactions": {}, + "parent_message": { + "type": "object", + "properties": { + "id": { + "oneOf": [ + { + "type": "string" + }, + { + "type": "number" + } + ] + }, + "documentId": { + "type": "string" + } + } + }, "createdAt": { "type": "string", "format": "date-time" @@ -136468,6 +136955,10 @@ } } }, + "description": { + "type": "string" + }, + "permissions": {}, "createdAt": { "type": "string", "format": "date-time" @@ -141913,6 +142404,25 @@ } } }, + "reactions": {}, + "parent_message": { + "type": "object", + "properties": { + "id": { + "oneOf": [ + { + "type": "string" + }, + { + "type": "number" + } + ] + }, + "documentId": { + "type": "string" + } + } + }, "createdAt": { "type": "string", "format": "date-time" @@ -141988,6 +142498,10 @@ } } }, + "description": { + "type": "string" + }, + "permissions": {}, "createdAt": { "type": "string", "format": "date-time" @@ -147472,6 +147986,25 @@ } } }, + "reactions": {}, + "parent_message": { + "type": "object", + "properties": { + "id": { + "oneOf": [ + { + "type": "string" + }, + { + "type": "number" + } + ] + }, + "documentId": { + "type": "string" + } + } + }, "createdAt": { "type": "string", "format": "date-time" @@ -147547,6 +148080,10 @@ } } }, + "description": { + "type": "string" + }, + "permissions": {}, "createdAt": { "type": "string", "format": "date-time" @@ -151538,6 +152075,18 @@ ], "example": "string or id" }, + "reactions": {}, + "parent_message": { + "oneOf": [ + { + "type": "integer" + }, + { + "type": "string" + } + ], + "example": "string or id" + }, "locale": { "type": "string" }, @@ -154401,6 +154950,25 @@ } } }, + "reactions": {}, + "parent_message": { + "type": "object", + "properties": { + "id": { + "oneOf": [ + { + "type": "string" + }, + { + "type": "number" + } + ] + }, + "documentId": { + "type": "string" + } + } + }, "createdAt": { "type": "string", "format": "date-time" @@ -154476,6 +155044,10 @@ } } }, + "description": { + "type": "string" + }, + "permissions": {}, "createdAt": { "type": "string", "format": "date-time" @@ -156973,6 +157545,25 @@ } } }, + "reactions": {}, + "parent_message": { + "type": "object", + "properties": { + "id": { + "oneOf": [ + { + "type": "string" + }, + { + "type": "number" + } + ] + }, + "documentId": { + "type": "string" + } + } + }, "createdAt": { "type": "string", "format": "date-time" @@ -159975,6 +160566,25 @@ } } }, + "reactions": {}, + "parent_message": { + "type": "object", + "properties": { + "id": { + "oneOf": [ + { + "type": "string" + }, + { + "type": "number" + } + ] + }, + "documentId": { + "type": "string" + } + } + }, "createdAt": { "type": "string", "format": "date-time" @@ -160050,6 +160660,10 @@ } } }, + "description": { + "type": "string" + }, + "permissions": {}, "createdAt": { "type": "string", "format": "date-time" @@ -165627,6 +166241,25 @@ } } }, + "reactions": {}, + "parent_message": { + "type": "object", + "properties": { + "id": { + "oneOf": [ + { + "type": "string" + }, + { + "type": "number" + } + ] + }, + "documentId": { + "type": "string" + } + } + }, "createdAt": { "type": "string", "format": "date-time" @@ -165702,6 +166335,10 @@ } } }, + "description": { + "type": "string" + }, + "permissions": {}, "createdAt": { "type": "string", "format": "date-time" @@ -173889,6 +174526,25 @@ } } }, + "reactions": {}, + "parent_message": { + "type": "object", + "properties": { + "id": { + "oneOf": [ + { + "type": "string" + }, + { + "type": "number" + } + ] + }, + "documentId": { + "type": "string" + } + } + }, "createdAt": { "type": "string", "format": "date-time" @@ -173964,6 +174620,10 @@ } } }, + "description": { + "type": "string" + }, + "permissions": {}, "createdAt": { "type": "string", "format": "date-time" @@ -177519,6 +178179,25 @@ } } }, + "reactions": {}, + "parent_message": { + "type": "object", + "properties": { + "id": { + "oneOf": [ + { + "type": "string" + }, + { + "type": "number" + } + ] + }, + "documentId": { + "type": "string" + } + } + }, "createdAt": { "type": "string", "format": "date-time" @@ -177594,6 +178273,10 @@ } } }, + "description": { + "type": "string" + }, + "permissions": {}, "createdAt": { "type": "string", "format": "date-time" @@ -183140,6 +183823,25 @@ } } }, + "reactions": {}, + "parent_message": { + "type": "object", + "properties": { + "id": { + "oneOf": [ + { + "type": "string" + }, + { + "type": "number" + } + ] + }, + "documentId": { + "type": "string" + } + } + }, "createdAt": { "type": "string", "format": "date-time" @@ -183215,6 +183917,10 @@ } } }, + "description": { + "type": "string" + }, + "permissions": {}, "createdAt": { "type": "string", "format": "date-time" @@ -188707,6 +189413,25 @@ } } }, + "reactions": {}, + "parent_message": { + "type": "object", + "properties": { + "id": { + "oneOf": [ + { + "type": "string" + }, + { + "type": "number" + } + ] + }, + "documentId": { + "type": "string" + } + } + }, "createdAt": { "type": "string", "format": "date-time" @@ -188782,6 +189507,10 @@ } } }, + "description": { + "type": "string" + }, + "permissions": {}, "createdAt": { "type": "string", "format": "date-time" diff --git a/types/generated/contentTypes.d.ts b/types/generated/contentTypes.d.ts index 39b574c..ae7c2b2 100644 --- a/types/generated/contentTypes.d.ts +++ b/types/generated/contentTypes.d.ts @@ -560,6 +560,7 @@ export interface ApiBoardBoard extends Struct.CollectionTypeSchema { export interface ApiChannelChannel extends Struct.CollectionTypeSchema { collectionName: 'channels'; info: { + description: ''; displayName: 'Channel'; pluralName: 'channels'; singularName: 'channel'; @@ -572,6 +573,7 @@ export interface ApiChannelChannel extends Struct.CollectionTypeSchema { createdAt: Schema.Attribute.DateTime; createdBy: Schema.Attribute.Relation<'oneToOne', 'admin::user'> & Schema.Attribute.Private; + description: Schema.Attribute.Text; locale: Schema.Attribute.String & Schema.Attribute.Private; localizations: Schema.Attribute.Relation< 'oneToMany', @@ -580,6 +582,7 @@ export interface ApiChannelChannel extends Struct.CollectionTypeSchema { Schema.Attribute.Private; messages: Schema.Attribute.Relation<'oneToMany', 'api::message.message'>; name: Schema.Attribute.String; + permissions: Schema.Attribute.JSON; publishedAt: Schema.Attribute.DateTime; type: Schema.Attribute.Enumeration<['TEXT', 'AUDIO', 'VIDEO']>; updatedAt: Schema.Attribute.DateTime; @@ -1413,7 +1416,12 @@ export interface ApiMessageMessage extends Struct.CollectionTypeSchema { 'api::message.message' > & Schema.Attribute.Private; + parent_message: Schema.Attribute.Relation< + 'oneToOne', + 'api::message.message' + >; publishedAt: Schema.Attribute.DateTime; + reactions: Schema.Attribute.JSON; updatedAt: Schema.Attribute.DateTime; updatedBy: Schema.Attribute.Relation<'oneToOne', 'admin::user'> & Schema.Attribute.Private;