ping groups improvements

pull/134/head
Aevann 2023-02-24 21:29:07 +02:00
parent 96d0e697a4
commit d26cc5a83f
6 changed files with 107 additions and 74 deletions

View File

@ -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();
}
);
}

View File

@ -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

View File

@ -51,7 +51,7 @@ def create_group(v):
return redirect(f'/ping_groups?msg=!{group} created successfully!')
@app.post("/!<group_name>/join")
@app.post("/!<group_name>/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("/!<group_name>/applications")
@app.post("/!<group_name>/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("/!<group_name>/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("/!<group_name>/<user_id>/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("/!<group_name>/<user_id>/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!'}

View File

@ -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 %}
<h5 class="my-3">!{{group}} Applications</h5>
<div class="overflow-x-auto mt-1"><table class="table table-striped mb-5">
<thead class="bg-primary text-white">
<tr>
<th>Name</th>
<th>Applied on</th>
{% if v.id == group.owner.id %}
<th></th>
<th></th>
{% endif %}
</tr>
</thead>
<tbody>
{% for application in applications %}
<tr>
<td>
{% with user=application.user %}
{% include "user_in_table.html" %}
{% endwith %}
</td>
<td data-time="{{application.created_utc}}"></td>
{% if v.id == group.owner.id %}
<td>
<form class="d-inline" action="/!{{group}}/{{application.user_id}}/approve" method="post" data-nonce="{{g.nonce}}">
<input hidden name="formkey" value="{{v|formkey}}">
<input autocomplete="off" class="btn btn-success ml-auto" type="submit" data-nonce="{{g.nonce}}" data-onclick="disable(this)" value="Approve">
</form>
<form class="d-inline ml-3" action="/!{{group}}/{{application.user_id}}/reject" method="post" data-nonce="{{g.nonce}}">
<input hidden name="formkey" value="{{v|formkey}}">
<input autocomplete="off" class="btn btn-danger ml-auto" type="submit" data-nonce="{{g.nonce}}" data-onclick="disable(this)" value="Reject">
</form>
</td>
{% endif %}
</tr>
{% endfor %}
</tbody>
</table>
{% endblock %}

View File

@ -0,0 +1,42 @@
{% extends "default.html" %}
{% block pagetitle %}!{{group}} Members{% endblock %}
{% block content %}
<h5 class="my-3">!{{group}} Members</h5>
<div class="overflow-x-auto mt-1"><table class="table table-striped mb-5">
<thead class="bg-primary text-white">
<tr>
<th>Name</th>
<th>Joined on</th>
{% if v.id == group.owner.id %}
<th></th>
<th></th>
{% endif %}
</tr>
</thead>
<tbody>
{% for membership in group.memberships|reverse %}
<tr>
<td>
{% with user=membership.user %}
{% include "user_in_table.html" %}
{% endwith %}
</td>
{% if membership.approved_utc %}
<td data-time="{{membership.approved_utc}}"></td>
{% elif v.id == group.owner.id %}
<td>
<button type="button" class="btn btn-primary" data-nonce="{{g.nonce}}" data-onclick="approve_membership(this,'/!{{group}}/{{membership.user_id}}/approve')">Approve</button>
<button type="button" class="btn btn-primary" data-nonce="{{g.nonce}}" data-onclick="reject_membership(this,'/!{{group}}/{{membership.user_id}}/reject')">Reject</button>
</td>
{% endif %}
</tr>
{% endfor %}
</tbody>
</table>
{% if v.id == group.owner.id %}
<script defer src="{{'js/group_members_owner.js' | asset}}"></script>
{% endif %}
{% endblock %}

View File

@ -12,7 +12,7 @@
<th>#</th>
<th>Name</th>
<th>Members</th>
<th></th>
<th class="disable-sort-click"></th>
<th>Created on</th>
</tr>
</thead>
@ -21,25 +21,20 @@
<tr>
<td>{{loop.index}}</td>
<td>{{group.name}}</td>
<td><a href="/!{{group}}/members">{{group.member_ids | length}}</a></td>
<td>
<div class="ml-3 mt-1">
{% for user in group.members %}
<span class="mr-2">
{% include "user_in_table.html" %}
</span>
{% endfor %}
</div>
</td>
<td>
{% if v.id in group.applied_ids %}
<a class="btn btn-primary" href="/!{{group.name}}/applications">Application pending</a>
{% elif v.id not in group.member_ids %}
<form action="/!{{group}}/join" method="post" data-nonce="{{g.nonce}}">
<input hidden name="formkey" value="{{v|formkey}}">
<input autocomplete="off" class="btn btn-primary ml-auto" type="submit" data-nonce="{{g.nonce}}" data-onclick="disable(this)" value="Apply to Join">
</form>
{% if v.id == group.owner.id %}
<a class="btn btn-primary" href="/!{{group.name}}/members">Applications</a>
{% else %}
<a class="btn btn-primary" href="/!{{group.name}}/applications">Applications</a>
<button id="leave-{{group}}" type="button" class="btn btn-primary {% if v.id not in group.membership_user_ids %}d-none{% endif %}" data-nonce="{{g.nonce}}" data-onclick="postToastSwitch(this,'/!{{group}}/leave','leave-{{group}}','apply-{{group}}','d-none')">
{%- if v.id in group.member_ids -%}
Leave
{%- else -%}
Cancel Application
{%- endif -%}
</button>
<button id="apply-{{group}}" type="button" class="{% if v.id in group.membership_user_ids %}d-none{% endif %} btn btn-primary" data-nonce="{{g.nonce}}" data-onclick="postToastSwitch(this,'/!{{group}}/apply','leave-{{group}}','apply-{{group}}','d-none')">Apply to Join</button>
{% endif %}
</td>
<td data-time="{{group.created_utc}}"></td>
@ -75,4 +70,5 @@
</div>
</form>
</div>
{% endblock %}