Files
harmony-back/src/api/post/controllers/post.ts

512 lines
16 KiB
TypeScript
Raw Blame History

This file contains invisible Unicode characters
This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/**
* post controller
*/
import { factories } from "@strapi/strapi";
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);
// Créer le postOwnership associé
if (result.data) {
const userId = ctx.state.user?.id;
await strapi.db.query("api::post-ownership.post-ownership").create({
data: {
post: result.data.id,
author: userId,
contextType: data.contextType || "user",
contextId: data.contextId || null,
relation: "owner",
},
});
}
return result;
},
/**
* Retrieves the feed for the authenticated user, including posts from friends, followed contacts,
* user's groups, friends' groups, and system posts. The feed is enriched with additional properties
* such as friend, contactFollow, member, and group.
*
* @param {Object} ctx - The Koa context object containing the request and response.
* @returns {Promise<void>} - Sends the enriched feed as the response.
*/
async feed(ctx) {
const userId = ctx.state.user?.id;
const { _limit = 20, _start = 0 } = ctx.query;
if (!userId) return ctx.badRequest("userId is required");
const queryParams = {
populate: {
post: {
populate: {
likes: true,
comments: {
populate: {
owner: {
populate: {
avatar: true,
},
},
},
},
author: {
populate: {
avatar: true,
},
},
media: true,
},
},
author: {
populate: {
avatar: true,
},
},
// populate context info if needed
},
sort: { createdAt: "desc" },
pagination: {
start: parseInt(String(_start)),
limit: parseInt(String(_limit)),
},
};
// 1⃣ Récupérer les groupes de l'utilisateur
const groups = await strapi.db
.query("api::group-membership.group-membership")
.findMany({
where: { user: { id: parseInt(userId) } },
populate: ["group"],
});
const groupIds = groups.map((g) => g.group.id);
// 2⃣ Récupérer les amis (contacts acceptés) et les follows
const friendsContacts = await strapi.db
.query("api::contact.contact")
.findMany({
where: {
$or: [
{ owner: { id: parseInt(userId) } },
{ user: { id: parseInt(userId) } },
],
state: "accepted",
},
populate: ["owner", "user"],
});
const friendIds = friendsContacts.map((c) =>
c.owner.id !== parseInt(userId) ? c.owner.id : c.user.id
);
// Récupérer les contacts suivis (follow)
const followContacts = await strapi.db
.query("api::contact.contact")
.findMany({
where: {
owner: { id: parseInt(userId) },
state: "follow",
},
populate: ["user"],
});
const followIds = followContacts.map((c) => c.user.id);
// Récupérer les contacts suivis (follow)
const blockedContacts = await strapi.db
.query("api::contact.contact")
.findMany({
where: {
owner: { id: parseInt(userId) },
state: "blocked",
},
populate: ["user"],
});
const blockedIds = blockedContacts.map((c) => c.user.id);
// 3⃣ Récupérer les groupes où mes amis sont membres (en excluant mes propres groupes)
const friendsGroupMemberships = await strapi.db
.query("api::group-membership.group-membership")
.findMany({
where: { user: { id: friendIds } },
populate: ["group"],
});
const friendsGroupIds = friendsGroupMemberships
.map((membership) => membership.group.id)
.filter((groupId) => !groupIds.includes(groupId)); // Exclure mes propres groupes
// 4⃣ Récupérer le feed
const feed = await strapi.db
.query("api::post-ownership.post-ownership")
.findMany({
where: {
$or: [
// Posts réguliers (amis, follows, groupes, système) - exclure les cachés
{
$and: [
{
$or: [
{ author: { id: friendIds } }, // Posts de mes amis
{ author: { id: followIds } }, // Posts des contacts que je suis
{ contextType: "group", contextId: groupIds }, // Posts de mes groupes
{ contextType: "group", contextId: friendsGroupIds }, // Posts des groupes de mes amis
{ contextType: "system" }, // Posts système
],
},
{ relation: { $ne: "hidden" } }, // exclure les posts masqués pour les posts réguliers
],
},
// Posts sauvés par l'utilisateur
{
contextType: "user",
contextId: parseInt(userId),
relation: "saved",
},
// Posts cachés par l'utilisateur
{
contextType: "user",
contextId: parseInt(userId),
relation: "hidden",
},
],
},
...queryParams,
});
// 5⃣ Récupérer tous les groupes mentionnés dans le feed pour les populer
const allGroupIds = [...new Set([...groupIds, ...friendsGroupIds])];
const allGroups = await strapi.db.query("api::group.group").findMany({
where: { id: allGroupIds },
});
// Créer un map pour un accès rapide aux groupes par ID
const groupsMap = new Map(allGroups.map((group) => [group.id, group]));
// 6⃣ Enrichir le feed avec les propriétés friend, member, contactFollow et group
const enrichedFeed = feed.map((postOwnership) => {
const authorId = postOwnership.author?.id;
const contextType = postOwnership.contextType;
const contextId = postOwnership.contextId;
// Vérifier si l'auteur est un ami
const isFriend = authorId ? friendIds.includes(authorId) : false;
// Vérifier si l'auteur est un contact suivi
const isContactFollow = authorId ? followIds.includes(authorId) : false;
// Vérifier si l'auteur est bloqué
const isBlocked = authorId ? blockedIds.includes(authorId) : false;
// Vérifier si je suis membre du groupe (seulement pour les posts de groupe)
const isMember =
contextType === "group" && contextId
? groupIds.includes(contextId)
: false;
// Ajouter l'objet group si contextType est "group"
const group =
contextType === "group" && contextId
? groupsMap.get(contextId)
: null;
return {
...postOwnership,
friend: isFriend,
contactFollow: isContactFollow,
member: isMember,
blocked: isBlocked,
...(group && { group }), // Ajouter group seulement s'il existe
};
});
const filteredFeedBlocked = enrichedFeed.filter((post) => !post.blocked);
ctx.send(filteredFeedBlocked);
},
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(String(ctx.params.id));
const authorId = parseInt(String(ctx.query.authorId));
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");
}
// Check if post is already saved by this user
const existingSavedPost = await strapi.db
.query("api::post-ownership.post-ownership")
.findOne({
where: {
post: postId,
author: authorId,
contextType: "user",
contextId: user.id,
relation: "saved",
},
});
if (existingSavedPost) {
console.log("⚠️ Post already saved");
return ctx.badRequest("Post is already saved");
}
// Create postOwnership entry to mark post as saved
const savedPostOwnership = await strapi.db
.query("api::post-ownership.post-ownership")
.create({
data: {
post: postId,
author: authorId,
contextType: "user",
contextId: user.id,
relation: "saved",
},
});
console.log("✅ Post marked as saved:", savedPostOwnership);
// Get count of saved posts for this user
const savedPostsCount = await strapi.db
.query("api::post-ownership.post-ownership")
.count({
where: {
author: authorId,
contextType: "user",
contextId: user.id,
relation: "saved",
},
});
return ctx.send({
message: "Post saved successfully",
savedPostsCount: savedPostsCount,
});
},
async removeSavedPost(ctx) {
console.log("🎯 removeSavedPost 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 remove saved posts");
}
console.log("✅ User authenticated:", user.id);
const postId = parseInt(String(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");
}
// Find the saved post ownership entry
const savedPostOwnership = await strapi.db
.query("api::post-ownership.post-ownership")
.findOne({
where: {
post: postId,
contextType: "user",
contextId: user.id,
relation: "saved",
},
});
if (!savedPostOwnership) {
console.log("⚠️ Post is not saved");
return ctx.badRequest("Post is not in your saved posts");
}
// Delete the saved post ownership entry
await strapi.db.query("api::post-ownership.post-ownership").delete({
where: { id: savedPostOwnership.id },
});
console.log("✅ Post removed from saved posts successfully");
// Get updated count of saved posts for this user
const savedPostsCount = await strapi.db
.query("api::post-ownership.post-ownership")
.count({
where: {
author: user.id,
contextType: "user",
contextId: user.id,
relation: "saved",
},
});
return ctx.send({
message: "Post removed from saved posts successfully",
savedPostsCount: savedPostsCount,
});
},
async hidePost(ctx) {
console.log("🎯 hidePost 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 hide posts");
}
console.log("✅ User authenticated:", user.id);
const postId = parseInt(String(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");
}
// Check if post is already hidden by this user
const existingHiddenPost = await strapi.db
.query("api::post-ownership.post-ownership")
.findOne({
where: {
post: postId,
author: user.id,
contextType: "user",
contextId: user.id,
relation: "hidden",
},
});
if (existingHiddenPost) {
console.log("⚠️ Post already hidden");
return ctx.badRequest("Post is already hidden");
}
// Create postOwnership entry to mark post as hidden
const hiddenPostOwnership = await strapi.db
.query("api::post-ownership.post-ownership")
.create({
data: {
post: postId,
author: user.id,
contextType: "user",
contextId: user.id,
relation: "hidden",
},
});
console.log("✅ Post marked as hidden:", hiddenPostOwnership);
return ctx.send({
message: "Post hidden successfully",
hiddenPostId: postId,
});
},
async removeHiddenPost(ctx) {
console.log("🎯 removeHiddenPost 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 unhide posts");
}
console.log("✅ User authenticated:", user.id);
const postId = parseInt(String(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");
}
// Find the hidden post ownership entry
const hiddenPostOwnership = await strapi.db
.query("api::post-ownership.post-ownership")
.findOne({
where: {
post: postId,
author: user.id,
contextType: "user",
contextId: user.id,
relation: "hidden",
},
});
if (!hiddenPostOwnership) {
console.log("⚠️ Post is not hidden");
return ctx.badRequest("Post is not hidden");
}
// Delete the hidden post ownership entry
await strapi.db.query("api::post-ownership.post-ownership").delete({
where: { id: hiddenPostOwnership.id },
});
console.log("✅ Post unhidden successfully");
return ctx.send({
message: "Post unhidden successfully",
unhiddenPostId: postId,
});
},
})
);