pull/182/head
parent
8b1f7baa74
commit
6e02ea8abb
|
@ -7321,6 +7321,10 @@ input[type=number] {
|
||||||
height: 50px;
|
height: 50px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.group-mod {
|
||||||
|
height: 40px;
|
||||||
|
}
|
||||||
|
|
||||||
@media (max-width: 768px) {
|
@media (max-width: 768px) {
|
||||||
.award-tab {
|
.award-tab {
|
||||||
font-size: 10px !important;
|
font-size: 10px !important;
|
||||||
|
@ -7343,6 +7347,10 @@ input[type=number] {
|
||||||
.group-owner {
|
.group-owner {
|
||||||
height: 30px;
|
height: 30px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.group-mod {
|
||||||
|
height: 23px;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#input-message, #input-message-mobile {
|
#input-message, #input-message-mobile {
|
||||||
|
|
|
@ -6,6 +6,8 @@ function approve_membership(t, group, uid) {
|
||||||
{
|
{
|
||||||
},
|
},
|
||||||
() => {
|
() => {
|
||||||
|
const mod = document.getElementById(`mod-${uid}`)
|
||||||
|
if (mod) mod.classList.remove('d-none')
|
||||||
document.getElementById(`kick-${uid}`).classList.remove('d-none')
|
document.getElementById(`kick-${uid}`).classList.remove('d-none')
|
||||||
document.getElementById(`time-${uid}`).innerHTML = formatDate(new Date());
|
document.getElementById(`time-${uid}`).innerHTML = formatDate(new Date());
|
||||||
document.getElementById(`counter-${uid}`).innerHTML = parseInt(members_tbody.lastElementChild.firstElementChild.innerHTML) + 1
|
document.getElementById(`counter-${uid}`).innerHTML = parseInt(members_tbody.lastElementChild.firstElementChild.innerHTML) + 1
|
||||||
|
|
|
@ -2,7 +2,7 @@ import time
|
||||||
|
|
||||||
from sqlalchemy import Column, ForeignKey
|
from sqlalchemy import Column, ForeignKey
|
||||||
from sqlalchemy.orm import relationship
|
from sqlalchemy.orm import relationship
|
||||||
from sqlalchemy.types import Integer, String
|
from sqlalchemy.types import Integer, String, Boolean
|
||||||
|
|
||||||
from files.classes import Base
|
from files.classes import Base
|
||||||
|
|
||||||
|
@ -12,6 +12,7 @@ class GroupMembership(Base):
|
||||||
group_name = Column(String, ForeignKey("groups.name"), primary_key=True)
|
group_name = Column(String, ForeignKey("groups.name"), primary_key=True)
|
||||||
created_utc = Column(Integer)
|
created_utc = Column(Integer)
|
||||||
approved_utc = Column(Integer)
|
approved_utc = Column(Integer)
|
||||||
|
is_mod = Column(Boolean, default=False)
|
||||||
|
|
||||||
user = relationship("User", uselist=False)
|
user = relationship("User", uselist=False)
|
||||||
|
|
||||||
|
|
|
@ -393,6 +393,13 @@ class User(Base):
|
||||||
except:
|
except:
|
||||||
return bool(g.db.query(Mod.user_id).filter_by(user_id=self.id, sub=sub).one_or_none())
|
return bool(g.db.query(Mod.user_id).filter_by(user_id=self.id, sub=sub).one_or_none())
|
||||||
|
|
||||||
|
@lazy
|
||||||
|
def mods_group(self, group):
|
||||||
|
if self.is_permabanned or self.shadowbanned: return False
|
||||||
|
if self.id == group.owner.id: return True
|
||||||
|
if self.admin_level >= PERMS['MODS_EVERY_GROUP']: return True
|
||||||
|
return bool(g.db.query(GroupMembership.user_id).filter_by(user_id=self.id, group_name=group.name, is_mod=True).one_or_none())
|
||||||
|
|
||||||
@lazy
|
@lazy
|
||||||
def exiler_username(self, sub):
|
def exiler_username(self, sub):
|
||||||
exile = g.db.query(Exile).options(load_only(Exile.exiler_id)).filter_by(user_id=self.id, sub=sub).one_or_none()
|
exile = g.db.query(Exile).options(load_only(Exile.exiler_id)).filter_by(user_id=self.id, sub=sub).one_or_none()
|
||||||
|
|
|
@ -152,8 +152,8 @@ def group_approve(v, group_name, user_id):
|
||||||
group = g.db.get(Group, group_name)
|
group = g.db.get(Group, group_name)
|
||||||
if not group: abort(404)
|
if not group: abort(404)
|
||||||
|
|
||||||
if v.id != group.owner.id and v.admin_level < PERMS['MODS_EVERY_GROUP']:
|
if not v.mods_group(group):
|
||||||
abort(403, f"Only the group owner (@{group.owner.username}) can approve applications!")
|
abort(403, f"Only the group owner and its mods can approve applications!")
|
||||||
|
|
||||||
application = g.db.query(GroupMembership).filter_by(user_id=user_id, group_name=group.name).one_or_none()
|
application = g.db.query(GroupMembership).filter_by(user_id=user_id, group_name=group.name).one_or_none()
|
||||||
if not application:
|
if not application:
|
||||||
|
@ -178,8 +178,8 @@ def group_reject(v, group_name, user_id):
|
||||||
group = g.db.get(Group, group_name)
|
group = g.db.get(Group, group_name)
|
||||||
if not group: abort(404)
|
if not group: abort(404)
|
||||||
|
|
||||||
if v.id != group.owner.id and v.admin_level < PERMS['MODS_EVERY_GROUP']:
|
if not v.mods_group(group):
|
||||||
abort(403, f"Only the group owner (@{group.owner.username}) can reject memberships!")
|
abort(403, f"Only the group owner and its mods can reject memberships!")
|
||||||
|
|
||||||
membership = g.db.query(GroupMembership).filter_by(user_id=user_id, group_name=group.name).one_or_none()
|
membership = g.db.query(GroupMembership).filter_by(user_id=user_id, group_name=group.name).one_or_none()
|
||||||
if not membership:
|
if not membership:
|
||||||
|
@ -204,3 +204,55 @@ def group_reject(v, group_name, user_id):
|
||||||
g.db.delete(group)
|
g.db.delete(group)
|
||||||
|
|
||||||
return {"message": msg}
|
return {"message": msg}
|
||||||
|
|
||||||
|
@app.post("/!<group_name>/<user_id>/add_mod")
|
||||||
|
@limiter.limit('1/second', scope=rpath)
|
||||||
|
@limiter.limit('1/second', scope=rpath, key_func=get_ID)
|
||||||
|
@limiter.limit(DEFAULT_RATELIMIT, deduct_when=lambda response: response.status_code < 400)
|
||||||
|
@limiter.limit(DEFAULT_RATELIMIT, deduct_when=lambda response: response.status_code < 400, key_func=get_ID)
|
||||||
|
@auth_required
|
||||||
|
def group_add_mod(v, group_name, user_id):
|
||||||
|
group_name = group_name.strip().lower()
|
||||||
|
|
||||||
|
group = g.db.get(Group, group_name)
|
||||||
|
if not group: abort(404)
|
||||||
|
|
||||||
|
if v.id != group.owner.id:
|
||||||
|
abort(403, f"Only the group owner (@{group.owner.username}) can add mods!")
|
||||||
|
|
||||||
|
membership = g.db.query(GroupMembership).filter_by(user_id=user_id, group_name=group.name).one_or_none()
|
||||||
|
if not membership:
|
||||||
|
abort(404, "The user is not a member of the group!")
|
||||||
|
|
||||||
|
membership.is_mod = True
|
||||||
|
g.db.add(membership)
|
||||||
|
|
||||||
|
send_repeatable_notification(membership.user_id, f"@{v.username} (!{group}'s owner) has added you as a mod!")
|
||||||
|
|
||||||
|
return {"message": f'You have added @{membership.user.username} as a mod successfully!'}
|
||||||
|
|
||||||
|
@app.post("/!<group_name>/<user_id>/remove_mod")
|
||||||
|
@limiter.limit('1/second', scope=rpath)
|
||||||
|
@limiter.limit('1/second', scope=rpath, key_func=get_ID)
|
||||||
|
@limiter.limit(DEFAULT_RATELIMIT, deduct_when=lambda response: response.status_code < 400)
|
||||||
|
@limiter.limit(DEFAULT_RATELIMIT, deduct_when=lambda response: response.status_code < 400, key_func=get_ID)
|
||||||
|
@auth_required
|
||||||
|
def group_remove_mod(v, group_name, user_id):
|
||||||
|
group_name = group_name.strip().lower()
|
||||||
|
|
||||||
|
group = g.db.get(Group, group_name)
|
||||||
|
if not group: abort(404)
|
||||||
|
|
||||||
|
if v.id != group.owner.id:
|
||||||
|
abort(403, f"Only the group owner (@{group.owner.username}) can remove mods!")
|
||||||
|
|
||||||
|
membership = g.db.query(GroupMembership).filter_by(user_id=user_id, group_name=group.name).one_or_none()
|
||||||
|
if not membership:
|
||||||
|
abort(404, "The user is not a member of the group!")
|
||||||
|
|
||||||
|
membership.is_mod = False
|
||||||
|
g.db.add(membership)
|
||||||
|
|
||||||
|
send_repeatable_notification(membership.user_id, f"@{v.username} (!{group}'s owner) has removed you as a mod!")
|
||||||
|
|
||||||
|
return {"message": f'You have removed @{membership.user.username} as a mod successfully!'}
|
||||||
|
|
|
@ -31,7 +31,7 @@
|
||||||
<th>Applied on</th>
|
<th>Applied on</th>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
{% if v.id == group.owner.id or v.admin_level >= PERMS['MODS_EVERY_GROUP'] %}
|
{% if v.mods_group(group) %}
|
||||||
<th class="disable-sort-click"></th>
|
<th class="disable-sort-click"></th>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</tr>
|
</tr>
|
||||||
|
@ -47,6 +47,8 @@
|
||||||
{% endwith %}
|
{% endwith %}
|
||||||
{% if owner %}
|
{% if owner %}
|
||||||
<img class="mx-2 group-owner" data-bs-toggle="tooltip" alt="Owner" title="Owner" src="{{SITE_FULL_IMAGES}}/e/marseykingretard.webp">
|
<img class="mx-2 group-owner" data-bs-toggle="tooltip" alt="Owner" title="Owner" src="{{SITE_FULL_IMAGES}}/e/marseykingretard.webp">
|
||||||
|
{% elif membership.is_mod %}
|
||||||
|
<img class="mx-2 group-mod" data-bs-toggle="tooltip" alt="Mod" title="Mod" src="{{SITE_FULL_IMAGES}}/e/marseyjanny.webp">
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</td>
|
</td>
|
||||||
|
|
||||||
|
@ -56,8 +58,15 @@
|
||||||
<td id="time-{{membership.user_id}}" data-time="{{membership.created_utc}}"></td>
|
<td id="time-{{membership.user_id}}" data-time="{{membership.created_utc}}"></td>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
{% if v.id == group.owner.id or v.admin_level >= PERMS['MODS_EVERY_GROUP'] %}
|
{% if v.mods_group(group) %}
|
||||||
<td>
|
<td>
|
||||||
|
{% if v.id == group.owner.id and v.id != membership.user_id %}
|
||||||
|
<div id="mod-{{membership.user_id}}" class="mb-2 {% if name == 'applications' %}d-none{% endif %}">
|
||||||
|
<button id="add-mod-{{membership.user_id}}" type="button" class="btn btn-success btn-block {% if membership.is_mod %}d-none{% endif %}" data-nonce="{{g.nonce}}" data-onclick="postToastSwitch(this,'/!{{group.name}}/{{membership.user_id}}/add_mod','add-mod-{{membership.user_id}}','remove-mod-{{membership.user_id}}','d-none')">Add as Mod</button>
|
||||||
|
<button id="remove-mod-{{membership.user_id}}" type="button" class="btn btn-danger btn-block {% if not membership.is_mod %}d-none{% endif %}" data-nonce="{{g.nonce}}" data-onclick="postToastSwitch(this,'/!{{group.name}}/{{membership.user_id}}/remove_mod','add-mod-{{membership.user_id}}','remove-mod-{{membership.user_id}}','d-none')">Remove as Mod</button>
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
<div id="kick-{{membership.user_id}}" {% if name == 'applications' %}class="d-none"{% endif %}>
|
<div id="kick-{{membership.user_id}}" {% if name == 'applications' %}class="d-none"{% endif %}>
|
||||||
<button type="button" class="btn btn-primary btn-block" data-nonce="{{g.nonce}}" data-onclick="reject_membership(this,'{{group}}','{{membership.user_id}}')">{% if v.id == membership.user_id %}Leave{% else %}Kick{% endif %}</button>
|
<button type="button" class="btn btn-primary btn-block" data-nonce="{{g.nonce}}" data-onclick="reject_membership(this,'{{group}}','{{membership.user_id}}')">{% if v.id == membership.user_id %}Leave{% else %}Kick{% endif %}</button>
|
||||||
</div>
|
</div>
|
||||||
|
@ -75,7 +84,7 @@
|
||||||
</div>
|
</div>
|
||||||
{% endmacro %}
|
{% endmacro %}
|
||||||
|
|
||||||
{% if v.id == group.owner.id or v.admin_level >= PERMS['MODS_EVERY_GROUP'] %}
|
{% if v.mods_group(group) %}
|
||||||
{{process_memberships(applications, 'applications')}}
|
{{process_memberships(applications, 'applications')}}
|
||||||
{{process_memberships(members, 'members')}}
|
{{process_memberships(members, 'members')}}
|
||||||
<script defer src="{{'js/group_members_owner.js' | asset}}"></script>
|
<script defer src="{{'js/group_members_owner.js' | asset}}"></script>
|
||||||
|
|
|
@ -0,0 +1,2 @@
|
||||||
|
alter table group_memberships add column is_mod bool not null default false;
|
||||||
|
alter table group_memberships alter column is_mod drop default;
|
Loading…
Reference in New Issue