Skip to content

Commit fe99fd2

Browse files
Add community management features: kick member, delete community, and leave community
1 parent 5cd632d commit fe99fd2

3 files changed

Lines changed: 251 additions & 242 deletions

File tree

Routes/router.js

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,9 @@ router.get('/discover', controller.discoverCommunities);
9191
router.post('/join-community/:id', controller.joinCommunityPublic);
9292
router.post('/com/:id/invite', controller.inviteMember);
9393
router.post('/accept-invitation/:id', controller.acceptInvitation);
94+
router.post('/com/:id/kick', auth.isLogin, controller.kickMember);
95+
router.post('/com/:id/delete', auth.isLogin, controller.deleteCommunity);
96+
router.post('/com/:id/leave', auth.isLogin, controller.leaveCommunity);
9497
router.post('/com/:id/settings', auth.isLogin, controller.updateCommunitySettings);
9598
router.get('/notifications', controller.getNotifications);
9699
router.post('/mark-notification-read', controller.markNotificationRead);

controllers/controller.js

Lines changed: 147 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -570,6 +570,150 @@ const inviteMember = async (req, res) => {
570570
}
571571
};
572572

573+
// Kick a member from community (owner only)
574+
const kickMember = async (req, res) => {
575+
try {
576+
const userId = req.session.user;
577+
const communityId = req.params.id;
578+
const { memberUsId } = req.body;
579+
580+
if (!userId) return res.status(401).json({ error: 'Not authenticated' });
581+
582+
const community = await Communities.findOne({ gp_id: communityId });
583+
if (!community) return res.status(404).json({ error: 'Community not found' });
584+
585+
// Only owner (first member) can kick
586+
const isOwner = community.members.length > 0 && community.members[0] === userId;
587+
if (!isOwner) return res.status(403).json({ error: 'Only community owner can remove members' });
588+
589+
if (!memberUsId) return res.status(400).json({ error: 'Missing member id to remove' });
590+
591+
// Prevent kicking the owner or self
592+
if (community.members[0] === memberUsId) return res.status(400).json({ error: 'Cannot remove community owner' });
593+
if (memberUsId === userId) return res.status(400).json({ error: 'You cannot remove yourself from the community' });
594+
595+
// Remove member if present
596+
const beforeCount = community.members.length;
597+
community.members = community.members.filter(id => id !== memberUsId);
598+
// Also remove from invitedMembers if present
599+
if (community.invitedMembers && community.invitedMembers.length > 0) {
600+
community.invitedMembers = community.invitedMembers.filter(id => id !== memberUsId);
601+
}
602+
603+
if (community.members.length === beforeCount) {
604+
return res.status(400).json({ error: 'Member not found in community' });
605+
}
606+
607+
await community.save();
608+
609+
// Notify the kicked user
610+
try {
611+
await sendNotification([memberUsId], 'general', `You have been removed from community ${community.Name}`);
612+
} catch (e) {
613+
console.log('Failed to notify kicked user:', e);
614+
}
615+
616+
return res.json({ success: true, message: 'Member removed' });
617+
} catch (error) {
618+
console.log('Error in kickMember:', error);
619+
return res.status(500).json({ error: 'Failed to remove member' });
620+
}
621+
};
622+
623+
// Delete community (owner only)
624+
const deleteCommunity = async (req, res) => {
625+
try {
626+
const userId = req.session.user;
627+
const communityId = req.params.id;
628+
629+
if (!userId) return res.status(401).json({ error: 'Not authenticated' });
630+
631+
const community = await Communities.findOne({ gp_id: communityId });
632+
if (!community) return res.status(404).json({ error: 'Community not found' });
633+
634+
// Only owner (first member) can delete
635+
const isOwner = community.members.length > 0 && community.members[0] === userId;
636+
if (!isOwner) return res.status(403).json({ error: 'Only community owner can delete community' });
637+
638+
// Collect members for notification
639+
const memberIds = Array.isArray(community.members) ? community.members.slice() : [];
640+
641+
// Delete problems belonging to community
642+
await Problems.deleteMany({ com_id: communityId });
643+
644+
// Delete the community
645+
await Communities.deleteOne({ gp_id: communityId });
646+
647+
// Notify members about deletion (best effort)
648+
try {
649+
if (memberIds.length > 0) {
650+
await sendNotification(memberIds, 'general', `Community ${community.Name} has been deleted by the owner.`);
651+
}
652+
} catch (e) {
653+
console.log('Failed to notify members of deletion:', e);
654+
}
655+
656+
// If request is AJAX, return JSON; else redirect
657+
if (req.headers['content-type'] && req.headers['content-type'].includes('application/json')) {
658+
return res.json({ success: true, message: 'Community deleted' });
659+
}
660+
661+
return res.redirect('/dashboard?success=Community deleted');
662+
} catch (error) {
663+
console.log('Error in deleteCommunity:', error);
664+
return res.status(500).json({ error: 'Failed to delete community' });
665+
}
666+
};
667+
668+
// Leave community (member can leave; owner cannot leave - must delete or transfer ownership)
669+
const leaveCommunity = async (req, res) => {
670+
try {
671+
const userId = req.session.user;
672+
const communityId = req.params.id;
673+
674+
if (!userId) return res.status(401).json({ error: 'Not authenticated' });
675+
676+
const community = await Communities.findOne({ gp_id: communityId });
677+
if (!community) return res.status(404).json({ error: 'Community not found' });
678+
679+
// If user is owner, prevent leaving (owner should delete or transfer)
680+
if (community.members.length > 0 && community.members[0] === userId) {
681+
return res.status(400).json({ error: 'Owner cannot leave the community. Delete or transfer ownership instead.' });
682+
}
683+
684+
// Check membership
685+
if (!community.members.includes(userId)) {
686+
return res.status(400).json({ error: 'You are not a member of this community' });
687+
}
688+
689+
// Remove user
690+
community.members = community.members.filter(id => id !== userId);
691+
await community.save();
692+
693+
// Notify owner that a member left
694+
try {
695+
console.log("here")
696+
const ownerId = community.members.length > 0 ? community.members[0] : null;
697+
if (ownerId && ownerId !== userId) {
698+
console.log("here")
699+
await sendNotification([ownerId], 'general', `${req.session.user} left the community ${community.Name}`);
700+
}
701+
} catch (e) {
702+
console.log('Failed to notify owner about leave:', e);
703+
}
704+
705+
// If AJAX, return JSON; else redirect
706+
if (req.headers['content-type'] && req.headers['content-type'].includes('application/json')) {
707+
return res.json({ success: true, message: 'Left community' });
708+
}
709+
710+
return res.redirect('/dashboard?success=Left community');
711+
} catch (error) {
712+
console.log('Error in leaveCommunity:', error);
713+
return res.status(500).json({ error: 'Failed to leave community' });
714+
}
715+
};
716+
573717
const markProblemSolved = async (req, res) => {
574718
try {
575719
const userId = req.session.user;
@@ -1132,6 +1276,8 @@ module.exports = {
11321276
logout_user,
11331277
inviteMember,
11341278
acceptInvitation,
1279+
kickMember,
1280+
leaveCommunity,
11351281
getNotifications,
11361282
markNotificationRead,
11371283
discoverCommunities,
@@ -1143,6 +1289,7 @@ module.exports = {
11431289
searchCommunities,
11441290
joinCommunity,
11451291
updateCommunitySettings,
1292+
deleteCommunity,
11461293
updateProfile,
11471294
profileSettings,
11481295
forgotPinPage,

0 commit comments

Comments
 (0)