Lastest objects for post, invite and add cron GNEWS
This commit is contained in:
@@ -0,0 +1,36 @@
|
||||
{
|
||||
"kind": "collectionType",
|
||||
"collectionName": "group_memberships",
|
||||
"info": {
|
||||
"singularName": "group-membership",
|
||||
"pluralName": "group-memberships",
|
||||
"displayName": "GroupMembership",
|
||||
"description": ""
|
||||
},
|
||||
"options": {
|
||||
"draftAndPublish": false
|
||||
},
|
||||
"pluginOptions": {},
|
||||
"attributes": {
|
||||
"user": {
|
||||
"type": "relation",
|
||||
"relation": "manyToOne",
|
||||
"target": "plugin::users-permissions.user",
|
||||
"inversedBy": "group_memberships"
|
||||
},
|
||||
"group": {
|
||||
"type": "relation",
|
||||
"relation": "manyToOne",
|
||||
"target": "api::group.group",
|
||||
"inversedBy": "memberships"
|
||||
},
|
||||
"role": {
|
||||
"type": "enumeration",
|
||||
"enum": [
|
||||
"member",
|
||||
"admin",
|
||||
"owner"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
7
src/api/group-membership/controllers/group-membership.ts
Normal file
7
src/api/group-membership/controllers/group-membership.ts
Normal file
@@ -0,0 +1,7 @@
|
||||
/**
|
||||
* group-membership controller
|
||||
*/
|
||||
|
||||
import { factories } from '@strapi/strapi'
|
||||
|
||||
export default factories.createCoreController('api::group-membership.group-membership');
|
||||
7
src/api/group-membership/routes/group-membership.ts
Normal file
7
src/api/group-membership/routes/group-membership.ts
Normal file
@@ -0,0 +1,7 @@
|
||||
/**
|
||||
* group-membership router
|
||||
*/
|
||||
|
||||
import { factories } from '@strapi/strapi';
|
||||
|
||||
export default factories.createCoreRouter('api::group-membership.group-membership');
|
||||
7
src/api/group-membership/services/group-membership.ts
Normal file
7
src/api/group-membership/services/group-membership.ts
Normal file
@@ -0,0 +1,7 @@
|
||||
/**
|
||||
* group-membership service
|
||||
*/
|
||||
|
||||
import { factories } from '@strapi/strapi';
|
||||
|
||||
export default factories.createCoreService('api::group-membership.group-membership');
|
||||
@@ -4,40 +4,73 @@
|
||||
"info": {
|
||||
"singularName": "group",
|
||||
"pluralName": "groups",
|
||||
"displayName": "Group"
|
||||
"displayName": "Group",
|
||||
"description": ""
|
||||
},
|
||||
"options": {
|
||||
"draftAndPublish": false
|
||||
},
|
||||
"pluginOptions": {},
|
||||
"attributes": {
|
||||
"title": {
|
||||
"name": {
|
||||
"type": "string"
|
||||
},
|
||||
"description": {
|
||||
"type": "text"
|
||||
},
|
||||
"banner": {
|
||||
"type": "media",
|
||||
"multiple": false,
|
||||
"required": false,
|
||||
"allowedTypes": [
|
||||
"images",
|
||||
"files",
|
||||
"videos",
|
||||
"audios"
|
||||
],
|
||||
"type": "media",
|
||||
"multiple": false
|
||||
]
|
||||
},
|
||||
"users": {
|
||||
"type": "relation",
|
||||
"relation": "manyToMany",
|
||||
"target": "plugin::users-permissions.user",
|
||||
"inversedBy": "groups"
|
||||
"tags": {
|
||||
"displayName": "tags",
|
||||
"type": "component",
|
||||
"repeatable": true,
|
||||
"component": "social.tags"
|
||||
},
|
||||
"owner": {
|
||||
"category": {
|
||||
"type": "enumeration",
|
||||
"enum": [
|
||||
"mixedChoir",
|
||||
"womensChoir",
|
||||
"mensChoir",
|
||||
"childrensChoir"
|
||||
]
|
||||
},
|
||||
"access": {
|
||||
"type": "enumeration",
|
||||
"enum": [
|
||||
"private",
|
||||
"public",
|
||||
"closed"
|
||||
]
|
||||
},
|
||||
"memberships": {
|
||||
"type": "relation",
|
||||
"relation": "manyToOne",
|
||||
"target": "plugin::users-permissions.user",
|
||||
"inversedBy": "groups"
|
||||
"relation": "oneToMany",
|
||||
"target": "api::group-membership.group-membership",
|
||||
"mappedBy": "group"
|
||||
},
|
||||
"lastActivity": {
|
||||
"type": "datetime"
|
||||
},
|
||||
"activityType": {
|
||||
"type": "string"
|
||||
},
|
||||
"state": {
|
||||
"type": "enumeration",
|
||||
"enum": [
|
||||
"open",
|
||||
"recruiting",
|
||||
"audition"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,84 @@
|
||||
/**
|
||||
* group controller
|
||||
*/
|
||||
// /src/api/group/controllers/group.ts
|
||||
import { factories } from "@strapi/strapi";
|
||||
|
||||
import { factories } from '@strapi/strapi'
|
||||
export default factories.createCoreController(
|
||||
"api::group.group",
|
||||
({ strapi }) => ({
|
||||
async create(ctx) {
|
||||
// 1) Prépare le payload + upload banner
|
||||
const body = ctx.request.body as any;
|
||||
const data =
|
||||
typeof body?.data === "string"
|
||||
? JSON.parse(body.data)
|
||||
: body?.data || {};
|
||||
|
||||
export default factories.createCoreController('api::group.group');
|
||||
const bannerInput = (ctx.request.files as any)?.banner;
|
||||
if (bannerInput) {
|
||||
const file = Array.isArray(bannerInput) ? bannerInput[0] : bannerInput;
|
||||
const uploaded = await strapi
|
||||
.plugin("upload")
|
||||
.service("upload")
|
||||
.upload({
|
||||
data: {
|
||||
fileInfo: {
|
||||
alternativeText: data?.name || "banner",
|
||||
caption: "banner",
|
||||
name: file.originalFilename || "banner",
|
||||
},
|
||||
},
|
||||
files: file,
|
||||
});
|
||||
|
||||
if (uploaded?.[0]?.id) {
|
||||
data.banner = uploaded[0].id;
|
||||
}
|
||||
}
|
||||
|
||||
// 2) Crée le group via core controller
|
||||
ctx.request.body = { data };
|
||||
const response = await super.create(ctx); // { data: { id, attributes }, meta: {} }
|
||||
|
||||
// 3) Tente de créer le GroupMembership (owner) pour le user courant
|
||||
const membershipMeta: {
|
||||
success: boolean;
|
||||
membershipId?: number;
|
||||
error?: string;
|
||||
} = { success: false };
|
||||
|
||||
try {
|
||||
const userId = ctx.state.user?.id;
|
||||
const groupId = response?.data?.id;
|
||||
|
||||
if (!userId) {
|
||||
membershipMeta.error = "Unauthenticated user";
|
||||
} else if (!groupId) {
|
||||
membershipMeta.error = "Missing group id";
|
||||
} else {
|
||||
const membership = await strapi.entityService.create(
|
||||
"api::group-membership.group-membership",
|
||||
{
|
||||
data: {
|
||||
user: userId,
|
||||
group: groupId,
|
||||
role: "owner",
|
||||
},
|
||||
}
|
||||
);
|
||||
membershipMeta.success = true;
|
||||
membershipMeta.membershipId = membership?.id as number;
|
||||
}
|
||||
} catch (err: any) {
|
||||
strapi.log.error(
|
||||
"[group.create] Erreur création GroupMembership:",
|
||||
err
|
||||
);
|
||||
membershipMeta.error = err?.message || "Unknown error";
|
||||
}
|
||||
|
||||
// 4) Ajoute le résultat du membership dans la meta sans casser la création du group
|
||||
response.meta = { ...(response.meta || {}), membership: membershipMeta };
|
||||
|
||||
return response;
|
||||
},
|
||||
})
|
||||
);
|
||||
|
||||
45
src/api/invite/content-types/invite/schema.json
Normal file
45
src/api/invite/content-types/invite/schema.json
Normal file
@@ -0,0 +1,45 @@
|
||||
{
|
||||
"kind": "collectionType",
|
||||
"collectionName": "invites",
|
||||
"info": {
|
||||
"singularName": "invite",
|
||||
"pluralName": "invites",
|
||||
"displayName": "Invite",
|
||||
"description": ""
|
||||
},
|
||||
"options": {
|
||||
"draftAndPublish": false
|
||||
},
|
||||
"pluginOptions": {},
|
||||
"attributes": {
|
||||
"invitedUser": {
|
||||
"type": "relation",
|
||||
"relation": "oneToOne",
|
||||
"target": "plugin::users-permissions.user"
|
||||
},
|
||||
"name": {
|
||||
"type": "string"
|
||||
},
|
||||
"description": {
|
||||
"type": "text"
|
||||
},
|
||||
"invitedBy": {
|
||||
"type": "relation",
|
||||
"relation": "oneToOne",
|
||||
"target": "plugin::users-permissions.user"
|
||||
},
|
||||
"type": {
|
||||
"type": "enumeration",
|
||||
"enum": [
|
||||
"group",
|
||||
"choral"
|
||||
]
|
||||
},
|
||||
"members": {
|
||||
"type": "integer"
|
||||
},
|
||||
"invitedDate": {
|
||||
"type": "datetime"
|
||||
}
|
||||
}
|
||||
}
|
||||
7
src/api/invite/controllers/invite.ts
Normal file
7
src/api/invite/controllers/invite.ts
Normal file
@@ -0,0 +1,7 @@
|
||||
/**
|
||||
* invite controller
|
||||
*/
|
||||
|
||||
import { factories } from '@strapi/strapi'
|
||||
|
||||
export default factories.createCoreController('api::invite.invite');
|
||||
7
src/api/invite/routes/invite.ts
Normal file
7
src/api/invite/routes/invite.ts
Normal file
@@ -0,0 +1,7 @@
|
||||
/**
|
||||
* invite router
|
||||
*/
|
||||
|
||||
import { factories } from '@strapi/strapi';
|
||||
|
||||
export default factories.createCoreRouter('api::invite.invite');
|
||||
7
src/api/invite/services/invite.ts
Normal file
7
src/api/invite/services/invite.ts
Normal file
@@ -0,0 +1,7 @@
|
||||
/**
|
||||
* invite service
|
||||
*/
|
||||
|
||||
import { factories } from '@strapi/strapi';
|
||||
|
||||
export default factories.createCoreService('api::invite.invite');
|
||||
@@ -52,6 +52,18 @@
|
||||
},
|
||||
"shares": {
|
||||
"type": "integer"
|
||||
},
|
||||
"title": {
|
||||
"type": "string"
|
||||
},
|
||||
"url": {
|
||||
"type": "string"
|
||||
},
|
||||
"imageUrl": {
|
||||
"type": "string"
|
||||
},
|
||||
"source": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,6 +2,97 @@
|
||||
* post controller
|
||||
*/
|
||||
|
||||
import { factories } from '@strapi/strapi'
|
||||
import { factories } from "@strapi/strapi";
|
||||
|
||||
export default factories.createCoreController('api::post.post');
|
||||
export default factories.createCoreController(
|
||||
"api::post.post",
|
||||
({ strapi }) => ({
|
||||
async create(ctx) {
|
||||
const data = JSON.parse(ctx.request.body.data);
|
||||
|
||||
if (ctx.request.files.media) {
|
||||
const files = Array.isArray(ctx.request.files.media)
|
||||
? ctx.request.files.media[0]
|
||||
: ctx.request.files.media;
|
||||
const extension = files.originalFilename.match(/\.[0-9a-z]+$/i);
|
||||
const payload = {
|
||||
fileInfo: {
|
||||
caption: "undefined",
|
||||
alternativeText: data.name || "",
|
||||
name: `${data.name}_media${extension}`,
|
||||
},
|
||||
};
|
||||
const asset = await strapi.services["plugin::upload.upload"].upload({
|
||||
data: payload,
|
||||
files,
|
||||
});
|
||||
data.media = asset[0].id;
|
||||
}
|
||||
ctx.request.body = { data };
|
||||
const result = await super.create(ctx);
|
||||
return result;
|
||||
},
|
||||
|
||||
async savePost(ctx) {
|
||||
console.log("🎯 savePost called with params:", ctx.params);
|
||||
console.log("🎯 Request method:", ctx.request.method);
|
||||
console.log("🎯 Request URL:", ctx.request.url);
|
||||
|
||||
const user = ctx.state.user;
|
||||
if (!user) {
|
||||
console.log("❌ User not authenticated");
|
||||
return ctx.unauthorized("You must be logged in to save posts");
|
||||
}
|
||||
|
||||
console.log("✅ User authenticated:", user.id);
|
||||
const postId = parseInt(ctx.params.id);
|
||||
|
||||
if (isNaN(postId)) {
|
||||
return ctx.badRequest("Invalid post ID");
|
||||
}
|
||||
|
||||
// Verify the post exists
|
||||
const post = await strapi.entityService.findOne("api::post.post", postId);
|
||||
if (!post) {
|
||||
return ctx.notFound("Post not found");
|
||||
}
|
||||
|
||||
// Get current user with saved_posts
|
||||
const currentUser: any = await strapi.entityService.findOne(
|
||||
"plugin::users-permissions.user",
|
||||
user.id,
|
||||
{ populate: ["saved_posts"] }
|
||||
);
|
||||
|
||||
// Initialize saved_posts array if it doesn't exist
|
||||
const currentSavedPosts = currentUser.saved_posts || [];
|
||||
|
||||
// Check if post is already saved to avoid duplicates
|
||||
if (currentSavedPosts.some((savedPost: any) => savedPost.id === postId)) {
|
||||
console.log("⚠️ Post already saved");
|
||||
return ctx.badRequest("Post already saved");
|
||||
}
|
||||
|
||||
// Add the post to saved_posts
|
||||
const updatedSavedPosts = [...currentSavedPosts, postId];
|
||||
|
||||
console.log("🔄 Updating user with new saved posts:", updatedSavedPosts);
|
||||
|
||||
// Update the user
|
||||
const updatedUser = await strapi.entityService.update(
|
||||
"plugin::users-permissions.user",
|
||||
user.id,
|
||||
{
|
||||
data: {
|
||||
saved_posts: updatedSavedPosts as any,
|
||||
},
|
||||
}
|
||||
);
|
||||
|
||||
return ctx.send({
|
||||
message: "Post saved successfully",
|
||||
savedPostsCount: updatedSavedPosts.length,
|
||||
});
|
||||
},
|
||||
})
|
||||
);
|
||||
|
||||
13
src/api/post/routes/custom.ts
Normal file
13
src/api/post/routes/custom.ts
Normal file
@@ -0,0 +1,13 @@
|
||||
/**
|
||||
* Custom post routes
|
||||
*/
|
||||
|
||||
export default {
|
||||
routes: [
|
||||
{
|
||||
method: "POST",
|
||||
path: "/posts/:id/save",
|
||||
handler: "post.savePost",
|
||||
},
|
||||
],
|
||||
};
|
||||
@@ -2,6 +2,6 @@
|
||||
* post router
|
||||
*/
|
||||
|
||||
import { factories } from '@strapi/strapi';
|
||||
import { factories } from "@strapi/strapi";
|
||||
|
||||
export default factories.createCoreRouter('api::post.post');
|
||||
export default factories.createCoreRouter("api::post.post");
|
||||
|
||||
13
src/components/social/tags.json
Normal file
13
src/components/social/tags.json
Normal file
@@ -0,0 +1,13 @@
|
||||
{
|
||||
"collectionName": "components_social_tags",
|
||||
"info": {
|
||||
"displayName": "tags",
|
||||
"icon": "emotionUnhappy"
|
||||
},
|
||||
"options": {},
|
||||
"attributes": {
|
||||
"tag": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -188,16 +188,21 @@
|
||||
"target": "api::post.post",
|
||||
"mappedBy": "author"
|
||||
},
|
||||
"groups": {
|
||||
"type": "relation",
|
||||
"relation": "oneToMany",
|
||||
"target": "api::group.group",
|
||||
"mappedBy": "owner"
|
||||
},
|
||||
"friends": {
|
||||
"type": "relation",
|
||||
"relation": "oneToMany",
|
||||
"target": "plugin::users-permissions.user"
|
||||
},
|
||||
"group_memberships": {
|
||||
"type": "relation",
|
||||
"relation": "oneToMany",
|
||||
"target": "api::group-membership.group-membership",
|
||||
"mappedBy": "user"
|
||||
},
|
||||
"saved_posts": {
|
||||
"type": "relation",
|
||||
"relation": "oneToMany",
|
||||
"target": "api::post.post"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user