Files
EMI-Backend/routes/post.js
Adolfo Reyna 64ca9df639 Tags support
2025-07-17 09:32:27 -04:00

399 lines
13 KiB
JavaScript

var express = require('express');
var router = express.Router();
const DB = require("./../mongoDB.js");
const Post = require("./../def/post.js");
const Notifications = require("./../notifications.js");
DB.getDB.then((DB) => {
const getProfileId = (req) => {
return DB.ObjectID(req.cookies.profile_id || req.query.profile_id || req.body.profile_id);
};
const postBelongToProfile = (post, profileid) => {
if (!post) return false;
return post.profileid == profileid;
};
const generateNonOrganicPosts = async (req, profileid) => {
let posts = [];
// News Posts
const newsPosts = await DB.getNews();
posts.push(...newsPosts);
// Popular Profiles
const popularProfiles = await DB.getPopularProfiles(5);
content = "Active users to follow:\n";
popularProfiles.forEach((p) => {
content += "@p:" + p._id + "\n";
});
let popularProfilesPost = new Post({ profileid: 1, content, nonOrganicType: "PopularUsers" });
posts.push(popularProfilesPost);
// Popular Groups
const popularGroups = await DB.getPopularGroups(5);
content = "Popular groups to follow:\n";
popularGroups.forEach((p) => {
content += "@p:" + p._id + "\n";
});
let popularGroupsPost = new Post({ profileid: 1, content, nonOrganicType: "PopularGroups" });
posts.push(popularGroupsPost);
const yourFollowsInterests = await DB.getFriendsFriends(profileid);
content = "People your follow has these interests:\n";
yourFollowsInterests.forEach((p) => {
content += "@p:" + p + "\n";
});
let yourFollowsInterestsPost = new Post({ profileid: 1, content, nonOrganicType: "PopularUsers" });
posts.push(yourFollowsInterestsPost);
return posts;
};
const mergePosts = (organic, nonOrganic) => {
if (!organic || organic.length < 5) return nonOrganic;
//organic.push(...nonOrganic);
let mergedPosts = [];
while (organic.length + nonOrganic.length) {
if (organic.length == 0) {
mergedPosts.push(nonOrganic.shift());
continue;
}
if (nonOrganic.length == 0) {
mergedPosts.push(organic.shift());
continue;
}
if (nonOrganic[0].nonOrganicType == 'News') {
mergedPosts.push(nonOrganic.shift());
continue;
}
if (Math.random() < 0.2) {
mergedPosts.push(nonOrganic.shift());
} else {
mergedPosts.push(organic.shift());
}
}
return mergedPosts;
};
router.get("/organic", async (req, res) => {
const profileid = getProfileId(req);
let organicPosts = await DB.getFeed(profileid);
//Add non-organic posts
const nonOrganicPosts = await generateNonOrganicPosts(req, profileid);
const posts = mergePosts(organicPosts, nonOrganicPosts);
return res.json(posts);
});
router.get("/", async (req, res) => {
const profileid = getProfileId(req);
//Add non-organic posts
const nonOrganicPosts = await generateNonOrganicPosts(req, profileid);
let promotionalPosts = await DB.getPromotionalPosts(profileid);
const posts = mergePosts(promotionalPosts, nonOrganicPosts);
return res.json(posts);
});
router.get("/tag/:tag", async (req, res) => {
const profileid = getProfileId(req);
const tag = req.query.tag || req.params.tag;
if(!tag) {
console.log("Tag query empty: ", tag);
return res.json({
status: "Tag is required",
});
}
console.log("Tag query: ", tag);
let posts = await DB.getPostsByTag('#' + tag, profileid);
return res.json(posts);
});
router.get("/usr/:id", async (req, res) => {
const profileId = req.params.id;
const viewerProdileId = getProfileId(req);
const profile = await DB.getProfileCache(profileId);
const posts = await DB.getPosts(profileId, viewerProdileId);
if (profile.isCourse) {
//check for subscription
//const viewerProdile = await DB.getProfileCache(viewerProdileId);
//if (!viewerProdile.subscription || viewerProdile.subscription < (new Date()-1)) {
// return res.json([posts[posts.length - 1]]);
//}
}
return res.json(posts);
});
router.get("/usr/:id/images", async (req, res) => {
const profileid = req.params.id;
const viewerProfileId = getProfileId(req);
const posts = await DB.getMediaTagPostOfUser(profileid, viewerProfileId);
return res.json({
status: "ok",
posts
});
});
router.get("/usr/:id/embedded", async (req, res) => {
const profileid = req.params.id;
const viewerProfileId = getProfileId(req);
const posts = await DB.getMediaTagPostOfUser(profileid, viewerProfileId, "@iframe:");
return res.json({
status: "ok",
posts
});
});
router.get("/usr/:id/media", async (req, res) => {
const profileid = req.params.id;
const viewerProfileId = getProfileId(req);
const posts = await DB.getMediaTagPostOfUser(profileid, viewerProfileId, "@youtube:|@vimeo:|@hls:");
return res.json({
status: "ok",
posts
});
});
router.get("/video/:id", async (req, res) => {
videoId = req.params.id;
return res.json([]);
});
router.post("/", async (req, res) => {
let post = {
profileid: getProfileId(req),
...req.body
}
const isGroupPrivate = await DB.isGroupPrivate(post.toProfile);
const isGroupNewsOnly = await DB.isGroupNewsOnly(post.toProfile);
if (post.toProfile && isGroupPrivate) {
let requestProfile = getProfileId(req) + "";
let group = await DB.getProfileCache(post.toProfile);
if (!group.subscribed[requestProfile] && group._id != requestProfile) {
return res.json({
status: "You are not part of this private group",
});
}
}
if (post.toProfile && isGroupNewsOnly) {
return res.json({
status: "This is a news only group, only the admin can post",
});
}
post.toProfile = post.toProfile ? DB.ObjectID(post.toProfile) : undefined;
let postObj = new Post(post);
let dbr = await DB.newPost(postObj);
post = postObj.toObj();
post._id = dbr.insertedId;
if ((post.toProfile && post.toProfile != post.profileid) || post.nonOrganicType == 'News') {
await Notifications.youGotANewPost(post);
}
await Notifications.yourGroupMakeANewPost(post);
if(!isGroupPrivate){
await Notifications.yourSubscriptionProfileHasNewPost(post);
}
return res.json({
status: "ok",
...post
})
});
router.post("/react", async (req, res) => {
let profileid = getProfileId(req);
let postid = req.body.postid;
let reaction = {
type: "like",
createdAt: new Date()
};
r = await DB.newReaction(postid, profileid, reaction);
Notifications.youGotANewReaction(postid, profileid, 'like');
return res.json({
status: "ok"
});
});
router.post("/unreact", async (req, res) => {
let profileid = getProfileId(req);
let postid = req.body.postid;
r = await DB.removeReaction(postid, profileid);
return res.json({
status: "ok"
})
});
router.post("/bookmark", async (req, res) => {
let profileid = getProfileId(req);
let postid = req.body.postid;
r = await DB.bookmarkPost(postid, profileid);
return res.json({
status: "ok"
});
})
router.post("/unbookmark", async (req, res) => {
let profileid = getProfileId(req);
let postid = req.body.postid;
r = await DB.unbookmarkPost(postid, profileid);
return res.json({
status: "ok"
})
});
router.post("/comment/", async (req, res) => {
let profileid = getProfileId(req);
let postid = req.body.postid;
let content = req.body.content;
let comment = {
profileid: profileid,
content: content,
createdAt: new Date(),
lastUpdated: new Date(),
reactions: {}
}
Notifications.youGotANewPostComment(postid, profileid, content)
r = await DB.newComment(postid, comment);
return res.json({
status: "ok",
...comment
})
});
router.post("/comment/react", async (req, res) => {
let userid = getProfileId(req);
let postid = req.body.postid;
let commentDate = new Date(req.body.commentDate);
let reaction = {
type: "like",
createdAt: new Date()
};
r = await DB.newCommentReaction(postid, commentDate, userid, reaction);
return res.json({
status: "ok"
})
});
router.post("/comment/unreact", async (req, res) => {
let profileid = getProfileId(req);
let postid = req.body.postid;
let commentDate = new Date(req.body.commentDate);
r = await DB.removeCommentReaction(postid, commentDate, profileid);
return res.json({
status: "ok"
})
});
router.get("/images", async (req, res) => {
const profileid = getProfileId(req);
const posts = await DB.getMediaTagPostOfUser(profileid, profileid);
return res.json({
status: "ok",
posts
});
});
router.get("/embedded", async (req, res) => {
const profileid = getProfileId(req);
const posts = await DB.getMediaTagPostOfUser(profileid, profileid, "@iframe:");
return res.json({
status: "ok",
posts
});
});
router.get("/media", async (req, res) => {
const profileid = getProfileId(req);
const posts = await DB.getMediaTagPostOfUser(profileid, profileid, "@youtube:|@vimeo:|@hls:");
return res.json({
status: "ok",
posts
});
});
router.get("/course/recent", async (req, res) => {
const profileid = getProfileId(req);
const profile = await DB.getProfileCache(profileid);
const mediaPostsId = []
const recentMedia = {};
const mediaProfileP = []
let postPromises = [];
// Get watch information from profile data
Object.keys(profile.data).forEach(key => {
// So far we only use watch info using postid keys
if(DB.ObjectID.isValid(key)){
mediaPostsId.push(profile.data[key]);
postPromises.push(DB.getPostCached(profile.data[key].postId));
if(!recentMedia[profile.data[key].profileId]){
recentMedia[profile.data[key].profileId] = [];
mediaProfileP.push(DB.getProfileCache(profile.data[key].profileId));
}
}
});
recentMediaArray = mediaPostsId.sort((a,b)=>{
return b.ts - a.ts;
});
const postObjs = await Promise.all(postPromises);
const postObjsMap = postObjs.reduce((map, item)=>{
map[item._id] = item;
return map
}, {});
recentMediaArray.forEach(record => {
const postAndRecord = {
watchRecord: record,
... postObjsMap[record.postId]
}
recentMedia[record.profileId].push(postAndRecord);
});
// Transform profiles array to dict
let mediaProfile = await Promise.all(mediaProfileP);
let mediaProfileMap = mediaProfile.reduce((dict, item) => {
dict[item._id] = item;
return dict;
}, {});
return res.json({
status: "ok",
recentMedia,
mediaProfileMap,
});
});
router.get("/:id", async (req, res) => {
const postId = req.params.id;
const post = await DB.getPost(postId);
return res.json({
status: "ok",
...post
});
});
router.delete("/:id", async (req, res) => {
const profileid = getProfileId(req) + '';
const postId = req.params.id;
const post = await DB.getPost(postId);
if (!postBelongToProfile(post, profileid))
return res.json({
status: "This post is not yours."
});
await DB.removePost(postId);
return res.json({
status: "ok"
});
});
router.post("/:id", async (req, res) => {
const profileid = getProfileId(req) + '';
const postId = req.params.id;
const post = await DB.getPost(postId);
const newContent = req.body.content;
if (!postBelongToProfile(post, profileid))
return res.json({
status: "This post is not yours."
});
await DB.updatePost(postId, newContent, post.content);
return res.json({
status: "ok"
});
});
});
module.exports = router