Files
EMI-Backend/dbTools/profile.js
2026-02-20 22:15:13 -05:00

515 lines
16 KiB
JavaScript

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();
if (!DB.ObjectID.isValid(profileid)) return false;
const _id = DB.ObjectID(profileid);
const query = { _id };
const update = {
$set: {
profile: tempProfile.profile,
data: tempProfile.data
}
};
let r = await DB.profileCols.updateOne(query, update).catch((err) => {
console.log(err);
return false;
});
if (userProfileCache[profileid]) delete userProfileCache[profileid];
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 [];
const following = Array.isArray(profile.following) ? profile.following : [];
let ids = following.filter((id) => DB.ObjectID.isValid(id)).map((id) => DB.ObjectID(id));
let alreadyFollowingMap = {};
alreadyFollowingMap[profileId] = 1; //skip that 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 => {
const related = Array.isArray(p.following) ? p.following : [];
related.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.getProfileCache = async (profileId) => {
const cachedProfile = userProfileCache[profileId];
if (cachedProfile?.isGroup === false) {
return cachedProfile;
}
return await 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 [];
});
}
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,
viewed: false,
}
}
}
const r = await DB.profileCols.updateOne({ _id }, update).catch((err) => {
console.log(err);
return false;
});
if (userProfileCache[profileid]) delete userProfileCache[profileid];
return r;
}
DB.markNotificationsViewed = async (profileid) => {
const _id = DB.ObjectID(profileid);
const update = {
$set: {
"notifications.$[n].viewed": true
}
};
const options = {
arrayFilters: [
{ "n.viewed": { $ne: true } }
]
};
const r = await DB.profileCols.updateOne({ _id }, update, options).catch((err) => {
console.log(err);
return false;
});
if (userProfileCache[profileid]) delete userProfileCache[profileid];
return r;
}
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 = [];
const following = Array.isArray(profile?.following) ? profile.following : [];
for (id in following) {
try {
let oId = DB.ObjectID(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;