const DBName = "EMI_SOCIAL"; let userProfileCache = {}; userDB = (DB) => { DB.profileCols = DB.db.db(DBName).collection("profiles"); DB.newProfile = (profileObj) => { return DB.profileCols.insertOne(profileObj.toObj()).catch((err) => { console.log(err); return false; }); } DB.removeProfile = (profileid) => { const _id = DB.ObjectID(profileid); if (userProfileCache[profileid]) delete userProfileCache[profileid]; return DB.profileCols.deleteOne({_id}).catch((err)=>{ console.log(err); return false; }); } DB.updateProfile = async (profileid, profileObj) => { let tempProfile = profileObj.toObj(); const query = {_id: profileid}; const update = { $set: { profile: tempProfile.profile, data: tempProfile.data } }; let r = await DB.profileCols.updateOne(query, update).catch((err) => { console.log(err); return false; }); return r; } DB.getProfile = async (profileId) => { //if (userProfileCache[profileId] && !userProfileCache[profileId].isGroup) return userProfileCache[profileId]; if(!profileId) return false; try{ const _id = DB.ObjectID(profileId); let r = await DB.profileCols.findOne({ _id }).catch((err) => { console.log(err); return false; }); if (r) userProfileCache[profileId] = r; return r; }catch(_){ return {}; } } DB.getPopularProfiles = async (limit = 10) => { return DB.profileCols.aggregate([ { $match: {isGroup: {$ne: true}} }, { $addFields: { subscribed_count: {$size: { "$ifNull": [ "$following", [] ] } } } }, { $sort: {"subscribed_count":-1} }, { $project: {_id: 1, "subscribed_count": 1} } ]).limit(limit).toArray().catch((err) => { console.log(err); return []; }); } DB.getPopularGroups = async (limit = 10) => { return DB.profileCols.aggregate([ { $match: {isGroup: true, isPrivate: {$ne: true}, isCourse: {$ne: true}} }, { $addFields: { subscribed_count: {$size: { "$ifNull": [ {"$objectToArray" : "$subscribed"}, [] ] } } } }, { $sort: {"subscribed_count":-1} }, { $project: {_id: 1, "subscribed_count": 1} } ]).limit(limit).toArray().catch((err) => { console.log(err); return []; }); } DB.getFriendsFriends = async (profileId, limit = 10) => { const profile = await DB.getProfile(profileId); if(!profile) return []; let ids = profile.following.map((id)=>DB.ObjectID(id)); let alreadyFollowingMap = {}; alreadyFollowingMap[profileId] = 1; //skip that profile profile.following.forEach(id => { if(!alreadyFollowingMap[id]) alreadyFollowingMap[id] = 1; }) return DB.profileCols.find({_id:{$in: ids}}).project({following: 1}).limit(limit).toArray().then(profiles => { let friendsOfFriendsMap = {}; profiles.forEach(p => { p.following.forEach(followingId => { if(alreadyFollowingMap[followingId]) return 0; if(!friendsOfFriendsMap[followingId]) friendsOfFriendsMap[followingId] = 0; friendsOfFriendsMap[followingId] = friendsOfFriendsMap[followingId] + 1; }); }); // sort by most related? return Object.keys(friendsOfFriendsMap); }).catch((err) => { console.log(err); return []; }); } DB.getProfileCache = async (profileId) => { if (userProfileCache[profileId] && !userProfileCache[profileId].isGroup) return userProfileCache[profileId]; return DB.getProfile(profileId); } DB.searchProfile = async (queryStr) => { let regEx = new RegExp(queryStr, 'i'); let query = { isGroup: false, isChat: {$ne: true}, $or: [ {"profile.firstName": { $regex: regEx }}, {"profile.lastName": { $regex: regEx }}, {"profile.description": { $regex: regEx }}, ] }; let r = await DB.profileCols.find(queryStr ? query : {isGroup: false, isChat: {$ne: true}}) .sort({ lastUpdate: -1 }).limit(20) .toArray().catch((err) => { console.log(err); return false; }); return r; } DB.getUserProfiles = async (userId) => { const userid = DB.ObjectID(userId); return await DB.profileCols.find({ userid }).toArray().catch((err) => { console.log(err); return false; }); } DB.latestProfile = async (userId) => { const userid = DB.ObjectID(userId); let r = await DB.profileCols.find({ userid }) .sort({ lastUpdate: -1 }) .toArray().catch((err) => { console.log(err); return false; }); let index = 0; while(r[index].isGroup || r[index].isChat) index += 1; if (r[index]) userProfileCache[r[index]._id] = r[index]; return r[index]; } DB.followProfile = async (profileId, followProfileId)=>{ const _id = DB.ObjectID(profileId); let update = { $addToSet:{ following: followProfileId + '' //converts to str } } return DB.profileCols.updateOne({_id}, update).catch((err)=>{ console.log(err); return false; }); } DB.unfollowProfile = async (profileId, followProfileId)=>{ const _id = DB.ObjectID(profileId); let update = { $pull:{ following: followProfileId + '' //converts to str } } return DB.profileCols.updateOne({_id}, update).catch((err)=>{ console.log(err); return false; }); } DB.getFollowingTheProfile = async (profileId) => { //const profile_id = DB.ObjectID(profileId); let r = await DB.profileCols.find({ following: (profileId+'') }) .toArray().catch((err) => { console.log(err); return []; }); return r; } DB.getData = async (profileid, key) => { let profile = await DB.getProfile(profileid); return profile.data[key]; } DB.setData = async (profileid, key, value) => { const _id = DB.ObjectID(profileid); let update = { $set:{ ["data." + key]: value } } return DB.profileCols.updateOne({_id}, update).catch((err)=>{ console.log(err); return false; }); } DB.setProfileToken = (profileid, token)=>{ if(!token) return false; const _id = DB.ObjectID(profileid); let update = { $addToSet:{ token } } if (userProfileCache[profileid]) delete userProfileCache[profileid]; return DB.profileCols.updateOne({_id}, update).catch((err)=>{ console.log(err); return false; }); } DB.setWebSubscription = (profileid, webSubscription)=>{ const _id = DB.ObjectID(profileid); let update = { $set:{ webSubscription } } if (userProfileCache[profileid]) delete userProfileCache[profileid]; return DB.profileCols.updateOne({_id}, update).catch((err)=>{ console.log(err); return false; }); } DB.addNotification = async (profileid, message, postid, commentIndx, actorid) => { const _id = DB.ObjectID(profileid); let update = { $push:{ notifications: { ts: new Date(), body: message, postid, commentIndx, actorid, } } } return DB.profileCols.updateOne({_id}, update).catch((err)=>{ console.log(err); return false; }); } DB.isSubscriptor = async (profileid) => { const profile = DB.getProfileCache(profileid); return profile && profile.subscription && profile.subscription > (new Date() - 0); } //Groups DB.getGroups = async (excludePrivate = false) => { let query = { isGroup: true, isCourse: {$ne: true}, isChat: {$ne: true}, }; if(excludePrivate) query.isPrivate = false; let r = await DB.profileCols.find(query).sort({ lastUpdate: -1 }).limit(10) .toArray().catch((err) => { console.log(err); return false; }); return r; } DB.getFollowingGroups = async (profileid) => { const profile = await DB.getProfile(profileid); let ids = []; for(id in profile.following){ try{ let oId = DB.ObjectID(profile.following[id]); let checkProfile = await DB.getProfileCache(oId) if(checkProfile && checkProfile.isGroup && !checkProfile.isChat){ ids.push(oId) } }catch{ } } let query = { isGroup: true, isCourse: {$ne: true}, isChat: {$ne: true}, _id: { $in: ids } }; let r = await DB.profileCols.find(query).sort({ lastUpdate: -1 }) .toArray().catch((err) => { console.log(err); return false; }); return r; } DB.searchGroups = async (queryStr, coursesB = false) => { let regEx = new RegExp(queryStr, 'i'); let query = queryStr ? { isGroup: true, isChat: {$ne: true}, isCourse: coursesB, $or: [ {"profile.firstName": { $regex: regEx }}, {"profile.lastName": { $regex: regEx }}, {"profile.description": { $regex: regEx }}, {"data.author": { $regex: regEx }} ] } : {isGroup: true, isChat: {$ne: true}, isCourse: coursesB}; let r = await DB.profileCols.find(query) .sort({ lastUpdate: -1 }).limit(20) .toArray().catch((err) => { console.log(err); return false; }); return r; } let privateGroupsCache = {}; DB.isGroupPrivate = async (groupid) => { if(userProfileCache[groupid]) return userProfileCache[groupid].isPrivate; let g = await DB.getGroup(groupid); return g ? g.isPrivate : false; } DB.isGroupNewsOnly = async (groupid) => { if(userProfileCache[groupid]) return userProfileCache[groupid].newsOnly; let g = await DB.getGroup(groupid); return g ? g.newsOnly : false; } DB.isOwnerOfGroup = async (profileid, groupid) => { let profile = await DB.getProfileCache(profileid); let group = userProfileCache[groupid] ? userProfileCache[groupid] : await DB.getGroup(groupid); return profile.userid == group.userid; } DB.getGroup = async (groupid) => { const _id = DB.ObjectID(groupid); //if(userProfileCache[groupid]) return userProfileCache[groupid]; let r = await DB.profileCols.findOne({_id, isGroup: true, isChat: {$ne: true},}).catch((err) => { console.log(err); return false; }); if (r) userProfileCache[r.id] = r; return r; } DB.subscribeToGroup = async (profileid, groupid, reqSubscription = false) => { const _id = DB.ObjectID(groupid); const subOrRequest = reqSubscription ? "pending." : "subscribed."; let update = { $set:{ [subOrRequest + profileid]: new Date() } } if(!reqSubscription) DB.followProfile(profileid, groupid); delete userProfileCache[groupid]; return DB.profileCols.updateOne({_id}, update).catch((err)=>{ console.log(err); return false; }); } DB.acceptGroupJoinReq = async (profileid, groupid) => { const _id = DB.ObjectID(groupid); let update = { $set:{ ["subscribed." + profileid]: new Date() }, $unset:{ ["pending." + profileid]: "" } } DB.followProfile(profileid, groupid); delete userProfileCache[groupid]; return DB.profileCols.updateOne({_id}, update).catch((err)=>{ console.log(err); return false; }); } DB.rejectGroupJoinReq = async (profileid, groupid) => { const _id = DB.ObjectID(groupid); let update = { $unset:{ ["pending." + profileid]: "" } } delete userProfileCache[groupid]; return DB.profileCols.updateOne({_id}, update).catch((err)=>{ console.log(err); return false; }); } DB.unsubscribeToGroup = async (profileid, groupid) => { const _id = DB.ObjectID(groupid); let update = { $unset:{ ["subscribed." + profileid]: "", } } DB.unfollowProfile(profileid, groupid) return DB.profileCols.updateOne({_id}, update).catch((err)=>{ console.log(err); return false; }); } //Courses DB.getCourses = async () => { let r = await DB.profileCols.find({isGroup: true, isCourse: true, isChat: {$ne: true}}) .sort({ lastUpdate: -1 }).limit(20) .toArray().catch((err) => { console.log(err); return false; }); return r; } } module.exports = userDB;