diff --git a/files/assets/js/group_members_owner.js b/files/assets/js/group_members_owner.js new file mode 100644 index 000000000..963df9378 --- /dev/null +++ b/files/assets/js/group_members_owner.js @@ -0,0 +1,19 @@ +function approve_membership(t, url) { + postToast(t, url, + { + }, + () => { + t.parentElement.innerHTML = formatDate(new Date()); + } + ); +} + +function reject_membership(t, url) { + postToast(t, url, + { + }, + () => { + t.parentElement.parentElement.remove(); + } + ); +} diff --git a/files/classes/group.py b/files/classes/group.py index 64e827f89..2b2ec2796 100644 --- a/files/classes/group.py +++ b/files/classes/group.py @@ -31,13 +31,13 @@ class Group(Base): @property @lazy - def members(self): - return [x.user for x in self.memberships if x.approved_utc] + def membership_user_ids(self): + return [x.user_id for x in self.memberships] @property @lazy def member_ids(self): - return [x.id for x in self.members] + return [x.user_id for x in self.memberships if x.approved_utc] @property @lazy diff --git a/files/routes/groups.py b/files/routes/groups.py index 1f5a95583..a9173b889 100644 --- a/files/routes/groups.py +++ b/files/routes/groups.py @@ -51,7 +51,7 @@ def create_group(v): return redirect(f'/ping_groups?msg=!{group} created successfully!') -@app.post("/!/join") +@app.post("/!/apply") @limiter.limit(DEFAULT_RATELIMIT, key_func=get_ID) @auth_required def join_group(v:User, group_name): @@ -61,18 +61,38 @@ def join_group(v:User, group_name): if not existing: join = GroupMembership(user_id=v.id, group_name=group_name) g.db.add(join) - send_repeatable_notification(group.owner.id, f"@{v.username} has applied to join !{group}. You can approve or reject the application [here](/!{group}/applications).") + send_notification(group.owner.id, f"@{v.username} has applied to join !{group}. You can approve or reject the application [here](/!{group}/members).") - return redirect(f"/ping_groups?msg=Application submitted to !{group}'s owner (@{group.owner.username}) successfully!") + return {"message": f"Application submitted to !{group}'s owner (@{group.owner.username}) successfully!"} -@app.get("/!/applications") +@app.post("/!/leave") @limiter.limit(DEFAULT_RATELIMIT, key_func=get_ID) @auth_required -def applications(v:User, group_name): +def leave_group(v:User, group_name): group = g.db.get(Group, group_name) if not group: abort(404) - applications = g.db.query(GroupMembership).filter_by(group_name=group_name, approved_utc=None).order_by(GroupMembership.created_utc.desc()).all() - return render_template('group_applications.html', v=v, group=group, applications=applications, msg=get_msg()) + existing = g.db.query(GroupMembership).filter_by(user_id=v.id, group_name=group_name).one_or_none() + if existing: + if existing.approved_utc: + text = f"@{v.username} has left !{group}" + msg = f"You have left !{group} successfully!" + else: + text = f"@{v.username} has cancelled their application to !{group}" + msg = f"You have cancelled your application to !{group} successfully!" + + send_notification(group.owner.id, text) + g.db.delete(existing) + + return {"message": msg} + + +@app.get("/!/members") +@limiter.limit(DEFAULT_RATELIMIT, key_func=get_ID) +@auth_required +def memberships(v:User, group_name): + group = g.db.get(Group, group_name) + if not group: abort(404) + return render_template('group_memberships.html', v=v, group=group) @app.post("/!//approve") @limiter.limit(DEFAULT_RATELIMIT, key_func=get_ID) @@ -93,7 +113,7 @@ def group_approve(v:User, group_name, user_id): g.db.add(application) send_repeatable_notification(application.user_id, f"@{v.username} (!{group}'s owner) has approved your application!") - return redirect(f'/!{group}/applications?msg=@{application.user.username} has been approved successfully!') + return {"message": f'@{application.user.username} has been approved successfully!'} @app.post("/!//reject") @limiter.limit(DEFAULT_RATELIMIT, key_func=get_ID) @@ -112,4 +132,4 @@ def group_reject(v:User, group_name, user_id): g.db.delete(application) send_repeatable_notification(application.user_id, f"@{v.username} (!{group}'s owner) has rejected your application!") - return redirect(f'/!{group}/applications?msg=@{application.user.username} has been rejected successfully!') + return {"message": f'@{application.user.username} has been rejected successfully!'} diff --git a/files/templates/group_applications.html b/files/templates/group_applications.html deleted file mode 100644 index ff1dc72c3..000000000 --- a/files/templates/group_applications.html +++ /dev/null @@ -1,44 +0,0 @@ -{% extends "default.html" %} -{% block pagetitle %}!{{group}} Applications{% endblock %} -{% block content %} -{% if error %}{{macros.alert(error, true)}}{% endif %} -{% if msg %}{{macros.alert(msg, false)}}{% endif %} -
!{{group}} Applications
-
- - - - - {% if v.id == group.owner.id %} - - - {% endif %} - - - -{% for application in applications %} - - - - {% if v.id == group.owner.id %} - - {% endif %} - -{% endfor %} - -
NameApplied on
- {% with user=application.user %} - {% include "user_in_table.html" %} - {% endwith %} - -
- - -
-
- - -
-
- -{% endblock %} diff --git a/files/templates/group_memberships.html b/files/templates/group_memberships.html new file mode 100644 index 000000000..fa57b4859 --- /dev/null +++ b/files/templates/group_memberships.html @@ -0,0 +1,42 @@ +{% extends "default.html" %} +{% block pagetitle %}!{{group}} Members{% endblock %} +{% block content %} +
!{{group}} Members
+
+ + + + + {% if v.id == group.owner.id %} + + + {% endif %} + + + +{% for membership in group.memberships|reverse %} + + + + {% if membership.approved_utc %} + + {% elif v.id == group.owner.id %} + + {% endif %} + +{% endfor %} + +
NameJoined on
+ {% with user=membership.user %} + {% include "user_in_table.html" %} + {% endwith %} + + + +
+ +{% if v.id == group.owner.id %} + +{% endif %} + +{% endblock %} diff --git a/files/templates/groups.html b/files/templates/groups.html index 21c867313..4daddf05a 100644 --- a/files/templates/groups.html +++ b/files/templates/groups.html @@ -12,7 +12,7 @@ # Name Members - + Created on @@ -21,25 +21,20 @@ {{loop.index}} {{group.name}} + {{group.member_ids | length}} -
- {% for user in group.members %} - - {% include "user_in_table.html" %} - - {% endfor %} -
- - - {% if v.id in group.applied_ids %} - Application pending - {% elif v.id not in group.member_ids %} -
- - -
+ {% if v.id == group.owner.id %} + Applications {% else %} - Applications + + + {% endif %} @@ -75,4 +70,5 @@
+ {% endblock %}