diff --git a/package.json b/package.json index a512dc8..af78d98 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "harmony-back", - "version": "0.11.18", + "version": "0.11.19", "private": true, "description": "A Strapi application", "scripts": { diff --git a/src/api/group-membership/content-types/group-membership/schema.json b/src/api/group-membership/content-types/group-membership/schema.json index 3fdb4b5..7009259 100644 --- a/src/api/group-membership/content-types/group-membership/schema.json +++ b/src/api/group-membership/content-types/group-membership/schema.json @@ -31,7 +31,8 @@ "admin", "owner", "follow", - "pending" + "pending", + "invited" ] } } diff --git a/src/api/group/controllers/group.ts b/src/api/group/controllers/group.ts index 0b47103..b385baf 100644 --- a/src/api/group/controllers/group.ts +++ b/src/api/group/controllers/group.ts @@ -83,6 +83,25 @@ export default factories.createCoreController( ); membershipMeta.success = true; membershipMeta.membershipId = membership?.id as number; + + try { + await strapi.service("api::notification.notification").createNotification({ + title: "Groupe créé", + message: `Vous avez créé un nouveau groupe`, + type: "success", + target_user: userId, + source: "group-create", + payload: { + groupId, + membershipId: membership?.id, + }, + }); + } catch (notificationErr: any) { + strapi.log.warn( + "[group.create] Erreur création notification:", + notificationErr + ); + } } } catch (err: any) { strapi.log.error( @@ -97,5 +116,98 @@ export default factories.createCoreController( return response; }, + async invite(ctx) { + const body = ctx.request.body as any; + const data = + typeof body?.data === "string" + ? JSON.parse(body.data) + : body?.data || {}; + + const groupId = ctx.params.id; + const userIds = data?.usersIds || []; + + if (!groupId) { + return ctx.badRequest("Missing groupId"); + } + + if (!Array.isArray(userIds) || userIds.length === 0) { + return ctx.badRequest("userIds must be a non-empty array"); + } + + const results = { + success: [], + errors: [], + }; + + for (const userId of userIds) { + try { + const existingMembership = await strapi.entityService.findMany( + "api::group-membership.group-membership", + { + filters: { + user: userId, + group: groupId, + }, + } + ); + + if (existingMembership && existingMembership.length > 0) { + results.errors.push({ + userId, + error: "User is already a member of this group", + }); + continue; + } + + const membership = await strapi.entityService.create( + "api::group-membership.group-membership", + { + data: { + user: userId, + group: groupId, + role: "invited", + }, + } + ); + + try { + await strapi.service("api::notification.notification").createNotification({ + title: "Invitation de groupe", + message: `Vous avez été invité à rejoindre un groupe`, + type: "info", + target_user: userId, + source: "group-invite", + payload: { + groupId, + membershipId: membership?.id, + }, + }); + } catch (notificationErr: any) { + strapi.log.warn( + "[group.invite] Erreur création notification:", + notificationErr + ); + } + + results.success.push({ + userId, + membershipId: membership?.id, + }); + } catch (err: any) { + strapi.log.error( + "[group.invite] Erreur création GroupMembership:", + err + ); + results.errors.push({ + userId, + error: err?.message || "Unknown error", + }); + } + } + + ctx.body = { + data: results, + }; + }, }) ); diff --git a/src/api/group/routes/custom.ts b/src/api/group/routes/custom.ts new file mode 100644 index 0000000..f28a473 --- /dev/null +++ b/src/api/group/routes/custom.ts @@ -0,0 +1,13 @@ +/** + * Custom post routes + */ + +export default { + routes: [ + { + method: "POST", + path: "/group/:id/invite", + handler: "group.invite", + }, + ], +}; 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 22499f7..f32cba5 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": "2025-11-09T17:10:55.198Z" + "x-generation-date": "2025-11-10T13:53:36.003Z" }, "x-strapi-config": { "plugins": [ @@ -17090,7 +17090,8 @@ "admin", "owner", "follow", - "pending" + "pending", + "invited" ] }, "createdAt": { @@ -20552,7 +20553,8 @@ "admin", "owner", "follow", - "pending" + "pending", + "invited" ] }, "createdAt": { @@ -24481,7 +24483,8 @@ "admin", "owner", "follow", - "pending" + "pending", + "invited" ] }, "createdAt": { @@ -27969,7 +27972,8 @@ "admin", "owner", "follow", - "pending" + "pending", + "invited" ] }, "createdAt": { @@ -31905,7 +31909,8 @@ "admin", "owner", "follow", - "pending" + "pending", + "invited" ] }, "createdAt": { @@ -36092,7 +36097,8 @@ "admin", "owner", "follow", - "pending" + "pending", + "invited" ] }, "createdAt": { @@ -40728,7 +40734,8 @@ "admin", "owner", "follow", - "pending" + "pending", + "invited" ] }, "createdAt": { @@ -44654,7 +44661,8 @@ "admin", "owner", "follow", - "pending" + "pending", + "invited" ] }, "createdAt": { @@ -48482,7 +48490,8 @@ "admin", "owner", "follow", - "pending" + "pending", + "invited" ] }, "createdAt": { @@ -52297,7 +52306,8 @@ "admin", "owner", "follow", - "pending" + "pending", + "invited" ] }, "createdAt": { @@ -56148,7 +56158,8 @@ "admin", "owner", "follow", - "pending" + "pending", + "invited" ] }, "createdAt": { @@ -59999,7 +60010,8 @@ "admin", "owner", "follow", - "pending" + "pending", + "invited" ] }, "createdAt": { @@ -63811,7 +63823,8 @@ "admin", "owner", "follow", - "pending" + "pending", + "invited" ] }, "createdAt": { @@ -67804,7 +67817,8 @@ "admin", "owner", "follow", - "pending" + "pending", + "invited" ] }, "createdAt": { @@ -71286,7 +71300,8 @@ "admin", "owner", "follow", - "pending" + "pending", + "invited" ] }, "createdAt": { @@ -75697,7 +75712,8 @@ "admin", "owner", "follow", - "pending" + "pending", + "invited" ] }, "createdAt": { @@ -80571,7 +80587,8 @@ "admin", "owner", "follow", - "pending" + "pending", + "invited" ] }, "createdAt": { @@ -80744,7 +80761,8 @@ "admin", "owner", "follow", - "pending" + "pending", + "invited" ] }, "locale": { @@ -83616,7 +83634,8 @@ "admin", "owner", "follow", - "pending" + "pending", + "invited" ] }, "createdAt": { @@ -84460,7 +84479,8 @@ "admin", "owner", "follow", - "pending" + "pending", + "invited" ] }, "createdAt": { @@ -87447,7 +87467,8 @@ "admin", "owner", "follow", - "pending" + "pending", + "invited" ] }, "createdAt": { @@ -91384,7 +91405,8 @@ "admin", "owner", "follow", - "pending" + "pending", + "invited" ] }, "createdAt": { @@ -95222,7 +95244,8 @@ "admin", "owner", "follow", - "pending" + "pending", + "invited" ] }, "createdAt": { @@ -98565,7 +98588,8 @@ "admin", "owner", "follow", - "pending" + "pending", + "invited" ] }, "createdAt": { @@ -103117,7 +103141,8 @@ "admin", "owner", "follow", - "pending" + "pending", + "invited" ] }, "createdAt": { @@ -106998,7 +107023,8 @@ "admin", "owner", "follow", - "pending" + "pending", + "invited" ] }, "createdAt": { @@ -110839,7 +110865,8 @@ "admin", "owner", "follow", - "pending" + "pending", + "invited" ] }, "createdAt": { diff --git a/types/generated/contentTypes.d.ts b/types/generated/contentTypes.d.ts index 5f73707..d1323cd 100644 --- a/types/generated/contentTypes.d.ts +++ b/types/generated/contentTypes.d.ts @@ -1047,7 +1047,7 @@ export interface ApiGroupMembershipGroupMembership Schema.Attribute.Private; publishedAt: Schema.Attribute.DateTime; role: Schema.Attribute.Enumeration< - ['member', 'admin', 'owner', 'follow', 'pending'] + ['member', 'admin', 'owner', 'follow', 'pending', 'invited'] >; updatedAt: Schema.Attribute.DateTime; updatedBy: Schema.Attribute.Relation<'oneToOne', 'admin::user'> &