0.13.10 : add fiels on message and channel
All checks were successful
Build release Docker image / Build Docker Images (push) Successful in 10m36s
All checks were successful
Build release Docker image / Build Docker Images (push) Successful in 10m36s
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "harmony-back",
|
||||
"version": "0.13.9",
|
||||
"version": "0.13.10",
|
||||
"private": true,
|
||||
"description": "A Strapi application",
|
||||
"scripts": {
|
||||
|
||||
@@ -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"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
},
|
||||
}),
|
||||
);
|
||||
|
||||
9
src/api/message/routes/01-custom-message.ts
Normal file
9
src/api/message/routes/01-custom-message.ts
Normal file
@@ -0,0 +1,9 @@
|
||||
export default {
|
||||
routes: [
|
||||
{
|
||||
method: "POST",
|
||||
path: "/messages/:id/react",
|
||||
handler: "message.addReaction",
|
||||
},
|
||||
],
|
||||
};
|
||||
File diff suppressed because it is too large
Load Diff
8
types/generated/contentTypes.d.ts
vendored
8
types/generated/contentTypes.d.ts
vendored
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user