Merge pull request #390 from justcool393/permissions-refactor

[DO NOT MERGE] complete permissions refactor
remotes/1693176582716663532/tmp_refs/heads/watchparty
justcool393 2022-10-06 19:56:05 -07:00 committed by GitHub
commit 460894346d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
39 changed files with 562 additions and 475 deletions

View File

@ -322,8 +322,8 @@ class Comment(Base):
def realbody(self, v):
if self.post and self.post.club and not (v and (v.paid_dues or v.id in [self.author_id, self.post.author_id] or (self.parent_comment and v.id == self.parent_comment.author_id))):
return f"<p>{CC} ONLY</p>"
if self.deleted_utc != 0 and not (v and (v.admin_level >= 2 or v.id == self.author.id)): return "[Deleted by user]"
if self.is_banned and not (v and v.admin_level >= 2): return "[Removed by admins]";
if self.deleted_utc != 0 and not (v and (v.admin_level >= PERMS['POST_COMMENT_MODERATION'] or v.id == self.author.id)): return "[Deleted by user]"
if self.is_banned and not (v and v.admin_level >= PERMS['POST_COMMENT_MODERATION']): return "[Removed by admins]"
body = self.body_html or ""
@ -389,8 +389,8 @@ class Comment(Base):
def plainbody(self, v):
if self.post and self.post.club and not (v and (v.paid_dues or v.id in [self.author_id, self.post.author_id] or (self.parent_comment and v.id == self.parent_comment.author_id))):
return f"{CC} ONLY"
if self.deleted_utc != 0 and not (v and (v.admin_level >= 2 or v.id == self.author.id)): return "[Deleted by user]"
if self.is_banned and not (v and v.admin_level >= 2): return "[Removed by admins]";
if self.deleted_utc != 0 and not (v and (v.admin_level >= PERMS['POST_COMMENT_MODERATION'] or v.id == self.author.id)): return "[Deleted by user]"
if self.is_banned and not (v and v.admin_level >= PERMS['POST_COMMENT_MODERATION']): return "[Removed by admins]"
body = self.body

View File

@ -326,8 +326,8 @@ class Submission(Base):
@lazy
def realbody(self, v, listing=False):
if self.club and not (v and (v.paid_dues or v.id == self.author_id)): return f"<p>{CC} ONLY</p>"
if self.deleted_utc != 0 and not (v and (v.admin_level >= 2 or v.id == self.author.id)): return "[Deleted by user]"
if self.is_banned and not (v and v.admin_level >= 2): return "[Removed by admins]"
if self.deleted_utc != 0 and not (v and (v.admin_level >= PERMS['POST_COMMENT_MODERATION'] or v.id == self.author.id)): return "[Deleted by user]"
if self.is_banned and not (v and v.admin_level >= PERMS['POST_COMMENT_MODERATION']): return "[Removed by admins]"
body = self.body_html or ""
@ -369,7 +369,7 @@ class Submission(Base):
if o.exclusive == 3:
body += " - <b>WINNER!</b>"
if not winner and v and v.admin_level > 2:
if not winner and v and v.admin_level >= PERMS['POST_BETS_DISTRIBUTE']:
body += f'''<button class="btn btn-primary distribute" onclick="this.nextElementSibling.classList.remove('d-none');this.classList.add('d-none')">Declare winner</button><button class="btn btn-primary distribute d-none" onclick="post_toast(this,'/distribute/{o.id}',true)">Are you sure?</button>'''
body += "</div>"
else:
@ -395,8 +395,8 @@ class Submission(Base):
@lazy
def plainbody(self, v):
if self.deleted_utc != 0 and not (v and (v.admin_level >= 2 or v.id == self.author.id)): return "[Deleted by user]"
if self.is_banned and not (v and v.admin_level >= 2): return "[Removed by admins]"
if self.deleted_utc != 0 and not (v and (v.admin_level >= PERMS['POST_COMMENT_MODERATION'] or v.id == self.author.id)): return "[Deleted by user]"
if self.is_banned and not (v and v.admin_level >= PERMS['POST_COMMENT_MODERATION']): return "[Removed by admins]"
if self.club and not (v and (v.paid_dues or v.id == self.author_id)): return f"<p>{CC} ONLY</p>"
body = self.body

View File

@ -285,7 +285,7 @@ class User(Base):
@lazy
def mods(self, sub):
if self.is_suspended_permanently or self.shadowbanned: return False
return self.admin_level > 2 or bool(g.db.query(Mod.user_id).filter_by(user_id=self.id, sub=sub).one_or_none())
return self.admin_level >= PERMS['GLOBAL_MODERATION'] or bool(g.db.query(Mod.user_id).filter_by(user_id=self.id, sub=sub).one_or_none())
@lazy
def exiled_from(self, sub):
@ -319,7 +319,7 @@ class User(Base):
@lazy
def mod_date(self, sub):
if self.admin_level >= 3: return 1
if self.admin_level >= PERMS['HOLE_GLOBAL_MODERATION']: return 1
mod = g.db.query(Mod).filter_by(user_id=self.id, sub=sub).one_or_none()
if not mod: return None
return mod.created_utc
@ -414,9 +414,10 @@ class User(Base):
@property
@lazy
def paid_dues(self):
if not FEATURES['COUNTRY_CLUB']:
return True
return not self.shadowbanned and not (self.is_banned and not self.unban_utc) and (self.admin_level or self.club_allowed or (self.club_allowed != False and self.truecoins >= dues))
if not FEATURES['COUNTRY_CLUB']: return True
if self.shadowbanned: return False
if self.is_suspended_permanently: return False
return self.admin_level >= PERMS['VIEW_CLUB'] or self.club_allowed or (self.club_allowed != False and self.truecoins >= dues)
@lazy
def any_block_exists(self, other):
@ -453,11 +454,11 @@ class User(Base):
@cache.memoize(timeout=86400)
def userpagelisting(self, site=None, v=None, page=1, sort="new", t="all"):
if self.shadowbanned and not (v and (v.admin_level > 1 or v.id == self.id)): return []
if self.shadowbanned and not (v and (v.admin_level >= PERMS['USER_SHADOWBAN'] or v.id == self.id)): return []
posts = g.db.query(Submission.id).filter_by(author_id=self.id, is_pinned=False)
if not (v and (v.admin_level > 1 or v.id == self.id)):
if not (v and (v.admin_level >= PERMS['POST_COMMENT_MODERATION'] or v.id == self.id)):
posts = posts.filter_by(is_banned=False, private=False, ghost=False, deleted_utc=0)
posts = apply_time_filter(t, posts, Submission)
@ -565,7 +566,7 @@ class User(Base):
@property
@lazy
def modaction_num(self):
if self.admin_level < 2: return 0
if self.admin_level < PERMS['ADMIN_MOP_VISIBLE']: return 0
return g.db.query(ModAction).filter_by(user_id=self.id).count()
@property
@ -585,7 +586,7 @@ class User(Base):
Notification.user_id == self.id, Notification.read == False,
Comment.is_banned == False, Comment.deleted_utc == 0)
if not self.shadowbanned and self.admin_level < 3:
if not self.shadowbanned and self.admin_level < PERMS['USER_SHADOWBAN']:
notifs = notifs.join(Comment.author).filter(User.shadowbanned == None)
return notifs.count() + self.post_notifications_count + self.modaction_notifications_count
@ -610,7 +611,7 @@ class User(Base):
Comment.parent_submission == None,
)
if not self.shadowbanned and self.admin_level < 3:
if not self.shadowbanned and self.admin_level < PERMS['USER_SHADOWBAN']:
notifs = notifs.join(Comment.author).filter(User.shadowbanned == None)
return notifs.count()
@ -767,8 +768,8 @@ class User(Base):
'bannerurl': self.banner_url,
'bio_html': self.bio_html_eager,
'coins': self.coins,
'post_count': 0 if self.shadowbanned and not (v and (v.shadowbanned or v.admin_level >= 2)) else self.post_count,
'comment_count': 0 if self.shadowbanned and not (v and (v.shadowbanned or v.admin_level >= 2)) else self.comment_count,
'post_count': 0 if self.shadowbanned and not (v and (v.shadowbanned or v.admin_level >= PERMS['USER_SHADOWBAN'])) else self.post_count,
'comment_count': 0 if self.shadowbanned and not (v and (v.shadowbanned or v.admin_level >= PERMS['USER_SHADOWBAN'])) else self.comment_count,
'badges': [x.path for x in self.badges],
}
@ -895,7 +896,7 @@ class User(Base):
def viewers_recorded(self):
if SITE_NAME == 'WPD': # WPD gets profile views
return True
elif self.admin_level >= 2: # Admins get profile views
elif self.admin_level >= PERMS['VIEW_PROFILE_VIEWS']: # Admins get profile views
return True
elif self.patron: # Patrons get profile views as a perk
return True
@ -919,7 +920,7 @@ class User(Base):
@property
@lazy
def can_see_chudrama(self):
if self.admin_level: return True
if self.admin_level >= PERMS['VIEW_CHUDRAMA']: return True
if self.client: return True
if self.truecoins >= 5000: return True
if self.agendaposter: return True

View File

@ -95,7 +95,7 @@ def NOTIFY_USERS(text, v):
notify_users.add(user.id)
if SITE_NAME == "WPD" and 'daisy' in text.lower():
admin_ids = [x[0] for x in g.db.query(User.id).filter(User.admin_level > 0).all()]
admin_ids = [x[0] for x in g.db.query(User.id).filter(User.admin_level >= PERMS['NOTIFICATIONS_SPECIFIC_WPD_COMMENTS']).all()]
notify_users.update(admin_ids)
return notify_users - bots

View File

@ -121,12 +121,76 @@ AGENDAPOSTER_MSG_HTML = """<p>Hi <a href="/id/{id}"><img loading="lazy" src="/pp
################################################################################
PERMS = { # Minimum admin_level to perform action.
'ADMIN_ADD': 3, # note: explicitly disabled on rDrama
'ADMIN_REMOVE': 3,
'ADMIN_ADD_PERM_LEVEL': 2, # permission level given when user added via site
'ADMIN_ACTIONS_REVERT': 3,
'ADMIN_MOP_VISIBLE': 2,
'ADMIN_HOME_VISIBLE': 2,
'DOMAINS_BAN': 3,
'HOLE_CREATE': 0,
'HOLE_GLOBAL_MODERATION': 3,
'FLAGS_REMOVE': 2,
'VOTES_VISIBLE': 0,
'USER_BLOCKS_VISIBLE': 0,
'USER_FOLLOWS_VISIBLE': 0,
'USER_VOTERS_VISIBLE': 0,
'POST_COMMENT_MODERATION': 2,
'POST_COMMENT_DISTINGUISH': 1,
'POST_COMMENT_MODERATION_TOOLS_VISIBLE': 2, # note: does not affect API at all
'POST_EDITING': 3,
'USER_BADGES': 2,
'USER_BAN': 2,
'USER_SHADOWBAN': 2,
'USER_AGENDAPOSTER': 2,
'USER_CLUB_ALLOW_BAN': 2,
'USER_LINK': 2,
'USER_MERGE': 3, # note: extra check for Aevann
'USER_TITLE_CHANGE': 2,
'USER_MODERATION_TOOLS_VISIBLE': 2, # note: does not affect API at all
'POST_TO_CHANGELOG': 1, # note: code contributors can also post to changelog
'POST_TO_POLL_THREAD': 2,
'POST_BETS': 3,
'POST_BETS_DISTRIBUTE': 3, # probably should be the same as POST_BETS but w/e
'BYPASS_PIN_LIMIT': 3,
'VIEW_PENDING_SUBMITTED_MARSEYS': 3,
'VIEW_PENDING_SUBMITTED_HATS': 3,
'MODERATE_PENDING_SUBMITTED_MARSEYS': 3, # note: there is an extra check so that only """carp""" can approve them
'MODERATE_PENDING_SUBMITTED_HATS': 3, # note: there is an extra check so that only """carp""" can approve them
'UPDATE_MARSEYS': 3, # note: extra check is here for 4 different users
'UPDATE_HATS': 3, # note: extra check is here for 4 different users
'BUY_GHOST_AWARD': 2,
'LOTTERY_ADMIN': 3,
'LOTTERY_VIEW_PARTICIPANTS': 2,
'VIEW_MODMAIL': 2,
'VIEW_CLUB': 1,
'VIEW_CHUDRAMA': 1,
'VIEW_PRIVATE_PROFILES': 2,
'VIEW_ALTS': 2,
'VIEW_PROFILE_VIEWS': 2,
'VIEW_SORTED_ADMIN_LIST': 3,
'VIEW_ACTIVE_USERS': 2,
'VIEW_ALL_USERS': 2,
'VIEW_ALT_VOTES': 2,
'VIEW_LAST_ACTIVE': 2,
'VIEW_PATRONS': 3, # note: extra check for Aevann, carp, or snakes
'VIEW_VOTE_BUTTONS_ON_USER_PAGE': 2,
'PRINT_MARSEYBUX_FOR_KIPPY_ON_PCMEMES': 3, # note: explicitly disabled on rDrama
'SITE_SETTINGS': 3,
'SITE_SETTINGS_SIDEBARS_BANNERS_BADGES': 3,
'SITE_SETTINGS_SNAPPY_QUOTES': 3,
'SITE_SETTINGS_UNDER_ATTACK': 3,
'SITE_CACHE_PURGE_CDN': 3,
'SITE_CACHE_DUMP_INTERNAL': 2,
'NOTIFICATIONS_HOLE_INACTIVITY_DELETION': 2,
'NOTIFICATIONS_HOLE_CREATION': 2,
'NOTIFICATIONS_FROM_SHADOWBANNED_USERS': 3,
'NOTIFICATIONS_MODMAIL': 3,
'NOTIFICATIONS_SPECIFIC_WPD_COMMENTS': 1,
'MESSAGE_BLOCKED_USERS': 1,
'APPS_MODERATION': 3,
'STREAMERS_MODERATION': 2,
'UNKNOWN_ADMIN_LEVEL2_PERM4': 2, # TODO: figure out what this is and remove it if unnecessary
}
FEATURES = {
@ -217,6 +281,7 @@ GIFT_NOTIF_ID = 5
if SITE == 'rdrama.net':
FEATURES['PRONOUNS'] = True
FEATURES['HOUSES'] = True
PERMS['ADMIN_ADD_PERM_LEVEL'] = 0 # extra check here to disallow adding admins on site
SIDEBAR_THREAD = 37696
BANNER_THREAD = 37697

View File

@ -65,7 +65,7 @@ def sub_inactive_purge_task():
dead_holes = g.db.query(Sub).filter(Sub.name.notin_(active_holes)).all()
names = [x.name for x in dead_holes]
admins = [x[0] for x in g.db.query(User.id).filter(User.admin_level > 1).all()]
admins = [x[0] for x in g.db.query(User.id).filter(User.admin_level >= PERMS['NOTIFICATIONS_HOLE_INACTIVITY_DELETION']).all()]
mods = g.db.query(Mod).filter(Mod.sub.in_(names)).all()
for x in mods:

View File

@ -39,7 +39,7 @@ def get_user(username, v=None, graceful=False, rendered=False, include_blocks=Fa
user = user.one_or_none()
if not user or (user.shadowbanned and not (include_shadowbanned or (v and (v.admin_level >= 2 or v.shadowbanned)))):
if not user or (user.shadowbanned and not (include_shadowbanned or (v and (v.admin_level >= PERMS['USER_SHADOWBAN'] or v.shadowbanned)))):
if not graceful: abort(404)
else: return None
@ -95,7 +95,7 @@ def get_account(id, v=None, graceful=False, include_blocks=False, include_shadow
user = g.db.get(User, id)
if not user or (user.shadowbanned and not (include_shadowbanned or (v and (v.admin_level >= 2 or v.shadowbanned)))):
if not user or (user.shadowbanned and not (include_shadowbanned or (v and (v.admin_level >= PERMS['USER_SHADOWBAN'] or v.shadowbanned)))):
if not graceful: abort(404)
else: return None
@ -264,7 +264,7 @@ def get_comments(cids, v=None, load_parent=False):
blocked.c.target_id,
).filter(Comment.id.in_(cids))
if not (v and (v.shadowbanned or v.admin_level >= 2)):
if not (v and (v.shadowbanned or v.admin_level >= PERMS['USER_SHADOWBAN'])):
comments = comments.join(Comment.author).filter(User.shadowbanned == None)
comments = comments.join(

View File

@ -22,28 +22,29 @@ import requests
from urllib.parse import quote, urlencode
@app.post('/kippy')
@admin_level_required(3)
@admin_level_required(PERMS['PRINT_MARSEYBUX_FOR_KIPPY_ON_PCMEMES'])
def kippy(v):
if SITE == 'rdrama.net': abort(404)
kippy = get_account(KIPPY_ID)
kippy.procoins += 10000
g.db.add(kippy)
return '10k marseycoins printed!'
@app.get('/admin/loggedin')
@admin_level_required(2)
@admin_level_required(PERMS['VIEW_ACTIVE_USERS'])
def loggedin_list(v):
ids = [x for x,val in cache.get(f'{SITE}_loggedin').items() if time.time()-val < LOGGEDIN_ACTIVE_TIME]
users = g.db.query(User).filter(User.id.in_(ids)).order_by(User.admin_level.desc(), User.truecoins.desc()).all()
return render_template("loggedin.html", v=v, users=users)
@app.get('/admin/loggedout')
@admin_level_required(2)
@admin_level_required(PERMS['VIEW_ACTIVE_USERS'])
def loggedout_list(v):
users = sorted([val[1] for x,val in cache.get(f'{SITE}_loggedout').items() if time.time()-val[0] < LOGGEDIN_ACTIVE_TIME])
return render_template("loggedout.html", v=v, users=users)
@app.get('/admin/merge/<id1>/<id2>')
@admin_level_required(3)
@admin_level_required(PERMS['USER_MERGE'])
def merge(v, id1, id2):
if v.id != AEVANN_ID: abort(403)
@ -105,7 +106,7 @@ def merge(v, id1, id2):
@app.get('/admin/merge_all/<id>')
@admin_level_required(3)
@admin_level_required(PERMS['USER_MERGE'])
def merge_all(v, id):
if v.id != AEVANN_ID: abort(403)
@ -155,13 +156,13 @@ def merge_all(v, id):
@app.post("/@<username>/make_admin")
@admin_level_required(3)
@admin_level_required(PERMS['ADMIN_ADD'])
def make_admin(v, username):
if SITE == 'rdrama.net': abort(403)
user = get_user(username)
user.admin_level = 2
user.admin_level = PERMS['ADMIN_ADD_PERM_LEVEL']
g.db.add(user)
ma = ModAction(
@ -175,7 +176,7 @@ def make_admin(v, username):
@app.post("/@<username>/remove_admin")
@admin_level_required(3)
@admin_level_required(PERMS['ADMIN_REMOVE'])
def remove_admin(v, username):
user = get_user(username)
user.admin_level = 0
@ -192,7 +193,7 @@ def remove_admin(v, username):
@app.post("/distribute/<option_id>")
@limiter.limit("1/second;30/minute;200/hour;1000/day")
@admin_level_required(3)
@admin_level_required(PERMS['POST_BETS_DISTRIBUTE'])
def distribute(v, option_id):
autojanny = get_account(AUTOJANNY_ID)
if autojanny.coins == 0: return {"error": "@AutoJanny has 0 coins"}, 400
@ -248,7 +249,7 @@ def distribute(v, option_id):
@app.post("/@<username>/revert_actions")
@limiter.limit("1/second;30/minute;200/hour;1000/day")
@admin_level_required(3)
@admin_level_required(PERMS['ADMIN_ACTIONS_REVERT'])
def revert_actions(v, username):
user = get_user(username)
@ -298,7 +299,7 @@ def revert_actions(v, username):
@app.post("/@<username>/club_allow")
@limiter.limit("1/second;30/minute;200/hour;1000/day")
@admin_level_required(2)
@admin_level_required(PERMS['USER_CLUB_ALLOW_BAN'])
def club_allow(v, username):
u = get_user(username, v=v)
@ -324,7 +325,7 @@ def club_allow(v, username):
@app.post("/@<username>/club_ban")
@limiter.limit("1/second;30/minute;200/hour;1000/day")
@admin_level_required(2)
@admin_level_required(PERMS['USER_CLUB_ALLOW_BAN'])
def club_ban(v, username):
u = get_user(username, v=v)
@ -351,13 +352,13 @@ def club_ban(v, username):
@app.get("/admin/shadowbanned")
@auth_required
def shadowbanned(v):
if not (v and v.admin_level > 1): abort(404)
if not (v and v.admin_level >= PERMS['USER_SHADOWBAN']): abort(404)
users = g.db.query(User).filter(User.shadowbanned != None).order_by(User.shadowbanned).all()
return render_template("shadowbanned.html", v=v, users=users)
@app.get("/admin/image_posts")
@admin_level_required(2)
@admin_level_required(PERMS['POST_COMMENT_MODERATION'])
def image_posts_listing(v):
try: page = int(request.values.get('page', 1))
@ -375,7 +376,7 @@ def image_posts_listing(v):
@app.get("/admin/reported/posts")
@admin_level_required(2)
@admin_level_required(PERMS['POST_COMMENT_MODERATION'])
def reported_posts(v):
page = max(1, int(request.values.get("page", 1)))
@ -396,7 +397,7 @@ def reported_posts(v):
@app.get("/admin/reported/comments")
@admin_level_required(2)
@admin_level_required(PERMS['POST_COMMENT_MODERATION'])
def reported_comments(v):
page = max(1, int(request.values.get("page", 1)))
@ -421,11 +422,11 @@ def reported_comments(v):
standalone=True)
@app.get("/admin")
@admin_level_required(2)
@admin_level_required(PERMS['ADMIN_HOME_VISIBLE'])
def admin_home(v):
under_attack = False
if v.admin_level > 2:
if v.admin_level >= PERMS['SITE_SETTINGS_UNDER_ATTACK']:
if CF_ZONE == 'blahblahblah': response = 'high'
else: response = requests.get(f'https://api.cloudflare.com/client/v4/zones/{CF_ZONE}/settings/security_level', headers=CF_HEADERS, timeout=5).json()['result']['value']
under_attack = response == 'under_attack'
@ -453,7 +454,7 @@ def admin_git_head():
return gitref
@app.post("/admin/site_settings/<setting>")
@admin_level_required(3)
@admin_level_required(PERMS['SITE_SETTINGS'])
def change_settings(v, setting):
site_settings = app.config['SETTINGS']
site_settings[setting] = not site_settings[setting]
@ -474,7 +475,7 @@ def change_settings(v, setting):
@app.post("/admin/purge_cache")
@admin_level_required(3)
@admin_level_required(PERMS['SITE_CACHE_PURGE_CDN'])
def purge_cache(v):
online = cache.get(ONLINE_STR)
cache.clear()
@ -493,7 +494,7 @@ def purge_cache(v):
@app.post("/admin/under_attack")
@admin_level_required(3)
@admin_level_required(PERMS['SITE_SETTINGS_UNDER_ATTACK'])
def under_attack(v):
response = requests.get(f'https://api.cloudflare.com/client/v4/zones/{CF_ZONE}/settings/security_level', headers=CF_HEADERS, timeout=5).json()['result']['value']
@ -519,7 +520,7 @@ def under_attack(v):
return {"error": "Failed to enable under attack mode."}, 400
@app.get("/admin/badge_grant")
@admin_level_required(2)
@admin_level_required(PERMS['USER_BADGES'])
def badge_grant_get(v):
if not FEATURES['BADGES']:
abort(404)
@ -530,7 +531,7 @@ def badge_grant_get(v):
@app.post("/admin/badge_grant")
@limiter.limit("1/second;30/minute;200/hour;1000/day")
@admin_level_required(2)
@admin_level_required(PERMS['USER_BADGES'])
def badge_grant_post(v):
if not FEATURES['BADGES']:
abort(404)
@ -580,7 +581,7 @@ def badge_grant_post(v):
@app.get("/admin/badge_remove")
@admin_level_required(2)
@admin_level_required(PERMS['USER_BADGES'])
def badge_remove_get(v):
if not FEATURES['BADGES']:
abort(404)
@ -592,7 +593,7 @@ def badge_remove_get(v):
@app.post("/admin/badge_remove")
@limiter.limit("1/second;30/minute;200/hour;1000/day")
@admin_level_required(2)
@admin_level_required(PERMS['USER_BADGES'])
def badge_remove_post(v):
if not FEATURES['BADGES']:
abort(404)
@ -629,7 +630,7 @@ def badge_remove_post(v):
@app.get("/admin/users")
@admin_level_required(2)
@admin_level_required(PERMS['VIEW_ALL_USERS'])
def users_list(v):
try: page = int(request.values.get("page", 1))
@ -650,7 +651,7 @@ def users_list(v):
@app.get("/admin/alt_votes")
@admin_level_required(2)
@admin_level_required(PERMS['VIEW_ALT_VOTES'])
def alt_votes_get(v):
u1 = request.values.get("u1")
@ -757,7 +758,7 @@ def alt_votes_get(v):
@app.post("/admin/link_accounts")
@limiter.limit("1/second;30/minute;200/hour;1000/day")
@admin_level_required(2)
@admin_level_required(PERMS['USER_LINK'])
def admin_link_accounts(v):
u1 = int(request.values.get("u1"))
@ -787,7 +788,7 @@ def admin_link_accounts(v):
@app.get("/admin/removed/posts")
@admin_level_required(2)
@admin_level_required(PERMS['POST_COMMENT_MODERATION'])
def admin_removed(v):
try: page = int(request.values.get("page", 1))
@ -814,7 +815,7 @@ def admin_removed(v):
@app.get("/admin/removed/comments")
@admin_level_required(2)
@admin_level_required(PERMS['POST_COMMENT_MODERATION'])
def admin_removed_comments(v):
try: page = int(request.values.get("page", 1))
@ -839,7 +840,7 @@ def admin_removed_comments(v):
@app.post("/agendaposter/<user_id>")
@admin_level_required(2)
@admin_level_required(PERMS['USER_AGENDAPOSTER'])
def agendaposter(user_id, v):
user = get_account(user_id)
@ -873,7 +874,7 @@ def agendaposter(user_id, v):
@app.post("/unagendaposter/<user_id>")
@admin_level_required(2)
@admin_level_required(PERMS['USER_AGENDAPOSTER'])
def unagendaposter(user_id, v):
user = get_account(user_id)
@ -902,7 +903,7 @@ def unagendaposter(user_id, v):
@app.post("/shadowban/<user_id>")
@limiter.limit("1/second;30/minute;200/hour;1000/day")
@admin_level_required(2)
@admin_level_required(PERMS['USER_SHADOWBAN'])
def shadowban(user_id, v):
user = get_account(user_id)
if user.admin_level != 0: abort(403)
@ -932,7 +933,7 @@ def shadowban(user_id, v):
@app.post("/unshadowban/<user_id>")
@limiter.limit("1/second;30/minute;200/hour;1000/day")
@admin_level_required(2)
@admin_level_required(PERMS['USER_SHADOWBAN'])
def unshadowban(user_id, v):
user = get_account(user_id)
user.shadowbanned = None
@ -957,7 +958,7 @@ def unshadowban(user_id, v):
@app.post("/admin/title_change/<user_id>")
@limiter.limit("1/second;30/minute;200/hour;1000/day")
@admin_level_required(2)
@admin_level_required(PERMS['USER_TITLE_CHANGE'])
def admin_title_change(user_id, v):
user = get_account(user_id)
@ -992,7 +993,7 @@ def admin_title_change(user_id, v):
@app.post("/ban_user/<user_id>")
@limiter.limit("1/second;30/minute;200/hour;1000/day")
@admin_level_required(2)
@admin_level_required(PERMS['USER_BAN'])
def ban_user(user_id, v):
user = get_account(user_id)
@ -1055,7 +1056,7 @@ def ban_user(user_id, v):
@app.post("/unban_user/<user_id>")
@limiter.limit("1/second;30/minute;200/hour;1000/day")
@admin_level_required(2)
@admin_level_required(PERMS['USER_BAN'])
def unban_user(user_id, v):
user = get_account(user_id)
if not user.is_banned:
@ -1086,7 +1087,7 @@ def unban_user(user_id, v):
@app.post("/mute_user/<int:user_id>/<int:mute_status>")
@limiter.limit("1/second;30/minute;200/hour;1000/day")
@admin_level_required(2)
@admin_level_required(PERMS['USER_BAN'])
def mute_user(v, user_id, mute_status):
user = get_account(user_id)
@ -1116,7 +1117,7 @@ def mute_user(v, user_id, mute_status):
@app.post("/remove_post/<post_id>")
@limiter.limit("1/second;30/minute;200/hour;1000/day")
@admin_level_required(2)
@admin_level_required(PERMS['POST_COMMENT_MODERATION'])
def remove_post(post_id, v):
post = get_post(post_id)
post.is_banned = True
@ -1148,7 +1149,7 @@ def remove_post(post_id, v):
@app.post("/approve_post/<post_id>")
@limiter.limit("1/second;30/minute;200/hour;1000/day")
@admin_level_required(2)
@admin_level_required(PERMS['POST_COMMENT_MODERATION'])
def approve_post(post_id, v):
post = get_post(post_id)
@ -1179,11 +1180,11 @@ def approve_post(post_id, v):
@app.post("/distinguish/<post_id>")
@admin_level_required(1)
@admin_level_required(PERMS['POST_COMMENT_DISTINGUISH'])
def distinguish_post(post_id, v):
post = get_post(post_id)
if post.author_id != v.id and v.admin_level < 2 : abort(403)
if post.author_id != v.id and v.admin_level < PERMS['POST_COMMENT_MODERATION']: abort(403)
if post.distinguish_level:
post.distinguish_level = 0
@ -1207,7 +1208,7 @@ def distinguish_post(post_id, v):
@app.post("/sticky/<post_id>")
@admin_level_required(2)
@admin_level_required(PERMS['POST_COMMENT_MODERATION'])
def sticky_post(post_id, v):
if not FEATURES['PINS']:
abort(403)
@ -1216,7 +1217,7 @@ def sticky_post(post_id, v):
if not post.stickied:
pins = g.db.query(Submission).filter(Submission.stickied != None, Submission.is_banned == False).count()
if pins >= PIN_LIMIT:
if v.admin_level > 2:
if v.admin_level >= PERMS['BYPASS_PIN_LIMIT']:
post.stickied = v.username
post.stickied_utc = int(time.time()) + 3600
else: return {"error": f"Can't exceed {PIN_LIMIT} pinned posts limit!"}, 403
@ -1237,7 +1238,7 @@ def sticky_post(post_id, v):
return {"message": "Post pinned!"}
@app.post("/unsticky/<post_id>")
@admin_level_required(2)
@admin_level_required(PERMS['POST_COMMENT_MODERATION'])
def unsticky_post(post_id, v):
post = get_post(post_id)
@ -1262,7 +1263,7 @@ def unsticky_post(post_id, v):
return {"message": "Post unpinned!"}
@app.post("/sticky_comment/<cid>")
@admin_level_required(2)
@admin_level_required(PERMS['POST_COMMENT_MODERATION'])
def sticky_comment(cid, v):
comment = get_comment(cid, v=v)
@ -1286,7 +1287,7 @@ def sticky_comment(cid, v):
@app.post("/unsticky_comment/<cid>")
@admin_level_required(2)
@admin_level_required(PERMS['POST_COMMENT_MODERATION'])
def unsticky_comment(cid, v):
comment = get_comment(cid, v=v)
@ -1313,7 +1314,7 @@ def unsticky_comment(cid, v):
@app.post("/remove_comment/<c_id>")
@limiter.limit("1/second;30/minute;200/hour;1000/day")
@admin_level_required(2)
@admin_level_required(PERMS['POST_COMMENT_MODERATION'])
def remove_comment(c_id, v):
comment = get_comment(c_id)
@ -1333,7 +1334,7 @@ def remove_comment(c_id, v):
@app.post("/approve_comment/<c_id>")
@limiter.limit("1/second;30/minute;200/hour;1000/day")
@admin_level_required(2)
@admin_level_required(PERMS['POST_COMMENT_MODERATION'])
def approve_comment(c_id, v):
comment = get_comment(c_id)
@ -1360,7 +1361,7 @@ def approve_comment(c_id, v):
@app.post("/distinguish_comment/<c_id>")
@admin_level_required(1)
@admin_level_required(PERMS['POST_COMMENT_DISTINGUISH'])
def admin_distinguish_comment(c_id, v):
@ -1389,7 +1390,7 @@ def admin_distinguish_comment(c_id, v):
else: return {"message": "Comment undistinguished!"}
@app.get("/admin/dump_cache")
@admin_level_required(2)
@admin_level_required(PERMS['SITE_CACHE_DUMP_INTERNAL'])
def admin_dump_cache(v):
online = cache.get(ONLINE_STR)
cache.clear()
@ -1405,7 +1406,7 @@ def admin_dump_cache(v):
@app.get("/admin/banned_domains/")
@admin_level_required(3)
@admin_level_required(PERMS['DOMAINS_BAN'])
def admin_banned_domains(v):
banned_domains = g.db.query(BannedDomain).all()
@ -1413,7 +1414,7 @@ def admin_banned_domains(v):
@app.post("/admin/banned_domains")
@limiter.limit("1/second;30/minute;200/hour;1000/day")
@admin_level_required(3)
@admin_level_required(PERMS['DOMAINS_BAN'])
def admin_toggle_ban_domain(v):
domain=request.values.get("domain", "").strip()
@ -1446,7 +1447,7 @@ def admin_toggle_ban_domain(v):
@app.post("/admin/nuke_user")
@limiter.limit("1/second;30/minute;200/hour;1000/day")
@admin_level_required(2)
@admin_level_required(PERMS['POST_COMMENT_MODERATION'])
def admin_nuke_user(v):
user=get_user(request.values.get("user"))
@ -1479,7 +1480,7 @@ def admin_nuke_user(v):
@app.post("/admin/unnuke_user")
@limiter.limit("1/second;30/minute;200/hour;1000/day")
@admin_level_required(2)
@admin_level_required(PERMS['POST_COMMENT_MODERATION'])
def admin_nunuke_user(v):
user=get_user(request.values.get("user"))

View File

@ -22,7 +22,7 @@ def asset_submissions(path):
@app.get("/submit/marseys")
@auth_required
def submit_marseys(v):
if v.admin_level > 2:
if v.admin_level >= PERMS['VIEW_PENDING_SUBMITTED_MARSEYS']:
marseys = g.db.query(Marsey).filter(Marsey.submitter_id != None).all()
else:
marseys = g.db.query(Marsey).filter(Marsey.submitter_id == v.id).all()
@ -44,7 +44,7 @@ def submit_marsey(v):
username = request.values.get('author').lower().strip()
def error(error):
if v.admin_level > 2: marseys = g.db.query(Marsey).filter(Marsey.submitter_id != None).all()
if v.admin_level >= PERMS['VIEW_PENDING_SUBMITTED_MARSEYS']: marseys = g.db.query(Marsey).filter(Marsey.submitter_id != None).all()
else: marseys = g.db.query(Marsey).filter(Marsey.submitter_id == v.id).all()
for marsey in marseys:
marsey.author = g.db.query(User.username).filter_by(id=marsey.author_id).one()[0]
@ -82,7 +82,7 @@ def submit_marsey(v):
g.db.add(marsey)
g.db.flush()
if v.admin_level > 2: marseys = g.db.query(Marsey).filter(Marsey.submitter_id != None).all()
if v.admin_level >= PERMS['VIEW_PENDING_SUBMITTED_MARSEYS']: marseys = g.db.query(Marsey).filter(Marsey.submitter_id != None).all()
else: marseys = g.db.query(Marsey).filter(Marsey.submitter_id == v.id).all()
for marsey in marseys:
marsey.author = g.db.query(User.username).filter_by(id=marsey.author_id).one()[0]
@ -92,7 +92,7 @@ def submit_marsey(v):
@app.post("/admin/approve/marsey/<name>")
@admin_level_required(3)
@admin_level_required(PERMS['MODERATE_PENDING_SUBMITTED_MARSEYS'])
def approve_marsey(v, name):
if AEVANN_ID and v.id not in (AEVANN_ID, CARP_ID, SNAKES_ID):
return {"error": "Only Carp can approve marseys!"}, 403
@ -186,7 +186,7 @@ def remove_marsey(v, name):
@app.get("/submit/hats")
@auth_required
def submit_hats(v):
if v.admin_level > 2: hats = g.db.query(HatDef).filter(HatDef.submitter_id != None).all()
if v.admin_level >= PERMS['VIEW_PENDING_SUBMITTED_HATS']: hats = g.db.query(HatDef).filter(HatDef.submitter_id != None).all()
else: hats = g.db.query(HatDef).filter(HatDef.submitter_id == v.id).all()
return render_template("submit_hats.html", v=v, hats=hats)
@ -200,7 +200,7 @@ def submit_hat(v):
username = request.values.get('author').strip()
def error(error):
if v.admin_level > 2: hats = g.db.query(HatDef).filter(HatDef.submitter_id != None).all()
if v.admin_level >= PERMS['VIEW_PENDING_SUBMITTED_HATS']: hats = g.db.query(HatDef).filter(HatDef.submitter_id != None).all()
else: hats = g.db.query(HatDef).filter(HatDef.submitter_id == v.id).all()
return render_template("submit_hats.html", v=v, hats=hats, error=error, name=name, description=description, username=username), 400
@ -245,13 +245,13 @@ def submit_hat(v):
g.db.commit()
if v.admin_level > 2: hats = g.db.query(HatDef).filter(HatDef.submitter_id != None).all()
if v.admin_level >= PERMS['VIEW_PENDING_SUBMITTED_HATS']: hats = g.db.query(HatDef).filter(HatDef.submitter_id != None).all()
else: hats = g.db.query(HatDef).filter(HatDef.submitter_id == v.id).all()
return render_template("submit_hats.html", v=v, hats=hats, msg=f"'{name}' submitted successfully!")
@app.post("/admin/approve/hat/<name>")
@admin_level_required(3)
@admin_level_required(PERMS['MODERATE_PENDING_SUBMITTED_HATS'])
def approve_hat(v, name):
if AEVANN_ID and v.id not in (AEVANN_ID, CARP_ID, SNAKES_ID):
return {"error": "Only Carp can approve hats!"}, 403
@ -345,7 +345,7 @@ def remove_hat(v, name):
@app.get("/admin/update/marseys")
@admin_level_required(3)
@admin_level_required(PERMS['UPDATE_MARSEYS'])
def update_marseys(v):
if AEVANN_ID and v.id not in (AEVANN_ID, CARP_ID, GEESE_ID, SNAKES_ID):
abort(403)
@ -354,7 +354,7 @@ def update_marseys(v):
@app.post("/admin/update/marseys")
@admin_level_required(3)
@admin_level_required(PERMS['UPDATE_MARSEYS'])
def update_marsey(v):
if AEVANN_ID and v.id not in (AEVANN_ID, CARP_ID, GEESE_ID, SNAKES_ID):
abort(403)
@ -408,7 +408,7 @@ def update_marsey(v):
@app.get("/admin/update/hats")
@admin_level_required(3)
@admin_level_required(PERMS['UPDATE_HATS'])
def update_hats(v):
if AEVANN_ID and v.id not in (AEVANN_ID, CARP_ID, GEESE_ID, SNAKES_ID):
abort(403)
@ -417,7 +417,7 @@ def update_hats(v):
@app.post("/admin/update/hats")
@admin_level_required(3)
@admin_level_required(PERMS['UPDATE_HATS'])
def update_hat(v):
if AEVANN_ID and v.id not in (AEVANN_ID, CARP_ID, GEESE_ID, SNAKES_ID):
abort(403)

View File

@ -51,7 +51,7 @@ def buy(v, award):
if award == 'benefactor' and not request.values.get("mb"):
return {"error": "You can only buy the Benefactor award with marseybux."}, 403
if award == 'ghost' and v.admin_level < 2:
if award == 'ghost' and v.admin_level < PERMS['BUY_GHOST_AWARD']:
return {"error": "Only admins can buy this award."}, 403
AWARDS = deepcopy(AWARDS2)
@ -212,7 +212,7 @@ def award_thing(v, thing_type, id):
author.unban_utc += 86400
send_repeatable_notification(author.id, f"Your account has been banned for **yet another day** for {link}. Seriously man?")
if v.admin_level > 2:
if v.admin_level >= PERMS['USER_BAN']:
log_link = f'/{thing_type}/{thing.id}'
reason = f'<a href="{log_link}">{log_link}</a>'
@ -236,7 +236,7 @@ def award_thing(v, thing_type, id):
author.ban_reason = None
send_repeatable_notification(author.id, "You have been unbanned!")
if v.admin_level > 2:
if v.admin_level >= PERMS['USER_BAN']:
ma=ModAction(
kind="unban_user",
user_id=v.id,
@ -249,7 +249,7 @@ def award_thing(v, thing_type, id):
author.unban_utc = int(time.time()) + 30 * 86400
send_repeatable_notification(author.id, f"Your account has been banned permanently for {link}. You must [provide the admins](/contact) a timestamped picture of you touching grass/snow/sand/ass to get unbanned!")
if v.admin_level > 2:
if v.admin_level >= PERMS['USER_BAN']:
log_link = f'/{thing_type}/{thing.id}'
reason = f'<a href="{log_link}">{log_link}</a>'
@ -297,7 +297,7 @@ def award_thing(v, thing_type, id):
badge_grant(user=author, badge_id=28)
if v.admin_level > 2:
if v.admin_level >= PERMS['USER_AGENDAPOSTER']:
ma = ModAction(
kind="agendaposter",
user_id=v.id,

View File

@ -97,7 +97,7 @@ def speak(data, v):
total += 1
if v.admin_level > 1:
if v.admin_level >= PERMS['USER_BAN']:
text = text.lower()
for i in mute_regex.finditer(text):
username = i.group(1).lower()
@ -153,7 +153,7 @@ def typing_indicator(data, v):
@socketio.on('delete')
@admin_level_required(2)
@admin_level_required(PERMS['POST_COMMENT_MODERATION'])
def delete(text, v):
for message in messages:

View File

@ -41,7 +41,7 @@ def post_pid_comment_cid(cid, pid=None, anything=None, v=None, sub=None):
if not comment.can_see(v): abort(403)
if comment.author.shadowbanned and not (v and v.shadowbanned) and not (v and v.admin_level >= 2):
if comment.author.shadowbanned and not (v and v.shadowbanned) and not (v and v.admin_level >= PERMS['USER_SHADOWBAN']):
abort(404)
if v and request.values.get("read"):
@ -52,7 +52,7 @@ def post_pid_comment_cid(cid, pid=None, anything=None, v=None, sub=None):
if comment.post and comment.post.club and not (v and (v.paid_dues or v.id in [comment.author_id, comment.post.author_id])): abort(403)
if not comment.parent_submission and not (v and (comment.author.id == v.id or comment.sentto == v.id)) and not (v and v.admin_level > 1) : abort(403)
if not comment.parent_submission and not (v and (comment.author.id == v.id or comment.sentto == v.id)) and not (v and v.admin_level >= PERMS['POST_COMMENT_MODERATION']) : abort(403)
if not pid:
if comment.parent_submission: pid = comment.parent_submission
@ -96,7 +96,7 @@ def post_pid_comment_cid(cid, pid=None, anything=None, v=None, sub=None):
blocked.c.target_id,
)
if not (v and v.shadowbanned) and not (v and v.admin_level >= 2):
if not (v and v.shadowbanned) and not (v and v.admin_level >= PERMS['USER_SHADOWBAN']):
comments = comments.join(Comment.author).filter(User.shadowbanned == None)
comments=comments.filter(
@ -127,7 +127,7 @@ def post_pid_comment_cid(cid, pid=None, anything=None, v=None, sub=None):
if request.headers.get("Authorization"): return top_comment.json
else:
if post.is_banned and not (v and (v.admin_level > 1 or post.author_id == v.id)): template = "submission_banned.html"
if post.is_banned and not (v and (v.admin_level >= PERMS['POST_COMMENT_MODERATION'] or post.author_id == v.id)): template = "submission_banned.html"
else: template = "submission.html"
return render_template(template, v=v, p=post, sort=sort, comment_info=comment_info, render_replies=True, sub=post.subr)
@ -156,7 +156,7 @@ def comment(v):
parent_comment_id = None
level = 1
if POLL_THREAD and parent.id == POLL_THREAD and v.admin_level < 2: abort(403)
if POLL_THREAD and parent.id == POLL_THREAD and v.admin_level < PERMS['POST_TO_POLL_THREAD']: abort(403)
elif parent_fullname.startswith("c_"):
parent = get_comment(parent_fullname.split("_")[1], v=v)
parent_comment_id = parent.id
@ -196,7 +196,7 @@ def comment(v):
file.save(oldname)
image = process_image(oldname, patron=v.patron)
if image == "": return {"error":"Image upload failed"}, 400
if v.admin_level > 2 and level == 1:
if v.admin_level >= PERMS['SITE_SETTINGS_SIDEBARS_BANNERS_BADGES'] and level == 1:
if parent_post.id == SIDEBAR_THREAD:
li = sorted(os.listdir(f'files/assets/images/{SITE_NAME}/sidebar'),
key=lambda e: int(e.split('.webp')[0]))[-1]
@ -239,7 +239,7 @@ def comment(v):
body = body.strip()
if v.admin_level > 2 and parent_post.id == SNAPPY_THREAD and level == 1:
if v.admin_level >= PERMS['SITE_SETTINGS_SNAPPY_QUOTES'] and parent_post.id == SNAPPY_THREAD and level == 1:
with open(f"snappy_{SITE_NAME}.txt", "a", encoding="utf-8") as f:
f.write('\n{[para]}\n' + body)
@ -263,7 +263,7 @@ def comment(v):
).first()
if existing: return {"error": f"You already made that comment: /comment/{existing.id}"}, 409
if parent.author.any_block_exists(v) and v.admin_level < 2:
if parent.author.any_block_exists(v) and v.admin_level < PERMS['POST_COMMENT_MODERATION']:
return {"error": "You can't reply to users who have blocked you, or users you have blocked."}, 403
is_bot = v.id != 12125 and (bool(request.headers.get("Authorization")) or (SITE == 'pcmemes.net' and v.id == SNAPPY_ID))
@ -914,7 +914,7 @@ def handle_wordle_action(cid, v):
def toggle_comment_nsfw(cid, v):
comment = get_comment(cid)
if comment.author_id != v.id and not v.admin_level > 1 and not (comment.post.sub and v.mods(comment.post.sub)):
if comment.author_id != v.id and not v.admin_level >= PERMS['POST_COMMENT_MODERATION'] and not (comment.post.sub and v.mods(comment.post.sub)):
abort(403)
if comment.over_18 and v.is_suspended_permanently:
@ -924,7 +924,7 @@ def toggle_comment_nsfw(cid, v):
g.db.add(comment)
if comment.author_id != v.id:
if v.admin_level > 2:
if v.admin_level >= PERMS['POST_COMMENT_MODERATION']:
ma = ModAction(
kind = "set_nsfw_comment" if comment.over_18 else "unset_nsfw_comment",
user_id = v.id,

View File

@ -239,7 +239,7 @@ def comment_idlist(page=1, v=None, nsfw=False, sort="new", t="all", gt=0, lt=0,
comments = g.db.query(Comment.id).filter(Comment.parent_submission != None, Comment.author_id.notin_(v.userblocks))
if v.admin_level < 2:
if v.admin_level < PERMS['POST_COMMENT_MODERATION']:
private = [x[0] for x in g.db.query(Submission.id).filter(Submission.private == True).all()]
comments = comments.filter(Comment.is_banned==False, Comment.deleted_utc == 0, Comment.parent_submission.notin_(private))

View File

@ -8,7 +8,7 @@ from files.helpers.lottery import *
import requests
@app.post("/lottery/end")
@admin_level_required(3)
@admin_level_required(PERMS['LOTTERY_ADMIN'])
@casino_required
def lottery_end(v):
success, message = end_lottery_session()
@ -16,7 +16,7 @@ def lottery_end(v):
@app.post("/lottery/start")
@admin_level_required(3)
@admin_level_required(PERMS['LOTTERY_ADMIN'])
@casino_required
def lottery_start(v):
start_new_lottery_session()
@ -51,7 +51,7 @@ def lottery_active(v):
return {"message": "", "stats": {"user": v.lottery_stats, "lottery": lottery, "participants": participants}}
@app.get("/admin/lottery/participants")
@admin_level_required(2)
@admin_level_required(PERMS['LOTTERY_VIEW_PARTICIPANTS'])
@casino_required
def lottery_admin(v):
participants = get_users_participating_in_lottery()

View File

@ -36,7 +36,7 @@ def unread(v):
@app.get("/notifications/modmail")
@admin_level_required(2)
@admin_level_required(PERMS['VIEW_MODMAIL'])
def notifications_modmail(v):
try: page = max(int(request.values.get("page", 1)), 1)
except: page = 1
@ -75,7 +75,7 @@ def notifications_messages(v):
Comment.parent_submission == None,
Comment.level == 1,
)
if not v.shadowbanned and v.admin_level < 3:
if not v.shadowbanned and v.admin_level < PERMS['NOTIFICATIONS_FROM_SHADOWBANNED_USERS']:
message_threads = message_threads.join(Comment.author) \
.filter(User.shadowbanned == None)
@ -258,7 +258,7 @@ def notifications(v):
or_(Comment.sentto == None, Comment.sentto == 2),
).order_by(Notification.created_utc.desc())
if not (v and (v.shadowbanned or v.admin_level > 2)):
if not (v and (v.shadowbanned or v.admin_level >= PERMS['NOTIFICATIONS_FROM_SHADOWBANNED_USERS'])):
comments = comments.join(Comment.author).filter(User.shadowbanned == None)
comments = comments.offset(25 * (page - 1)).limit(26).all()

View File

@ -83,7 +83,7 @@ def request_api_keys(v):
new_comment.top_comment_id = new_comment.id
for admin in g.db.query(User).filter(User.admin_level > 2).all():
for admin in g.db.query(User).filter(User.admin_level >= PERMS['APPS_MODERATION']).all():
notif = Notification(comment_id=new_comment.id, user_id=admin.id)
g.db.add(notif)
@ -137,7 +137,7 @@ def edit_oauth_app(v, aid):
@app.post("/admin/app/approve/<aid>")
@limiter.limit("1/second;30/minute;200/hour;1000/day")
@admin_level_required(3)
@admin_level_required(PERMS['APPS_MODERATION'])
def admin_app_approve(v, aid):
app = g.db.get(OauthApp, aid)
@ -173,7 +173,7 @@ def admin_app_approve(v, aid):
@app.post("/admin/app/revoke/<aid>")
@limiter.limit("1/second;30/minute;200/hour;1000/day")
@admin_level_required(3)
@admin_level_required(PERMS['APPS_MODERATION'])
def admin_app_revoke(v, aid):
app = g.db.get(OauthApp, aid)
@ -198,7 +198,7 @@ def admin_app_revoke(v, aid):
@app.post("/admin/app/reject/<aid>")
@limiter.limit("1/second;30/minute;200/hour;1000/day")
@admin_level_required(3)
@admin_level_required(PERMS['APPS_MODERATION'])
def admin_app_reject(v, aid):
app = g.db.get(OauthApp, aid)
@ -223,7 +223,7 @@ def admin_app_reject(v, aid):
@app.get("/admin/app/<aid>")
@admin_level_required(3)
@admin_level_required(PERMS['APPS_MODERATION'])
def admin_app_id(v, aid):
aid=aid
oauth = g.db.get(OauthApp, aid)
@ -244,7 +244,7 @@ def admin_app_id(v, aid):
)
@app.get("/admin/app/<aid>/comments")
@admin_level_required(3)
@admin_level_required(PERMS['APPS_MODERATION'])
def admin_app_id_comments(v, aid):
aid=aid
@ -271,7 +271,7 @@ def admin_app_id_comments(v, aid):
@app.get("/admin/apps")
@admin_level_required(3)
@admin_level_required(PERMS['APPS_MODERATION'])
def admin_apps_list(v):
apps = g.db.query(OauthApp).order_by(OauthApp.id.desc()).all()

View File

@ -35,7 +35,7 @@ def club_post(pid, v):
abort(403)
post = get_post(pid)
if post.author_id != v.id and v.admin_level < 2: abort(403)
if post.author_id != v.id and v.admin_level < PERMS['POST_COMMENT_MODERATION']: abort(403)
if not post.club:
post.club = True
@ -106,8 +106,7 @@ def publish(pid, v):
cache.delete_memoized(frontlist)
cache.delete_memoized(User.userpagelisting)
if (v.admin_level > 0 or v.has_badge(3)) and post.sub == 'changelog':
send_changelog_message(post.permalink)
send_changelog_message(post.permalink)
if SITE == 'watchpeopledie.co':
send_wpd_message(post.permalink)
@ -168,7 +167,7 @@ def post_id(pid, anything=None, v=None, sub=None):
blocked.c.target_id,
)
if not (v and v.shadowbanned) and not (v and v.admin_level >= 2):
if not (v and v.shadowbanned) and not (v and v.admin_level >= PERMS['USER_SHADOWBAN']):
comments = comments.join(Comment.author).filter(User.shadowbanned == None)
comments=comments.filter(Comment.parent_submission == post.id, Comment.level < 10).join(
@ -258,7 +257,7 @@ def post_id(pid, anything=None, v=None, sub=None):
template = "submission.html"
if (post.is_banned or post.author.shadowbanned) \
and not (v and (v.admin_level >= 2 or post.author_id == v.id)):
and not (v and (v.admin_level >= PERMS['POST_COMMENT_MODERATION'] or post.author_id == v.id)):
template = "submission_banned.html"
return render_template(template, v=v, p=post, ids=list(ids),
@ -290,7 +289,7 @@ def viewmore(v, pid, sort, offset):
blocked.c.target_id,
).filter(Comment.parent_submission == pid, Comment.stickied == None, Comment.id.notin_(ids), Comment.level < 10)
if not (v and v.shadowbanned) and not (v and v.admin_level >= 2):
if not (v and v.shadowbanned) and not (v and v.admin_level >= PERMS['USER_SHADOWBAN']):
comments = comments.join(Comment.author).filter(User.shadowbanned == None)
comments=comments.join(
@ -409,14 +408,13 @@ def morecomments(v, cid):
@auth_required
def edit_post(pid, v):
p = get_post(pid)
if v.id != p.author_id and v.admin_level < PERMS['POST_EDITING']:
abort(403)
title = sanitize_raw_title(request.values.get("title", ""))
body = sanitize_raw_body(request.values.get("body", ""))
if v.id != p.author_id and v.admin_level < 2:
abort(403)
if v.id == p.author_id:
if v.longpost and (len(body) < 280 or ' [](' in body or body.startswith('[](')):
return {"error":"You have to type more than 280 characters!"}, 403
@ -717,8 +715,9 @@ def submit_post(v, sub=None):
sub = request.values.get("sub", "").lower().replace('/h/','').strip()
if sub == 'changelog':
allowed = g.db.query(User.id).filter(User.admin_level > 0).all() + g.db.query(Badge.user_id).filter_by(badge_id=3).all()
if sub == 'changelog' and not v.admin_level >= PERMS['POST_TO_CHANGELOG']:
# we also allow 'code contributor' badgeholders to post to the changelog hole
allowed = g.db.query(Badge.user_id).filter_by(badge_id=3).all()
allowed = [x[0] for x in allowed]
if v.id not in allowed: return error(f"You don't have sufficient permissions to post in /h/changelog")
@ -876,7 +875,7 @@ def submit_post(v, sub=None):
if len(url) > 2048:
return error("There's a 2048 character limit for URLs.")
if v and v.admin_level > 2:
if v and v.admin_level >= PERMS['POST_BETS']:
bets = []
for i in bet_regex.finditer(body):
bets.append(i.group(1))
@ -963,7 +962,7 @@ def submit_post(v, sub=None):
)
g.db.add(choice)
if v and v.admin_level > 2:
if v and v.admin_level >= PERMS['POST_BETS']:
for bet in bets:
bet = SubmissionOption(
submission_id=post.id,
@ -1067,7 +1066,7 @@ def submit_post(v, sub=None):
cache.delete_memoized(frontlist)
cache.delete_memoized(User.userpagelisting)
if (v.admin_level > 0 or v.has_badge(3)) and post.sub == 'changelog' and not post.private:
if post.sub == 'changelog' and not post.private:
send_changelog_message(post.permalink)
if not post.private and SITE == 'watchpeopledie.co':
@ -1133,7 +1132,7 @@ def undelete_post_pid(pid, v):
def toggle_post_nsfw(pid, v):
post = get_post(pid)
if post.author_id != v.id and not v.admin_level > 1 and not (post.sub and v.mods(post.sub)):
if post.author_id != v.id and not v.admin_level >= PERMS['POST_COMMENT_MODERATION'] and not (post.sub and v.mods(post.sub)):
abort(403)
if post.over_18 and v.is_suspended_permanently:
@ -1143,7 +1142,7 @@ def toggle_post_nsfw(pid, v):
g.db.add(post)
if post.author_id != v.id:
if v.admin_level > 2:
if v.admin_level >= PERMS['POST_COMMENT_MODERATION']:
ma = ModAction(
kind = "set_nsfw" if post.over_18 else "unset_nsfw",
user_id = v.id,

View File

@ -30,10 +30,10 @@ def flag_post(pid, v):
if len(reason) > 350: return {"error": "Too long."}, 400
if reason.startswith('!') and (v.admin_level > 1 or post.sub and v.mods(post.sub)):
if reason.startswith('!') and (v.admin_level >= PERMS['POST_COMMENT_MODERATION'] or post.sub and v.mods(post.sub)):
post.flair = reason[1:]
g.db.add(post)
if v.admin_level > 1:
if v.admin_level >= PERMS['POST_COMMENT_MODERATION']:
ma=ModAction(
kind="flair_post",
user_id=v.id,
@ -51,7 +51,7 @@ def flag_post(pid, v):
)
g.db.add(ma)
elif reason.startswith('/h/') and (v.admin_level >= 2 or v.id == post.author_id or (reason == '/h/chudrama' and v.mods(post.sub))):
elif reason.startswith('/h/') and (v.admin_level >= PERMS['POST_COMMENT_MODERATION'] or v.id == post.author_id or (reason == '/h/chudrama' and v.mods(post.sub))):
sub_from = post.sub
sub_to = reason[3:].strip().lower()
@ -95,7 +95,7 @@ def flag_post(pid, v):
g.db.add(ma)
if v.id != post.author_id:
if v.admin_level >= 3: position = 'Admin'
if v.admin_level >= PERMS['POST_COMMENT_MODERATION']: position = 'Admin'
else: position = 'Mod'
message = f"@{v.username} ({position}) has moved [{post.title}]({post.shortlink}) to /h/{post.sub}"
send_repeatable_notification(post.author_id, message)

View File

@ -61,17 +61,19 @@ def searchposts(v):
if not v.paid_dues:
posts = posts.filter(Submission.club == False)
if v.admin_level < 2:
if v.admin_level < PERMS['POST_COMMENT_MODERATION']:
posts = posts.filter(
Submission.deleted_utc == 0,
Submission.is_banned == False,
Submission.private == False,
User.shadowbanned == None)
Submission.private == False)
if v.admin_level < PERMS['USER_SHADOWBAN']:
posts = posts.filter(User.shadowbanned == None)
if 'author' in criteria:
posts = posts.filter(Submission.ghost == False)
author = get_user(criteria['author'], v=v, include_shadowbanned=False)
if author.is_private and author.id != v.id and v.admin_level < 2 and not v.eye:
if author.is_private and author.id != v.id and v.admin_level < PERMS['VIEW_PRIVATE_PROFILES'] and not v.eye:
if request.headers.get("Authorization"):
return {"error": f"@{author.username}'s profile is private; You can't use the 'author' syntax on them"}, 400
return render_template("search.html",
@ -198,7 +200,7 @@ def searchcomments(v):
if 'author' in criteria:
comments = comments.filter(Comment.ghost == False)
author = get_user(criteria['author'], v=v, include_shadowbanned=False)
if author.is_private and author.id != v.id and v.admin_level < 2 and not v.eye:
if author.is_private and author.id != v.id and v.admin_level < PERMS['VIEW_PRIVATE_PROFILES'] and not v.eye:
if request.headers.get("Authorization"):
return {"error": f"@{author.username}'s profile is private; You can't use the 'author' syntax on them"}, 400
@ -220,7 +222,7 @@ def searchcomments(v):
comments = apply_time_filter(t, comments, Comment)
if v.admin_level < 2:
if v.admin_level < PERMS['POST_COMMENT_MODERATION']:
private = [x[0] for x in g.db.query(Submission.id).filter(Submission.private == True).all()]
comments = comments.filter(Comment.is_banned==False, Comment.deleted_utc == 0, Comment.parent_submission.notin_(private))
@ -282,7 +284,7 @@ def searchusers(v):
)
)
if v.admin_level < 2:
if v.admin_level < PERMS['USER_SHADOWBAN']:
users = users.filter(User.shadowbanned == None)
users=users.order_by(User.username.ilike(term).desc(), User.stored_subscriber_count.desc())

View File

@ -104,7 +104,7 @@ def daily_chart(v):
@app.get("/patrons")
@app.get("/paypigs")
@admin_level_required(3)
@admin_level_required(PERMS['VIEW_PATRONS'])
def patrons(v):
if AEVANN_ID and v.id not in (AEVANN_ID, CARP_ID, SNAKES_ID): abort(404)
@ -116,7 +116,7 @@ def patrons(v):
@app.get("/badmins")
@auth_required
def admins(v):
if v and v.admin_level > 2:
if v.admin_level >= PERMS['VIEW_SORTED_ADMIN_LIST']:
admins = g.db.query(User).filter(User.admin_level>1).order_by(User.truecoins.desc()).all()
admins += g.db.query(User).filter(User.admin_level==1).order_by(User.truecoins.desc()).all()
else: admins = g.db.query(User).filter(User.admin_level>0).order_by(User.truecoins.desc()).all()
@ -137,7 +137,7 @@ def log(v):
kind = request.values.get("kind")
if v and v.admin_level > 1: types = ACTIONTYPES
if v and v.admin_level >= PERMS['USER_SHADOWBAN']: types = ACTIONTYPES
else: types = ACTIONTYPES2
if kind and kind not in types:
@ -145,7 +145,7 @@ def log(v):
actions = []
else:
actions = g.db.query(ModAction)
if not (v and v.admin_level >= 2):
if not (v and v.admin_level >= PERMS['USER_SHADOWBAN']):
actions = actions.filter(ModAction.kind.notin_(["shadowban","unshadowban"]))
if admin_id:
@ -162,7 +162,7 @@ def log(v):
next_exists=len(actions)>25
actions=actions[:25]
admins = [x[0] for x in g.db.query(User.username).filter(User.admin_level >= 2).order_by(User.username).all()]
admins = [x[0] for x in g.db.query(User.username).filter(User.admin_level >= PERMS['ADMIN_MOP_VISIBLE']).order_by(User.username).all()]
return render_template("log.html", v=v, admins=admins, types=types, admin=admin, type=kind, actions=actions, next_exists=next_exists, page=page)
@ -177,9 +177,9 @@ def log_item(id, v):
if not action: abort(404)
admins = [x[0] for x in g.db.query(User.username).filter(User.admin_level > 1).all()]
admins = [x[0] for x in g.db.query(User.username).filter(User.admin_level >= PERMS['ADMIN_MOP_VISIBLE']).all()]
if v and v.admin_level > 1: types = ACTIONTYPES
if v and v.admin_level >= PERMS['USER_SHADOWBAN']: types = ACTIONTYPES
else: types = ACTIONTYPES2
return render_template("log.html", v=v, actions=[action], next_exists=False, page=1, action=action, admins=admins, types=types)
@ -232,7 +232,7 @@ def submit_contact(v):
g.db.flush()
new_comment.top_comment_id = new_comment.id
admins = g.db.query(User).filter(User.admin_level > 2)
admins = g.db.query(User).filter(User.admin_level >= PERMS['NOTIFICATIONS_MODMAIL'])
if SITE == 'watchpeopledie.co':
admins = admins.filter(User.id != AEVANN_ID)
@ -556,7 +556,7 @@ if SITE == 'pcmemes.net':
return render_template('live.html', v=v, live=live, offline=offline)
@app.post('/live/add')
@admin_level_required(2)
@admin_level_required(PERMS['STREAMERS_MODERATION'])
def live_add(v):
link = request.values.get('link').strip()
@ -595,7 +595,7 @@ if SITE == 'pcmemes.net':
return redirect('/live')
@app.post('/live/remove')
@admin_level_required(2)
@admin_level_required(PERMS['STREAMERS_MODERATION'])
def live_remove(v):
id = request.values.get('id').strip()
if not id: abort(400)

View File

@ -345,7 +345,7 @@ def create_sub2(v):
mod = Mod(user_id=v.id, sub=sub.name)
g.db.add(mod)
admins = [x[0] for x in g.db.query(User.id).filter(User.admin_level > 1, User.id != v.id).all()]
admins = [x[0] for x in g.db.query(User.id).filter(User.admin_level >= PERMS['NOTIFICATIONS_HOLE_CREATION'], User.id != v.id).all()]
for admin in admins:
send_repeatable_notification(admin, f":!marseyparty: /h/{sub} has been created by @{v.username} :marseyparty:")
@ -366,7 +366,7 @@ def kick(v, pid):
old = post.sub
post.sub = None
if v.admin_level >= 3 and v.id != post.author_id:
if v.admin_level >= PERMS['GLOBAL_MODERATION'] and v.id != post.author_id:
old_str = f'<a href="/h/{old}">/h/{old}</a>'
ma = ModAction(
kind='move_hole',
@ -385,7 +385,7 @@ def kick(v, pid):
g.db.add(ma)
if v.id != post.author_id:
if v.admin_level >= 3: position = 'Admin'
if v.admin_level >= PERMS['GLOBAL_MODERATION']: position = 'Admin'
else: position = 'Mod'
message = f"@{v.username} ({position}) has moved [{post.title}]({post.shortlink}) from /h/{old} to the main feed!"
send_repeatable_notification(post.author_id, message)

View File

@ -26,7 +26,7 @@ from .login import check_for_alts
@auth_required
def upvoters_posts(v, username, uid):
u = get_user(username, v=v, include_shadowbanned=False)
if u.is_private and (not v or (v.id != u.id and v.admin_level < 2 and not v.eye)): abort(403)
if u.is_private and (not v or (v.id != u.id and v.admin_level < PERMS['VIEW_PRIVATE_PROFILES'] and not v.eye)): abort(403)
if not (v.id == u.id or v.admin_level >= PERMS['USER_VOTERS_VISIBLE']): abort(403)
id = u.id
uid = int(uid)
@ -48,7 +48,7 @@ def upvoters_posts(v, username, uid):
@auth_required
def upvoters_comments(v, username, uid):
u = get_user(username, v=v, include_shadowbanned=False)
if u.is_private and (not v or (v.id != u.id and v.admin_level < 2 and not v.eye)): abort(403)
if u.is_private and (not v or (v.id != u.id and v.admin_level < PERMS['VIEW_PRIVATE_PROFILES'] and not v.eye)): abort(403)
if not (v.id == u.id or v.admin_level >= PERMS['USER_VOTERS_VISIBLE']): abort(403)
id = u.id
uid = int(uid)
@ -70,7 +70,7 @@ def upvoters_comments(v, username, uid):
@auth_required
def downvoters_posts(v, username, uid):
u = get_user(username, v=v, include_shadowbanned=False)
if u.is_private and (not v or (v.id != u.id and v.admin_level < 2 and not v.eye)): abort(403)
if u.is_private and (not v or (v.id != u.id and v.admin_level < PERMS['VIEW_PRIVATE_PROFILES'] and not v.eye)): abort(403)
if not (v.id == u.id or v.admin_level >= PERMS['USER_VOTERS_VISIBLE']): abort(403)
id = u.id
uid = int(uid)
@ -92,7 +92,7 @@ def downvoters_posts(v, username, uid):
@auth_required
def downvoters_comments(v, username, uid):
u = get_user(username, v=v, include_shadowbanned=False)
if u.is_private and (not v or (v.id != u.id and v.admin_level < 2 and not v.eye)): abort(403)
if u.is_private and (not v or (v.id != u.id and v.admin_level < PERMS['VIEW_PRIVATE_PROFILES'] and not v.eye)): abort(403)
if not (v.id == u.id or v.admin_level >= PERMS['USER_VOTERS_VISIBLE']): abort(403)
id = u.id
uid = int(uid)
@ -117,7 +117,7 @@ def downvoters_comments(v, username, uid):
@auth_required
def upvoting_posts(v, username, uid):
u = get_user(username, v=v, include_shadowbanned=False)
if u.is_private and (not v or (v.id != u.id and v.admin_level < 2 and not v.eye)): abort(403)
if u.is_private and (not v or (v.id != u.id and v.admin_level < PERMS['VIEW_PRIVATE_PROFILES'] and not v.eye)): abort(403)
if not (v.id == u.id or v.admin_level >= PERMS['USER_VOTERS_VISIBLE']): abort(403)
id = u.id
uid = int(uid)
@ -139,7 +139,7 @@ def upvoting_posts(v, username, uid):
@auth_required
def upvoting_comments(v, username, uid):
u = get_user(username, v=v, include_shadowbanned=False)
if u.is_private and (not v or (v.id != u.id and v.admin_level < 2 and not v.eye)): abort(403)
if u.is_private and (not v or (v.id != u.id and v.admin_level < PERMS['VIEW_PRIVATE_PROFILES'] and not v.eye)): abort(403)
if not (v.id == u.id or v.admin_level >= PERMS['USER_VOTERS_VISIBLE']): abort(403)
id = u.id
uid = int(uid)
@ -161,7 +161,7 @@ def upvoting_comments(v, username, uid):
@auth_required
def downvoting_posts(v, username, uid):
u = get_user(username, v=v, include_shadowbanned=False)
if u.is_private and (not v or (v.id != u.id and v.admin_level < 2 and not v.eye)): abort(403)
if u.is_private and (not v or (v.id != u.id and v.admin_level < PERMS['VIEW_PRIVATE_PROFILES'] and not v.eye)): abort(403)
if not (v.id == u.id or v.admin_level >= PERMS['USER_VOTERS_VISIBLE']): abort(403)
id = u.id
uid = int(uid)
@ -183,7 +183,7 @@ def downvoting_posts(v, username, uid):
@auth_required
def downvoting_comments(v, username, uid):
u = get_user(username, v=v, include_shadowbanned=False)
if u.is_private and (not v or (v.id != u.id and v.admin_level < 2 and not v.eye)): abort(403)
if u.is_private and (not v or (v.id != u.id and v.admin_level < PERMS['VIEW_PRIVATE_PROFILES'] and not v.eye)): abort(403)
if not (v.id == u.id or v.admin_level >= PERMS['USER_VOTERS_VISIBLE']): abort(403)
id = u.id
uid = int(uid)
@ -205,7 +205,7 @@ def downvoting_comments(v, username, uid):
@auth_required
def user_upvoted_posts(v, username):
u = get_user(username, v=v, include_shadowbanned=False)
if u.is_private and (not v or (v.id != u.id and v.admin_level < 2 and not v.eye)): abort(403)
if u.is_private and (not v or (v.id != u.id and v.admin_level < PERMS['VIEW_PRIVATE_PROFILES'] and not v.eye)): abort(403)
if not (v.id == u.id or v.admin_level >= PERMS['USER_VOTERS_VISIBLE']): abort(403)
page = max(1, int(request.values.get("page", 1)))
@ -231,7 +231,7 @@ def user_upvoted_posts(v, username):
@auth_required
def user_upvoted_comments(v, username):
u = get_user(username, v=v, include_shadowbanned=False)
if u.is_private and (not v or (v.id != u.id and v.admin_level < 2 and not v.eye)): abort(403)
if u.is_private and (not v or (v.id != u.id and v.admin_level < PERMS['VIEW_PRIVATE_PROFILES'] and not v.eye)): abort(403)
if not (v.id == u.id or v.admin_level >= PERMS['USER_VOTERS_VISIBLE']): abort(403)
page = max(1, int(request.values.get("page", 1)))
@ -674,7 +674,7 @@ def message2(v, username):
if hasattr(user, 'is_blocking') and user.is_blocking:
return {"error": "You're blocking this user."}, 403
if v.admin_level <= 1 and hasattr(user, 'is_blocked') and user.is_blocked:
if v.admin_level <= PERMS['MESSAGE_BLOCKED_USERS'] and hasattr(user, 'is_blocked') and user.is_blocked:
return {"error": "This user is blocking you."}, 403
message = request.values.get("message", "").strip()[:10000].strip()
@ -810,7 +810,7 @@ def messagereply(v):
if c.top_comment.sentto == 2:
admins = g.db.query(User.id).filter(User.admin_level > 2, User.id != v.id)
admins = g.db.query(User.id).filter(User.admin_level >= PERMS['NOTIFICATIONS_MODMAIL'], User.id != v.id)
if SITE == 'watchpeopledie.co':
admins = admins.filter(User.id != AEVANN_ID)
@ -961,7 +961,7 @@ def u_username(username, v=None):
g.db.commit()
if u.is_private and (not v or (v.id != u.id and v.admin_level < 2 and not v.eye)):
if u.is_private and (not v or (v.id != u.id and v.admin_level < PERMS['VIEW_PRIVATE_PROFILES'] and not v.eye)):
if request.headers.get("Authorization") or request.headers.get("xhr") or request.path.endswith(".json"):
return {"error": "This userpage is private"}, 403
@ -1049,7 +1049,7 @@ def u_username_comments(username, v=None):
return render_template("userpage_reserved.html", u=u, v=v)
if u.is_private and (not v or (v.id != u.id and v.admin_level < 2 and not v.eye)):
if u.is_private and (not v or (v.id != u.id and v.admin_level < PERMS['VIEW_PRIVATE_PROFILES'] and not v.eye)):
if request.headers.get("Authorization") or request.headers.get("xhr") or request.path.endswith(".json"):
return {"error": "This userpage is private"}, 403
return render_template("userpage_private.html", u=u, v=v)
@ -1074,7 +1074,7 @@ def u_username_comments(username, v=None):
Comment.parent_submission != None
)
if not v or (v.id != u.id and v.admin_level < 2):
if not v or (v.id != u.id and v.admin_level < PERMS['POST_COMMENT_MODERATION']):
comments = comments.filter(
Comment.is_banned == False,
Comment.ghost == False,

View File

@ -10,19 +10,21 @@
<pre></pre>
<h3 class="pb-2">Admin Tools</h3>
{% if v.admin_level > 2 and (SITE_NAME == 'rDrama' or SIDEBAR_THREAD or BANNER_THREAD or BADGE_THREAD or SNAPPY_THREAD) %}
{% if (v.admin_level >= PERMS['SITE_SETTINGS_SIDEBARS_BANNERS_BADGES'] or v.admin_level >= PERMS['SITE_SETTINGS_SNAPPY_QUOTES']) and (SITE_NAME == 'rDrama' or SIDEBAR_THREAD or BANNER_THREAD or BADGE_THREAD or SNAPPY_THREAD) %}
<h4>Add Stuff</h4>
<ul>
{% if SIDEBAR_THREAD %}
<li><a href="/post/{{SIDEBAR_THREAD}}">Add Sidebar Images</a></li>
{% if v.admin_level >= PERMS['SITE_SETTINGS_SIDEBARS_BANNERS_BADGES'] %}
{% if SIDEBAR_THREAD %}
<li><a href="/post/{{SIDEBAR_THREAD}}">Add Sidebar Images</a></li>
{% endif %}
{% if BANNER_THREAD %}
<li><a href="/post/{{BANNER_THREAD}}">Add Banners</a></li>
{% endif %}
{% if BADGE_THREAD %}
<li><a href="/post/{{BADGE_THREAD}}">Add Badges</a></li>
{% endif %}
{% endif %}
{% if BANNER_THREAD %}
<li><a href="/post/{{BANNER_THREAD}}">Add Banners</a></li>
{% endif %}
{% if BADGE_THREAD %}
<li><a href="/post/{{BADGE_THREAD}}">Add Badges</a></li>
{% endif %}
{% if SNAPPY_THREAD %}
{% if SNAPPY_THREAD and v.admin_level >= PERMS['SITE_SETTINGS_SNAPPY_QUOTES'] %}
<li><a href="/post/{{SNAPPY_THREAD}}">Add Snappy Quotes</a></li>
{% endif %}
{% if SITE_NAME == 'rDrama' %}
@ -35,16 +37,22 @@
<h4>Content</h4>
<ul>
<li><a href="/log">Moderation Log</a></li>
<li><a href="/admin/image_posts">Image Posts</a></li>
<li><a href="/admin/reported/posts">Reported Posts/Comments</a></li>
<li><a href="/admin/removed/posts">Removed Posts/Comments</a></li>
{% if v.admin_level >= PERMS['POST_COMMENT_MODERATION'] %}
<li><a href="/admin/image_posts">Image Posts</a></li>
<li><a href="/admin/reported/posts">Reported Posts/Comments</a></li>
<li><a href="/admin/removed/posts">Removed Posts/Comments</a></li>
{% endif %}
</ul>
<h4>Users</h4>
<ul>
<li><a href="/admin/users">Users Feed</a></li>
<li><a href="/admin/shadowbanned">Shadowbanned Users</a></li>
<li><a href="/banned">Permabanned Users</a></li>
{% if v.admin_level >= PERMS['VIEW_ALL_USERS'] %}
<li><a href="/admin/users">Users Feed</a></li>
{% endif %}
{% if v.admin_level >= PERMS['USER_SHADOWBAN'] %}
<li><a href="/admin/shadowbanned">Shadowbanned Users</a></li>
{% endif %}
<li><a href="/banned">Permabanned Users</a></li>
{% if FEATURES['AWARDS'] -%}
<li><a href="/agendaposters">Users with Chud Theme</a></li>
<li><a href="/grassed">Currently Grassed Users</a></li>
@ -52,8 +60,10 @@
{% if FEATURES['PROCOINS'] and (not AEVANN_ID or v.id in (AEVANN_ID, CARP_ID, SNAKES_ID)) -%}
<li><a href="/patrons">Patrons</a></li>
{%- endif %}
<li><a href="/admin/loggedin">Currently Logged-in Users</a></li>
<li><a href="/admin/loggedout">Currently Logged-out Users</a></li>
{% if v.admin_level >= PERMS['VIEW_ACTIVE_USERS'] %}
<li><a href="/admin/loggedin">Currently Logged-in Users</a></li>
<li><a href="/admin/loggedout">Currently Logged-out Users</a></li>
{% endif %}
</ul>
<h4>Safety</h4>
@ -65,7 +75,7 @@
{% if FEATURES['BADGES'] or FEATURES['AWARDS'] -%}
<h4>Grant</h4>
<ul>
{% if FEATURES['BADGES'] -%}
{% if FEATURES['BADGES'] and v.admin_level >= PERMS['USER_BADGES'] -%}
<li><a href="/admin/badge_grant">Grant Badges</a></li>
<li><a href="/admin/badge_remove">Remove Badges</a></li>
{%- endif %}
@ -89,11 +99,15 @@
<h4>Configuration</h4>
<ul>
<li><a href="/create_hole">Create {{ HOLE_NAME | capitalize }}</a></li>
<li><a href="/admin/apps">Apps</a></li>
{% if v.admin_level >= PERMS['HOLE_CREATE'] %}
<li><a href="/create_hole">Create {{ HOLE_NAME | capitalize }}</a></li>
{% endif %}
{% if v.admin_level >= PERMS['APPS_MODERATION'] %}
<li><a href="/admin/apps">Apps</a></li>
{% endif %}
</ul>
{% if v.admin_level > 2 %}
{% if v.admin_level >= PERMS['SITE_SETTINGS'] %}
<pre></pre>
<div class="custom-control custom-switch">
<input autocomplete="off" type="checkbox" class="custom-control-input" id="signups" {% if site_settings['Signups'] %}checked{% endif %} onchange="post_toast(this,'/admin/site_settings/Signups');">
@ -119,15 +133,17 @@
<input autocomplete="off" type="checkbox" class="custom-control-input" id="Read-only mode" {% if site_settings['Read-only mode'] %}checked{% endif %} onchange="post_toast(this,'/admin/site_settings/Read-only mode');">
<label class="custom-control-label" for="Read-only mode">Read-only mode</label>
</div>
<div class="custom-control custom-switch">
<input autocomplete="off" type="checkbox" class="custom-control-input" id="under_attack" name="under_attack" {% if under_attack%}checked{% endif %} onchange="post_toast(this,'/admin/under_attack');">
<label class="custom-control-label" for="under_attack">Under attack mode</label>
</div>
<button class="btn btn-primary mt-3" onclick="post_toast(this,'/admin/purge_cache');" style="margin-bottom: 2em;">PURGE CACHE</button>
{% if v.admin_level >= PERMS['SITE_SETTINGS_UNDER_ATTACK'] %}
<div class="custom-control custom-switch">
<input autocomplete="off" type="checkbox" class="custom-control-input" id="under_attack" name="under_attack" {% if under_attack%}checked{% endif %} onchange="post_toast(this,'/admin/under_attack');">
<label class="custom-control-label" for="under_attack">Under attack mode</label>
</div>
{% endif %}
{% if v.admin_level >= PERMS['SITE_CACHE_PURGE_CDN'] %}
<button class="btn btn-primary mt-3" onclick="post_toast(this,'/admin/purge_cache');" style="margin-bottom: 2em;">PURGE CACHE</button>
{% endif %}
<br>
{% if SITE_NAME == 'PCM' %}
{% if SITE_NAME == 'PCM' and v.admin_level >= PERMS['PRINT_MARSEYBUX_FOR_KIPPY_ON_PCMEMES'] %}
<button class="btn btn-primary" onclick="post_toast(this,'/kippy');" style="margin-bottom: 2em;">Print 10k Marseybux</button>
{% endif %}
{% endif %}

View File

@ -32,7 +32,7 @@
id="root"
data-id="{{v.id}}"
data-username="{{v.username}}"
data-admin="{{v.admin_level > 1}}"
data-admin="{{v.admin_level >= PERMS['ADMIN_MOP_VISIBLE']}}"
data-censored="{{v.slurreplacer}}"
data-sitename="{{SITE_NAME}}"
data-themecolor="{{v.themecolor}}"

View File

@ -21,14 +21,14 @@
{% set score=ups-downs %}
{% if render_replies %}
{% if v and (v.shadowbanned or v.admin_level >= 2) %}
{% if v and (v.shadowbanned or v.admin_level >= PERMS['USER_SHADOWBAN']) %}
{% set replies=c.replies3(sort) %}
{% else %}
{% set replies=c.replies(sort) %}
{% endif %}
{% endif %}
{% if c.is_blocking and not c.ghost or (c.is_banned or c.deleted_utc) and not (v and v.admin_level > 1) and not (v and v.id==c.author_id) %}
{% if c.is_blocking and not c.ghost or (c.is_banned or c.deleted_utc) and not (v and v.admin_level >= PERMS['POST_COMMENT_MODERATION']) and not (v and v.id==c.author_id) %}
<div id="comment-{{c.id}}" class="comment">
<span class="comment-collapse-desktop d-none d-md-block" style="border-left: 2px solid #{{c.author.name_color}}"onclick="collapse_comment('{{c.id}}', this.parentElement)"></span>
@ -140,7 +140,7 @@
{% endif %}
{% if c.active_flags(v) %}<a class="btn btn-primary" style="padding:1px 5px; font-size:10px"role="button" onclick="document.getElementById('flaggers-{{c.id}}').classList.toggle('d-none')">{{c.active_flags(v)}} Report{{ help.plural(c.active_flags(v)) }}</a>{% endif %}
{% if c.over_18 %}<span class="badge badge-danger text-small-extra mr-1">+18</span>{% endif %}
{% if v and v.admin_level > 1 and c.author.shadowbanned %}<i class="fas fa-user-times text-admin" data-bs-toggle="tooltip" data-bs-placement="bottom" title='Shadowbanned by @{{c.author.shadowbanned}} for "{{c.author.ban_reason}}"'></i>{% endif %}
{% if v and v.admin_level >= PERMS['USER_SHADOWBAN'] and c.author.shadowbanned %}<i class="fas fa-user-times text-admin" data-bs-toggle="tooltip" data-bs-placement="bottom" title='Shadowbanned by @{{c.author.shadowbanned}} for "{{c.author.ban_reason}}"'></i>{% endif %}
{% if c.stickied %}
<i id='pinned-{{c.id}}'class="fas fa-thumbtack fa-rotate--45 text-admin" data-bs-toggle="tooltip" data-bs-placement="bottom" title="Pinned by @{{c.stickied}}" {% if c.stickied_utc %}onmouseover="pinned_timestamp('pinned-{{c.id}}')" data-timestamp={{c.stickied_utc}} {% endif %}></i>
{% endif %}
@ -298,7 +298,7 @@
<div class="post-actions">
<ul class="list-inline text-right d-flex">
<li class="list-inline-item mr-auto">
{% if v and v.admin_level > 1 %}
{% if v and v.admin_level >= PERMS['POST_COMMENT_MODERATION'] %}
<a role="button" data-bs-toggle="modal" data-bs-target="#adminModal-{{c.id}}">
<i class="fas fa-broom"></i>
</a>
@ -315,7 +315,7 @@
</a>
</li>
{% if v and request.path.startswith('/@') and v.admin_level < 2 %}
{% if v and request.path.startswith('/@') and v.admin_level < PERMS['VIEW_VOTE_BUTTONS_ON_USER_PAGE'] %}
<li id="voting-{{c.id}}-mobile" class="voting list-inline-item d-md-none">
{% if voted==1 %}
<span class="mr-2 arrow-up comment-{{c.id}}-up active"></span>
@ -366,7 +366,7 @@
<ul class="d-none d-md-flex list-inline text-right text-md-left"><li>
{% if v and request.path.startswith('/@') and v.admin_level < 2%}
{% if v and request.path.startswith('/@') and v.admin_level < PERMS['VIEW_VOTE_BUTTONS_ON_USER_PAGE'] %}
{% if voted==1 %}
<button class="btn caction py-0 m-0 px-3 nobackground arrow-up mx-0 comment-{{c.id}}-up active"></button>
{% endif %}
@ -383,7 +383,7 @@
<span data-bs-toggle="tooltip" data-bs-placement="top" title="+{{ups}} | -{{downs}}" class="comment-score-{{c.id}} score comment-score-{{c.id}} {% if voted==1 %}score-up{% elif voted==-1%}score-down{% endif %}{% if c.controversial %} controversial{% endif %}">{{score}}</span>
</button>
{% if v and request.path.startswith('/@') and v.admin_level < 2 %}
{% if v and request.path.startswith('/@') and v.admin_level < PERMS['VIEW_VOTE_BUTTONS_ON_USER_PAGE'] %}
{% if voted==-1 %}
<li class=" arrow-down py-0 m-0 px-3 comment-{{c.id}}-down active"></li>
{% endif %}
@ -432,7 +432,7 @@
<button style="margin-top:0.2rem" class="btn caction py-0 nobackground px-1 text-muted" data-bs-toggle="dropdown" aria-expanded="false"><i class="fas fa-ellipsis-h fa-fw"></i></button>
<ul class="dropdown-menu">
{% if v.admin_level and v.id==c.author_id %}
{% if v.admin_level >= PERMS['POST_COMMENT_DISTINGUISH'] and (v.id == c.author_id or v.admin_level >= PERMS['POST_COMMENT_MODERATION']) %}
<button id="undistinguish-{{c.id}}" class="dropdown-item list-inline-item d-none {% if c.distinguish_level %}d-md-block{% endif %} text-info" onclick="post_toast(this,'/distinguish_comment/{{c.id}}','distinguish-{{c.id}}','undistinguish-{{c.id}}','d-md-block')"><i class="fas fa-id-badge text-info fa-fw"></i>Undistinguish</button>
<button id="distinguish-{{c.id}}" class="dropdown-item list-inline-item d-none {% if not c.distinguish_level %}d-md-block{% endif %} text-info" onclick="post_toast(this,'/distinguish_comment/{{c.id}}','distinguish-{{c.id}}','undistinguish-{{c.id}}','d-md-block')"><i class="fas fa-id-badge text-info fa-fw"></i>Distinguish</button>
{% endif %}
@ -446,7 +446,7 @@
{% if c.post %}
{% set url = "" %}
{% if v.admin_level > 1%}
{% if v.admin_level >= PERMS['POST_COMMENT_MODERATION'] %}
{% set url = "sticky_comment" %}
{% elif v.id == c.post.author_id %}
{% set url = "pin_comment" %}
@ -462,7 +462,7 @@
{% endif %}
{% if v.admin_level > 1 %}
{% if v.admin_level >= PERMS['POST_COMMENT_MODERATION'] %}
{% if "/reported/" in request.path %}
<button class="dropdown-item list-inline-item text-success" onclick="approveComment('{{c.id}}')"><i class="fas fa-check text-success fa-fw"></i>Approve</button>
<button class="dropdown-item list-inline-item text-danger" onclick="removeComment('{{c.id}}')"><i class="fas fa-ban text-danger fa-fw"></i>Remove</button>
@ -480,17 +480,17 @@
{% endif %}
{% endif %}
{% if c.parent_submission and (c.author_id==v.id or v.admin_level > 1 or (c.post.sub and v.mods(c.post.sub))) %}
{% if c.parent_submission and (c.author_id==v.id or v.admin_level >= PERMS['POST_COMMENT_MODERATION'] or (c.post.sub and v.mods(c.post.sub))) %}
<button id="unmark-{{c.id}}" class="dropdown-item list-inline-item d-none {% if c.over_18 %}d-md-block{% endif %} text-danger" onclick="post_toast(this,'/toggle_comment_nsfw/{{c.id}}','mark-{{c.id}}','unmark-{{c.id}}','d-md-block')"><i class="fas fa-eye-evil text-danger fa-fw"></i>Unmark +18</button>
<button id="mark-{{c.id}}" class="dropdown-item list-inline-item d-none {% if not c.over_18 %}d-md-block{% endif %} text-danger" onclick="post_toast(this,'/toggle_comment_nsfw/{{c.id}}','mark-{{c.id}}','unmark-{{c.id}}','d-md-block')"><i class="fas fa-eye-evil text-danger fa-fw"></i>Mark +18</button>
{% endif %}
{% if v.admin_level > 1 and v.id != c.author_id %}
{% if v.admin_level >= PERMS['USER_BAN'] and v.id != c.author_id %}
<button id="unban-{{c.id}}" class="dropdown-item list-inline-item d-none {% if c.author.is_suspended %}d-md-block{% endif %} text-success" onclick="post_toast(this,'/unban_user/{{c.author_id}}','ban-{{c.id}}','unban-{{c.id}}','d-md-block')"><i class="fas fa-user-slash text-success fa-fw"></i>Unban user</button>
<button id="ban-{{c.id}}" class="dropdown-item list-inline-item d-none {% if not c.author.is_suspended %}d-md-block{% endif %} text-danger" data-bs-toggle="modal" data-bs-target="#banModal" onclick="banModal('/comment/{{c.id}}', '{{c.author.id}}', '{{c.author_name}}')"><i class="fas fa-user-slash text-danger fa-fw"></i>Ban user</button>
{% endif %}
{% if v.admin_level > 1 and c.oauth_app %}
{% if v.admin_level >= PERMS['APPS_MODERATION'] and c.oauth_app %}
<a href="{{c.oauth_app.permalink}}/comments" class="dropdown-item list-inline-item d-none d-md-block text-primary"><i class="fas fa-code text-primary fa-fw"></i>API App</a>
{% endif %}
</ul>
@ -567,7 +567,7 @@
</div>
{% if request.path.startswith('/notifications') and c.level == 1 and c.sentto and not c.parent_submission and c.author_id != AUTOJANNY_ID %}
{% if (v and v.admin_level >= 2) and (c.sentto == 2) and not c.author.is_muted %}
{% if (v and v.admin_level >= PERMS['USER_BAN']) and (c.sentto == 2) and not c.author.is_muted %}
<a class="btn btn-primary" role="button" id="mute-user-{{c.id}}" onclick="adminMuteUser({{c.author_id}}, 1, {{c.id}})">Mute</a>
{% endif %}
@ -653,7 +653,7 @@
<a id="unmark2-{{c.id}}" class="{% if not c.over_18 %}d-none{% endif %} list-group-item text-danger" role="button" onclick="post_toast(this,'/toggle_comment_nsfw/{{c.id}}','mark2-{{c.id}}','unmark2-{{c.id}}','d-none')" data-bs-dismiss="modal"><i class="fas fa-eye-evil text-danger mr-2"></i>Unmark +18</a>
{% endif %}
{% if v.admin_level < 2 %}
{% if v.admin_level < PERMS['POST_COMMENT_MODERATION'] %}
{% if c.post and v.id == c.post.author_id %}
<a id="pin2-{{c.id}}" class="list-group-item {% if c.stickied %}d-none{% endif %} text-info" role="button" data-bs-target="#actionsModal-{{c.id}}" onclick="post_toast(this,'/pin_comment/{{c.id}}','pin2-{{c.id}}','unpin2-{{c.id}}','d-none')" data-bs-dismiss="modal"><i class="fas fa-thumbtack fa-rotate--45 text-info mr-2"></i>Pin</a>
<a id="unpin2-{{c.id}}" class="list-group-item {% if not c.stickied %}d-none{% endif %} text-info" role="button" data-bs-target="#actionsModal-{{c.id}}" onclick="post_toast(this,'/unpin_comment/{{c.id}}','pin2-{{c.id}}','unpin2-{{c.id}}','d-none')" data-bs-dismiss="modal"><i class="fas fa-thumbtack fa-rotate--45 text-info mr-2"></i>Unpin</a>
@ -682,7 +682,7 @@
{% if v and v.admin_level > 1 %}
{% if v and v.admin_level >= PERMS['POST_COMMENT_MODERATION_TOOLS_VISIBLE'] %}
<div class="modal fade d-md-none" id="adminModal-{{c.id}}" tabindex="-1" role="dialog" aria-labelledby="actionsModalTitle" aria-hidden="true">
<div class="modal-dialog modal-dialog-centered" role="document">
<div class="modal-content">
@ -707,20 +707,21 @@
<a id="unmark2-{{c.id}}" class="{% if not c.over_18 %}d-none{% endif %} list-group-item text-danger" role="button" onclick="post_toast(this,'/toggle_comment_nsfw/{{c.id}}','mark2-{{c.id}}','unmark2-{{c.id}}','d-none')" data-bs-dismiss="modal"><i class="fas fa-eye-evil text-danger mr-2"></i>Unmark +18</a>
{% endif %}
{% if v.id != c.author_id %}
{% if v.id != c.author_id and v.admin_level >= PERMS['USER_BAN'] %}
<a id="ban2-{{c.id}}" class="{% if c.author.is_banned %}d-none{% endif %} list-group-item text-danger" data-bs-dismiss="modal" data-bs-toggle="modal" data-bs-target="#banModal" onclick="banModal('/comment/{{c.id}}', '{{c.author.id}}', '{{c.author_name}}')" role="button"><i class="fas fa-user-slash text-danger fa-fw mr-2"></i>Ban user</a>
<a id="unban2-{{c.id}}" class="{% if not c.author.is_banned %}d-none{% endif %} list-group-item text-success" role="button" onclick="post_toast(this,'/unban_user/{{c.author_id}}','ban2-{{c.id}}','unban2-{{c.id}}','d-none')" data-bs-dismiss="modal"><i class="fas fa-user-minus fa-fw text-success mr-2"></i>Unban user</a>
{% endif %}
{% if "/reported/" in request.path %}
<a class="list-group-item text-danger" role="button" onclick="removeComment2('{{c.id}}')" data-bs-dismiss="modal"><i class="fas fa-ban text-danger mr-2"></i>Remove</a>
<a class="list-group-item text-success" role="button" onclick="approveComment2('{{c.id}}')" data-bs-dismiss="modal"><i class="fas fa-check text-success mr-2"></i>Approve</a>
{% else %}
<a id="remove2-{{c.id}}" class="{% if c.is_banned %}d-none{% endif %} list-group-item text-danger" role="button" onclick="removeComment2('{{c.id}}','approve2-{{c.id}}','remove2-{{c.id}}')" data-bs-dismiss="modal"><i class="fas fa-ban text-danger mr-2"></i>Remove</a>
<a id="approve2-{{c.id}}" class="{% if not c.is_banned %}d-none{% endif %} list-group-item text-success" role="button" onclick="approveComment2('{{c.id}}','approve2-{{c.id}}','remove2-{{c.id}}')" data-bs-dismiss="modal"><i class="fas fa-check text-success mr-2"></i>Approve</a>
{% if v.admin_level >= PERMS['POST_COMMENT_MODERATION'] %}
{% if "/reported/" in request.path %}
<a class="list-group-item text-danger" role="button" onclick="removeComment2('{{c.id}}')" data-bs-dismiss="modal"><i class="fas fa-ban text-danger mr-2"></i>Remove</a>
<a class="list-group-item text-success" role="button" onclick="approveComment2('{{c.id}}')" data-bs-dismiss="modal"><i class="fas fa-check text-success mr-2"></i>Approve</a>
{% else %}
<a id="remove2-{{c.id}}" class="{% if c.is_banned %}d-none{% endif %} list-group-item text-danger" role="button" onclick="removeComment2('{{c.id}}','approve2-{{c.id}}','remove2-{{c.id}}')" data-bs-dismiss="modal"><i class="fas fa-ban text-danger mr-2"></i>Remove</a>
<a id="approve2-{{c.id}}" class="{% if not c.is_banned %}d-none{% endif %} list-group-item text-success" role="button" onclick="approveComment2('{{c.id}}','approve2-{{c.id}}','remove2-{{c.id}}')" data-bs-dismiss="modal"><i class="fas fa-check text-success mr-2"></i>Approve</a>
{% endif %}
{% endif %}
{% if c.oauth_app %}
{% if c.oauth_app and v.admin_level >= PERMS['APPS_MODERATION'] %}
<a href="{{c.oauth_app.permalink}}/comments" class="list-group-item text-info"><i class="fas fa-code text-info mr-2"></i>API App</a>
{% endif %}
</ul>
@ -755,7 +756,7 @@
{% if v %}
{% include "gif_modal.html" %}
{% include "emoji_modal.html" %}
{% if v.admin_level > 1 %}
{% if v.admin_level >= PERMS['USER_BAN'] %}
{% include "ban_modal.html" %}
{% endif %}
@ -819,7 +820,7 @@
<script defer src="{{'js/clipboard.js' | asset}}"></script>
{% if v and v.admin_level >= 2 %}
{% if v and v.admin_level >= PERMS['POST_COMMENT_MODERATION_TOOLS_VISIBLE'] %}
<script defer src="{{'js/comments_admin.js' | asset}}"></script>
{% endif %}

View File

@ -116,7 +116,7 @@
{% endif %}
{% if not err %}
{% if v and v.admin_level > 1 %}
{% if v and v.admin_level >= PERMS['ADMIN_HOME_VISIBLE'] %}
<a class="mobile-nav-icon d-md-none" href="/admin"><i class="fas fa-crown align-middle text-gray-500 black"></i></a>
{% endif %}
@ -161,7 +161,7 @@
</li>
{% endif %}
{% if v.admin_level > 1 %}
{% if v.admin_level >= PERMS['ADMIN_HOME_VISIBLE'] %}
<li class="nav-item d-flex align-items-center justify-content-center text-center mx-1">
<a class="nav-link" href="/admin" data-bs-toggle="tooltip" data-bs-placement="bottom" title="Admin Tools"><i class="fas fa-crown"></i></a>
</li>

View File

@ -54,7 +54,7 @@
<td>{{name}}</td>
<td>{{title}}</td>
<td>{{viewers}} watching</td>
{% if v and v.admin_level > 1 %}
{% if v and v.admin_level >= PERMS['STREAMERS_MODERATION'] %}
<td>
<form action="/live/remove" method="post">
<input type="hidden" name="formkey" value="{{v.formkey}}">
@ -80,7 +80,7 @@
<td>{{name}}</td>
<td>{{actual}} ago</td>
<td>{{views}} views</td>
{% if v and v.admin_level > 1 %}
{% if v and v.admin_level >= PERMS['STREAMERS_MODERATION'] %}
<td>
<form action="/live/remove" method="post">
<input type="hidden" name="formkey" value="{{v.formkey}}">
@ -96,7 +96,7 @@
</table>
</div>
{% if v and v.admin_level > 1 %}
{% if v and v.admin_level >= PERMS['STREAMERS_MODERATION'] %}
<form action="/live/add" method="post">
<input type="hidden" name="formkey" value="{{v.formkey}}">
<input class="form-control" autocomplete="off" type="text" name="link" class="form-control" placeholder="Enter channel link.." required>

View File

@ -10,7 +10,7 @@
/>
</div>
<div class="lottery-page--stats">
{% if v.admin_level > 2 %}
{% if v.admin_level >= PERMS['LOTTERY_ADMIN'] %}
<div
class="lottery-page--stat"
style="position: relative; padding-top: 1rem; overflow: hidden"

View File

@ -37,7 +37,7 @@
</a>
</li>
{% endif %}
{% if v.admin_level >= 2 %}
{% if v.admin_level >= PERMS['VIEW_MODMAIL'] %}
<li class="nav-item">
<a class="nav-link py-3{% if request.path == '/notifications/modmail' %} active{% endif %}" href="/notifications/modmail">
Modmail

View File

@ -40,12 +40,12 @@
{% if v %}
<a class="list-inline-item" role="button" data-bs-toggle="dropdown" aria-expanded="false"><i class="fas fa-ellipsis-h fa-fw"></i></a>
<ul class="dropdown-menu">
{% if v.admin_level %}
{% if v.admin_level >= PERMS['POST_COMMENT_DISTINGUISH'] %}
<a id="distinguish-{{p.id}}" class="dropdown-item {% if p.distinguish_level %}d-none{% endif %} list-inline-item text-info" role="button" onclick="post_toast(this,'/distinguish/{{p.id}}','distinguish-{{p.id}}','undistinguish-{{p.id}}','d-none')"><i class="fas fa-crown"></i>Distinguish</a>
<a id="undistinguish-{{p.id}}" class="dropdown-item {% if not p.distinguish_level %}d-none{% endif %} list-inline-item text-info" role="button" onclick="post_toast(this,'/distinguish/{{p.id}}','distinguish-{{p.id}}','undistinguish-{{p.id}}','d-none')"><i class="fas fa-crown"></i>Undistinguish</a>
{% endif %}
{% if v.admin_level > 1 %}
{% if v.admin_level >= PERMS['POST_COMMENT_MODERATION'] %}
<a id="pin-{{p.id}}" class="dropdown-item {% if p.stickied %}d-none{% endif %} list-inline-item text-info" role="button" onclick="post_toast(this,'/sticky/{{p.id}}','pin-{{p.id}}','unpin-{{p.id}}','d-none')"><i class="fas fa-thumbtack fa-rotate--45"></i>Pin</a>
<a id="unpin-{{p.id}}" class="dropdown-item {% if not p.stickied %}d-none{% endif %} list-inline-item text-info" role="button" onclick="post_toast(this,'/unsticky/{{p.id}}','pin-{{p.id}}','unpin-{{p.id}}','d-none')"><i class="fas fa-thumbtack fa-rotate--45"></i>Unpin</a>
{% endif %}
@ -55,12 +55,12 @@
<a id="hole-unpin-{{p.id}}" class="dropdown-item {% if not p.hole_pinned %}d-none{% endif %} list-inline-item text-info" role="button" onclick="post_toast(this,'/hole_unpin/{{p.id}}','hole-pin-{{p.id}}','hole-unpin-{{p.id}}','d-none')"><i class="fas fa-thumbtack fa-rotate--45"></i>Unpin from /h/{{p.sub}}</a>
{% endif %}
{% if FEATURES['COUNTRY_CLUB'] and (v.admin_level > 1 or v.id == p.author_id) %}
<a id="club-{{p.id}}" class="dropdown-item {% if p.club %}d-none{% endif %} list-inline-item text-info" role="button" onclick="post_toast(this,'/club_post/{{p.id}}','club-{{p.id}}','unclub-{{p.id}}','d-none')"><i class="fas fa-eye-slash"></i>Mark club</a>
<a id="unclub-{{p.id}}" class="dropdown-item {% if not p.club %}d-none{% endif %} list-inline-item text-info" role="button" onclick="post_toast(this,'/unclub_post/{{p.id}}','club-{{p.id}}','unclub-{{p.id}}','d-none')"><i class="fas fa-eye"></i>Unmark club</a>
{% if FEATURES['COUNTRY_CLUB'] and (v.admin_level >= PERMS['POST_COMMENT_MODERATION'] or v.id == p.author_id) %}
<a id="club-{{p.id}}" class="dropdown-item {% if p.club %}d-none{% endif %} list-inline-item text-info" role="button" onclick="post_toast(this,'/toggle_club/{{p.id}}','club-{{p.id}}','unclub-{{p.id}}','d-none')"><i class="fas fa-eye-slash"></i>Mark club</a>
<a id="unclub-{{p.id}}" class="dropdown-item {% if not p.club %}d-none{% endif %} list-inline-item text-info" role="button" onclick="post_toast(this,'/toggle_club/{{p.id}}','club-{{p.id}}','unclub-{{p.id}}','d-none')"><i class="fas fa-eye"></i>Unmark club</a>
{% endif %}
{% if v.admin_level > 1 %}
{% if v.admin_level >= PERMS['POST_COMMENT_MODERATION'] %}
{% if "/reported/" in request.path %}
{% if v.id != p.author.id %}<a class="dropdown-item list-inline-item text-danger" role="button" onclick="post_toast(this,'/remove_post/{{p.id}}')"><i class="fas fa-ban"></i>Remove</a>{% endif %}
<a class="dropdown-item list-inline-item text-success" role="button" onclick="post_toast(this,'/approve_post/{{p.id}}')"><i class="fas fa-check"></i>Approve</a>
@ -93,12 +93,12 @@
{% endif %}
{% if v.id==p.author_id or v.admin_level > 1 or (p.sub and v.mods(p.sub)) %}
{% if v.id==p.author_id or v.admin_level >= PERMS['POST_COMMENT_MODERATION'] or (p.sub and v.mods(p.sub)) %}
<a id="mark-{{p.id}}" class="dropdown-item {% if p.over_18 %}d-none{% endif %} list-inline-item text-danger" role="button" onclick="post_toast(this,'/toggle_post_nsfw/{{p.id}}','mark-{{p.id}}','unmark-{{p.id}}','d-none')"><i class="fas fa-eye-evil"></i>Mark +18</a>
<a id="unmark-{{p.id}}" class="dropdown-item {% if not p.over_18 %}d-none{% endif %} list-inline-item text-success" role="button" onclick="post_toast(this,'/toggle_post_nsfw/{{p.id}}','mark-{{p.id}}','unmark-{{p.id}}','d-none')"><i class="fas fa-eye-evil"></i>Unmark +18</a>
{% endif %}
{% if v.admin_level > 1 and v.id != p.author_id %}
{% if v.admin_level >= PERMS['USER_BAN'] and v.id != p.author_id %}
<a id="ban-{{p.id}}" class="dropdown-item {% if p.author.is_suspended %}d-none{% endif %} list-inline-item text-danger" id="exile-comment-{{p.id}}" role="button" data-bs-toggle="modal" data-bs-target="#banModal" onclick="banModal('/post/{{p.id}}', '{{p.author.id}}', '{{p.author_name}}')"><i class="fas fa-user-slash text-danger fa-fw"></i>Ban user</a>
<a id="unban-{{p.id}}" class="dropdown-item {% if not p.author.is_suspended %}d-none{% endif %} list-inline-item text-danger" id="unexile2-user-{{p.id}}" role="button" onclick="post_toast(this,'/unban_user/{{p.author_id}}','ban-{{p.id}}','unban-{{p.id}}','d-none')"><i class="fas fa-user-slash"></i>Unban user</a>
{% endif %}

View File

@ -9,7 +9,7 @@
</div>
<div class="modal-body">
<ul class="list-group post-actions">
{% if (request.path.startswith('/post/') or request.path.startswith('/h/')) and v.admin_level > 2 and p.id %}
{% if (request.path.startswith('/post/') or request.path.startswith('/h/')) and v.admin_level >= PERMS['POST_EDITING'] and p.id %}
<button class="nobackground btn btn-link btn-block btn-lg text-left text-muted" data-bs-dismiss="modal" onclick="togglePostEdit('{{p.id}}')"><i class="far fa-edit text-center text-muted mr-2"></i>Edit</button>
{% endif %}
@ -17,31 +17,30 @@
<button id="club2-{{p.id}}" class="{% if p.club %}d-none{% endif %} nobackground btn btn-link btn-block btn-lg text-info text-left" role="button" onclick="post_toast(this,'/club_post/{{p.id}}','club2-{{p.id}}','unclub2-{{p.id}}','d-none')" data-bs-dismiss="modal"><i class="fas fa-eye-slash mr-2"></i>Mark club</button>
<button id="unclub2-{{p.id}}" class="{% if not p.club %}d-none{% endif %} nobackground btn btn-link btn-block btn-lg text-info text-left" role="button" onclick="post_toast(this,'/unclub_post/{{p.id}}','club2-{{p.id}}','unclub2-{{p.id}}','d-none')" data-bs-dismiss="modal"><i class="fas fa-eye mr-2"></i>Unmark club</button>
{%- endif %}
{% if v.admin_level >= PERMS['POST_COMMENT_DISTINGUISH'] and (v.id == c.author_id or v.admin_level >= PERMS['POST_COMMENT_MODERATION']) %}
<button id="distinguish2-{{p.id}}" class="{% if p.distinguish_level %}d-none{% endif %} nobackground btn btn-link btn-block btn-lg text-left text-primary" role="button" onclick="post_toast(this,'/distinguish/{{p.id}}','distinguish2-{{p.id}}','undistinguish2-{{p.id}}','d-none')" data-bs-dismiss="modal"><i class="fas fa-crown text-center text-primary mr-2"></i>Distinguish</button>
<button id="undistinguish2-{{p.id}}" class="{% if not p.distinguish_level %}d-none{% endif %} nobackground btn btn-link btn-block btn-lg text-left text-primary" role="button" onclick="post_toast(this,'/distinguish/{{p.id}}','distinguish2-{{p.id}}','undistinguish2-{{p.id}}','d-none')" data-bs-dismiss="modal"><i class="fas fa-crown text-center text-primary mr-2"></i>Undistinguish</button>
<button id="pin2-{{p.id}}" class="{% if p.stickied %}d-none{% endif %} nobackground btn btn-link btn-block btn-lg text-left text-primary" role="button" onclick="post_toast(this,'/sticky/{{p.id}}','pin2-{{p.id}}','unpin2-{{p.id}}','d-none')" data-bs-dismiss="modal"><i class="fas fa-thumbtack fa-rotate--45 text-center text-primary mr-2"></i>Pin</button>
<button id="unpin2-{{p.id}}" class="{% if not p.stickied %}d-none{% endif %} nobackground btn btn-link btn-block btn-lg text-left text-primary" role="button" onclick="post_toast(this,'/unsticky/{{p.id}}','pin2-{{p.id}}','unpin2-{{p.id}}','d-none')" data-bs-dismiss="modal"><i class="fas fa-thumbtack fa-rotate--45 text-center text-primary mr-2"></i>Unpin</button>
{% if "/reported/" in request.path %}
<button class="nobackground btn btn-link btn-block btn-lg text-danger text-left" role="button" onclick="post_toast(this,'/remove_post/{{p.id}}')" data-bs-dismiss="modal"><i class="far fa-ban text-center mr-2"></i>Remove</button>
<button class="nobackground btn btn-link btn-block btn-lg text-success text-left" role="button" onclick="post_toast(this,'/approve_post/{{p.id}}')" data-bs-dismiss="modal"><i class="far fa-check text-center mr-2"></i>Approve</button>
{% else %}
<button id="remove2-{{p.id}}" class="{% if p.is_banned %}d-none{% endif %} nobackground btn btn-link btn-block btn-lg text-danger text-left" role="button" onclick="post_toast(this,'/remove_post/{{p.id}}','remove2-{{p.id}}','approve2-{{p.id}}','d-none')" data-bs-dismiss="modal"><i class="far fa-ban text-center mr-2"></i>Remove</button>
<button id="approve2-{{p.id}}" class="{% if not p.is_banned %}d-none{% endif %} nobackground btn btn-link btn-block btn-lg text-success text-left" role="button" onclick="post_toast(this,'/approve_post/{{p.id}}','remove2-{{p.id}}','approve2-{{p.id}}','d-none')" data-bs-dismiss="modal"><i class="far fa-check text-center mr-2"></i>Approve</button>
{% endif %}
{% if p.oauth_app %}
{% if v.admin_level >= PERMS['POST_COMMENT_MODERATION'] %}
<button id="pin2-{{p.id}}" class="{% if p.stickied %}d-none{% endif %} nobackground btn btn-link btn-block btn-lg text-left text-primary" role="button" onclick="post_toast(this,'/sticky/{{p.id}}','pin2-{{p.id}}','unpin2-{{p.id}}','d-none')" data-bs-dismiss="modal"><i class="fas fa-thumbtack fa-rotate--45 text-center text-primary mr-2"></i>Pin</button>
<button id="unpin2-{{p.id}}" class="{% if not p.stickied %}d-none{% endif %} nobackground btn btn-link btn-block btn-lg text-left text-primary" role="button" onclick="post_toast(this,'/unsticky/{{p.id}}','pin2-{{p.id}}','unpin2-{{p.id}}','d-none')" data-bs-dismiss="modal"><i class="fas fa-thumbtack fa-rotate--45 text-center text-primary mr-2"></i>Unpin</button>
{% if "/reported/" in request.path %}
<button class="nobackground btn btn-link btn-block btn-lg text-danger text-left" role="button" onclick="post_toast(this,'/remove_post/{{p.id}}')" data-bs-dismiss="modal"><i class="far fa-ban text-center mr-2"></i>Remove</button>
<button class="nobackground btn btn-link btn-block btn-lg text-success text-left" role="button" onclick="post_toast(this,'/approve_post/{{p.id}}')" data-bs-dismiss="modal"><i class="far fa-check text-center mr-2"></i>Approve</button>
{% else %}
<button id="remove2-{{p.id}}" class="{% if p.is_banned %}d-none{% endif %} nobackground btn btn-link btn-block btn-lg text-danger text-left" role="button" onclick="post_toast(this,'/remove_post/{{p.id}}','remove2-{{p.id}}','approve2-{{p.id}}','d-none')" data-bs-dismiss="modal"><i class="far fa-ban text-center mr-2"></i>Remove</button>
<button id="approve2-{{p.id}}" class="{% if not p.is_banned %}d-none{% endif %} nobackground btn btn-link btn-block btn-lg text-success text-left" role="button" onclick="post_toast(this,'/approve_post/{{p.id}}','remove2-{{p.id}}','approve2-{{p.id}}','d-none')" data-bs-dismiss="modal"><i class="far fa-check text-center mr-2"></i>Approve</button>
{% endif %}
{% endif %}
{% if p.oauth_app and v.admin_level >= PERMS['APPS_MODERATION'] %}
<a href="{{p.oauth_app.permalink}}"><button class="nobackground btn btn-link btn-block btn-lg text-muted text-left"><i class="far fa-code text-center text-info mr-2"></i>API App</button></a>
{% endif %}
<button id="mark2-{{p.id}}" class="{% if p.over_18 %}d-none{% endif %} nobackground btn btn-link btn-block btn-lg text-left text-danger" onclick="post_toast(this,'/toggle_post_nsfw/{{p.id}}','mark2-{{p.id}}','unmark2-{{p.id}}','d-none')" data-bs-dismiss="modal"><i class="far fa-eye-evil text-center text-danger mr-2"></i>Mark +18</button>
<button id="unmark2-{{p.id}}" class="{% if not p.over_18 %}d-none{% endif %} nobackground btn btn-link btn-block btn-lg text-left text-danger" onclick="post_toast(this,'/toggle_post_nsfw/{{p.id}}','mark2-{{p.id}}','unmark2-{{p.id}}','d-none')" data-bs-dismiss="modal"><i class="far fa-eye-evil text-center text-danger mr-2"></i>Unmark +18</button>
{% if v.id != p.author_id %}
{% if v.admin_level >= PERMS['POST_COMMENT_MODERATION'] %}
<button id="mark2-{{p.id}}" class="{% if p.over_18 %}d-none{% endif %} nobackground btn btn-link btn-block btn-lg text-left text-danger" onclick="post_toast(this,'/toggle_post_nsfw/{{p.id}}','mark2-{{p.id}}','unmark2-{{p.id}}','d-none')" data-bs-dismiss="modal"><i class="far fa-eye-evil text-center text-danger mr-2"></i>Mark +18</button>
<button id="unmark2-{{p.id}}" class="{% if not p.over_18 %}d-none{% endif %} nobackground btn btn-link btn-block btn-lg text-left text-danger" onclick="post_toast(this,'/toggle_post_nsfw/{{p.id}}','mark2-{{p.id}}','unmark2-{{p.id}}','d-none')" data-bs-dismiss="modal"><i class="far fa-eye-evil text-center text-danger mr-2"></i>Unmark +18</button>
{% endif %}
{% if v.id != p.author_id and v.admin_level >= PERMS['USER_BAN'] %}
<button id="ban2-{{p.id}}" data-bs-dismiss="modal" data-bs-toggle="modal" data-bs-target="#banModal" onclick="banModal('/post/{{p.id}}', '{{p.author.id}}', '{{p.author_name}}')" class="{% if p.author.is_suspended %}d-none{% endif %} nobackground btn btn-link btn-block btn-lg text-danger text-left" role="button"><i class="fas fa-user-minus mr-2"></i>Ban user</button>
<button id="unban2-{{p.id}}" class="{% if not p.author.is_suspended %}d-none{% endif %} nobackground btn btn-link btn-block btn-lg text-success text-left" role="button" onclick="post_toast(this,'/unban_user/{{p.author_id}}','ban2-{{p.id}}','unban2-{{p.id}}','d-none')" data-bs-dismiss="modal"><i class="fas fa-user-minus mr-2"></i>Unban user</button>
{% endif %}

View File

@ -53,7 +53,7 @@
{% block subNav %}
{% set mod = (v and v.admin_level > 1) %}
{% set mod = (v and v.admin_level >= PERMS['UNKNOWN_ADMIN_LEVEL2_PERM4']) %}
{% if not request.path.startswith('/h/') %}
<div class="container-fluid bg-white sticky d-none d-md-block" style="padding-top: 50px; padding-bottom: 0 !important;">
<div class="row box-shadow-bottom">

View File

@ -11,7 +11,7 @@
{% set voted=-2 %}
{% endif %}
{% set v_forbid_deleted = (p.deleted_utc != 0) and not (v and v.admin_level >= 2) and not (v and v.id == p.author_id) %}
{% set v_forbid_deleted = (p.deleted_utc != 0) and not (v and v.admin_level >= PERMS['POST_COMMENT_MODERATION']) and not (v and v.id == p.author_id) %}
{% block title %}
@ -590,7 +590,7 @@
</div>
{% endif %}
{% if v and v.admin_level > 1 %}
{% if v and v.admin_level >= PERMS['POST_COMMENT_MODERATION_TOOLS_VISIBLE'] %}
{% include "post_admin_actions_mobile.html" %}
{% endif %}
@ -640,7 +640,7 @@
<i class="{{a.class_list}} px-1" data-bs-toggle="tooltip" data-bs-placement="bottom" title="{{a.title}} Award given by @{{a.user.username}}"></i>
{% endfor %}
{% if v and v.admin_level > 1 and p.author.shadowbanned %}<i class="fas fa-user-times text-admin" data-bs-toggle="tooltip" data-bs-placement="bottom" title='Shadowbanned by @{{p.author.shadowbanned}} for "{{p.author.ban_reason}}"'></i>{% endif %}
{% if v and v.admin_level >= PERMS['USER_SHADOWBAN'] and p.author.shadowbanned %}<i class="fas fa-user-times text-admin" data-bs-toggle="tooltip" data-bs-placement="bottom" title='Shadowbanned by @{{p.author.shadowbanned}} for "{{p.author.ban_reason}}"'></i>{% endif %}
{% if p.stickied %}
<i id='pinned-{{p.id}}' class="fas fa-thumbtack fa-rotate--45 text-admin" data-bs-toggle="tooltip" data-bs-placement="bottom" title="Pinned by @{{p.stickied}}" {% if p.stickied_utc %}onmouseover="pinned_timestamp('pinned-{{p.id}}')" data-timestamp={{p.stickied_utc}} {% endif %}></i>
@ -790,7 +790,7 @@
</div>
{% endif %}
{% if v and (v.id==p.author_id or v.admin_level > 2) and not v.is_suspended %}
{% if v and (v.id==p.author_id or v.admin_level >= PERMS['POST_EDITING']) and not v.is_suspended %}
<div id="edit-post-body-{{p.id}}" class="d-none comment-write collapsed child">
<form id="post-edit-form-{{p.id}}" action="/edit_post/{{p.id}}" method="post" enctype="multipart/form-data">
<input type="hidden" name="formkey" value="{{v.formkey}}">
@ -844,7 +844,7 @@
</a>
</li>
{% if v and (v.id==p.author_id or v.admin_level > 1 and v.admin_level > 2) %}
{% if v and (v.id==p.author_id or v.admin_level >= PERMS['POST_EDITING']) %}
<a class="list-inline-item" role="button" onclick="togglePostEdit('{{p.id}}')"><i class="fas fa-edit"></i>Edit</a>
{% endif %}
@ -902,7 +902,7 @@
<span class="text-info d-none {{p.id}}-new-comments"></span>
</a>
{% if v and v.admin_level > 1 %}
{% if v and v.admin_level >= PERMS['POST_COMMENT_MODERATION_TOOLS_VISIBLE'] %}
<a class="ml-2" role="button" data-bs-toggle="modal" data-bs-target="#adminModal-{{p.id}}">
<i class="fas fa-broom"></i>
</a>
@ -1092,7 +1092,7 @@
{% include "report_post_modal.html" %}
{% endif %}
{% if v and (v.id == p.author_id or v.admin_level > 1 and v.admin_level > 2) %}
{% if v and (v.id == p.author_id or v.admin_level >= PERMS['POST_EDITING']) %}
<script defer src="{{'js/togglePostEdit.js' | asset}}"></script>
{% endif %}

View File

@ -43,7 +43,7 @@
</div>
</div>
{% if v and v.admin_level > 1 and p.body_html %}
{% if v and v.admin_level >= PERMS['POST_COMMENT_MODERATION'] and p.body_html %}
<div class="post-body mt-4 mb-2">
{{p.body_html | safe}}
</div>

View File

@ -28,7 +28,7 @@
{% set voted=-2 %}
{% endif %}
{% set v_forbid_deleted = (p.deleted_utc != 0 or p.is_banned) and not (v and v.admin_level >= 2) and not (v and v.id == p.author_id) %}
{% set v_forbid_deleted = (p.deleted_utc != 0 or p.is_banned) and not (v and v.admin_level >= PERMS['POST_COMMENT_MODERATION']) and not (v and v.id == p.author_id) %}
{% if p.active_flags(v) %}
<div id="flaggers-{{p.id}}" class="flaggers d-none">
@ -48,7 +48,7 @@
{% if not postembed %}
<div class="voting my-2 d-none d-md-flex pr-2">
{% if v and request.path.startswith('/@') and v.admin_level < 2 %}
{% if v and request.path.startswith('/@') and v.admin_level < PERMS['VIEW_VOTE_BUTTONS_ON_USER_PAGE'] %}
<div tabindex="0" role="button" onclick="vote('post', '{{p.id}}', '1')" class="post-{{p.id}}-up mx-auto arrow-up upvote-button post-{{p.id}}-up {% if voted==1 %}active{% else %}d-none{% endif %}"></div>
<span class="post-score-{{p.id}} score post-score-{{p.id}} {% if voted==1 %}score-up{% elif voted==-1%}score-down{% endif %}{% if p.controversial %} controversial{% endif %}"{% if not p.is_banned %} data-bs-toggle="tooltip" data-bs-placement="right" title="+{{ups}} | -{{downs}}"{% endif %}>{{score}}</span>
@ -133,7 +133,7 @@
<i class="{{a.class_list}} px-1" data-bs-toggle="tooltip" data-bs-placement="bottom" title="{{a.title}} Award given by @{{a.user.username}}"></i>
{% endfor %}
{% if v and v.admin_level > 1 and p.author.shadowbanned %}
{% if v and v.admin_level >= PERMS['USER_SHADOWBAN'] and p.author.shadowbanned %}
<i class="fas fa-user-times text-admin" data-bs-toggle="tooltip" data-bs-placement="bottom" title='Shadowbanned by @{{p.author.shadowbanned}} for "{{p.author.ban_reason}}"'></i>
{% endif %}
@ -225,7 +225,7 @@
<span class="text-info d-none {{p.id}}-new-comments"></span>
</a>
{% if v and v.admin_level > 1 %}
{% if v and v.admin_level >= PERMS['ADMIN_HOME_VISIBLE'] %}
<a class="ml-2" role="button" data-bs-toggle="modal" data-bs-target="#adminModal-{{p.id}}">
<i class="fas fa-broom"></i>
</a>
@ -245,7 +245,7 @@
</li>
{% endif %}
{% if not postembed %}
{% if v and request.path.startswith('/@') and v.admin_level < 2 %}
{% if v and request.path.startswith('/@') and v.admin_level < PERMS['VIEW_VOTE_BUTTONS_ON_USER_PAGE'] %}
<li id="voting-{{p.id}}-mobile" class="voting list-inline-item d-md-none">
<span tabindex="0" role="button" onclick="vote('post-mobile', '{{p.id}}', '1')" class="post-mobile-{{p.id}}-up mx-0 pr-1 arrow-up upvote-button post-{{p.id}}-up {% if voted==1 %}active{% else %}d-none{% endif %}"></span>
@ -311,7 +311,7 @@
</script>
{% if v and v.admin_level > 1 %}
{% if v and v.admin_level >= PERMS['POST_COMMENT_MODERATION'] %}
{% include "post_admin_actions_mobile.html" %}
{% endif %}
@ -418,7 +418,7 @@
{% if v %}
{% include "delete_post_modal.html" %}
{% include "report_post_modal.html" %}
{% if v.admin_level > 1 %}
{% if v.admin_level >= PERMS['USER_BAN'] %}
{% include "ban_modal.html" %}
{% endif %}
{% endif %}

View File

@ -184,7 +184,7 @@
</div>
<div class="d-flex my-4 mx-3">
<a role="button" class="btn btn-primary ml-auto" onclick="remove_hat(this, '{{hat.name}}')">Remove</a>
{% if v.admin_level > 2 %}
{% if v.admin_level >= PERMS['MODERATE_PENDING_SUBMITTED_HATS'] %}
<a role="button" class="btn btn-primary ml-3" onclick="approve_hat(this, '{{hat.name}}')">Approve</a>
{% endif %}
</div>

View File

@ -182,7 +182,7 @@
</div>
<div class="d-flex my-4 mx-3">
<a role="button" class="btn btn-primary ml-auto" onclick="remove_marsey(this, '{{marsey.name}}')">Remove</a>
{% if v.admin_level > 2 %}
{% if v.admin_level >= PERMS['MODERATE_PENDING_SUBMITTED_MARSEYS'] %}
<a role="button" class="btn btn-primary ml-3" onclick="approve_marsey(this, '{{marsey.name}}')">Approve</a>
{% endif %}
</div>

View File

@ -29,7 +29,7 @@
<div id="profile--joined">Joined on <span id="profile--joined--time" data-time="{{u.created_utc}}"></span></div>
{% if v.admin_level >= 2 -%}
{% if v.admin_level >= PERMS['VIEW_LAST_ACTIVE'] -%}
<div id="profile--lastactive" class="mt-3">Last active on <span id="profile--lastactive--time" data-time="{{u.last_active}}"></span></div>
{%- endif %}

View File

@ -58,7 +58,7 @@
<h5 class="text-primary" id="profile--unban">{{u.unban_string}}</h5>
{% endif %}
{% endif %}
{% if v and v.admin_level >= 2 and u.shadowbanned %}
{% if v and v.admin_level >= PERMS['USER_SHADOWBAN'] and u.shadowbanned %}
<h5 class="text-primary" id="profile--shadowbanned">SHADOWBANNED USER
{% if u.ban_reason %}:
{{u.ban_reason | safe}}
@ -87,7 +87,7 @@
<span id="profile--verified"><i class="fas fa-badge-check align-middle ml-2 {% if u.verified=='Glowiefied' %}glow{% endif %}" style="color:{% if u.verifiedcolor %}#{{u.verifiedcolor}}{% else %}#1DA1F2{% endif %}" data-bs-toggle="tooltip" data-bs-placement="bottom" title="{{u.verified}}"></i></span>
{% endif %}
{% if u.admin_level > 1 %}
{% if u.admin_level >= PERMS['ADMIN_MOP_VISIBLE'] %}
<span id="profile--mop">
<i class="fas fa-broom text-admin align-middle ml-2" data-bs-toggle="tooltip" data-bs-placement="bottom" title="Admin"></i>
</span>
@ -151,7 +151,7 @@
<span id="profile--joined">joined <span id="profile--joined--time" data-bs-toggle="tooltip" data-bs-placement="bottom" onmouseover="timestamp('profile--joined--time','{{u.created_utc}}')">{{u.created_date}}</span></span>
{% if v and v.admin_level >= 2 -%}
{% if v and v.admin_level >= PERMS['VIEW_LAST_ACTIVE'] -%}
<span id="profile--lastactive" class="ml-2">last active <span id="profile--lastactive--time" data-bs-toggle="tooltip" data-bs-placement="bottom" onmouseover="timestamp('profile--lastactive--time','{{u.last_active}}')">{{u.last_active_date}}</span></span>
{%- endif %}
</div>
@ -218,16 +218,14 @@
<a class="btn btn-primary" role="button" onclick="post_toast(this,'/settings/block?username={{u.username}}',true)">Block</a>
{% if v.admin_level > 2 %}
{% if SITE != 'rdrama.net' %}
<a id="admin" class="{% if u.admin_level > 1 %}d-none{% endif %} btn btn-primary" href="javascript:void(0)" onclick="post_toast(this,'/@{{u.username}}/make_admin','admin','unadmin','d-none')">Make admin</a>
{% endif %}
<a id="unadmin" class="{% if u.admin_level < 2 %}d-none{% endif %} btn btn-primary" href="javascript:void(0)" onclick="post_toast(this,'/@{{u.username}}/remove_admin','admin','unadmin','d-none')">Remove admin</a>
{% if u.admin_level > 1 %}
<a class="btn btn-primary" role="button" onclick="post_toast(this,'/@{{u.username}}/revert_actions')">Revert admin actions</a>
{% endif %}
{% if v.admin_level >= PERMS['ADMIN_ADD'] and SITE != 'rdrama.net' %}
<a id="admin" class="{% if u.admin_level >= PERMS['ADMIN_ADD_PERM_LEVEL'] %}d-none{% endif %} btn btn-primary" href="javascript:void(0)" onclick="post_toast(this,'/@{{u.username}}/make_admin','admin','unadmin','d-none')">Make admin</a>
{% endif %}
{% if v.admin_level >= PERMS['ADMIN_REMOVE'] %}
<a id="unadmin" class="{% if u.admin_level < 1 %}d-none{% endif %} btn btn-primary" href="javascript:void(0)" onclick="post_toast(this,'/@{{u.username}}/remove_admin','admin','unadmin','d-none')">Remove admin</a>
{% endif %}
{% if v.admin_level >= PERMS['ADMIN_ACTIONS_REVERT'] %}
<a class="btn btn-primary" role="button" onclick="post_toast(this,'/@{{u.username}}/revert_actions')">Revert admin actions</a>
{% endif %}
</div>
@ -272,9 +270,10 @@
<a class="btn btn-secondary" role="button" onclick="toggle()">Toggle anthem</a>
{% endif %}
{% if v and v.id != u.id and v.admin_level > 1 %}
{% if v and v.id != u.id and v.admin_level >= PERMS['USER_MODERATION_TOOLS_VISIBLE'] %}
<br><br>
<div class="body d-lg-flex border-bottom">
{% if v.admin_level >= PERMS['USER_TITLE_CHANGE'] %}
<div class="w-lg-100">
<form action="/admin/title_change/{{u.id}}" method="post">
@ -292,86 +291,88 @@
</div>
</form>
</div>
{% endif %}
</div>
<pre></pre>
<pre></pre>
{% if u.is_suspended %}
<form action="/unban_user/{{u.id}}" method="post" action="">
<input type="hidden" name="formkey" value="{{v.formkey}}">
<input type="hidden" name="redir" value="true">
<input type="submit" onclick="disable(this)" class="btn btn-success" value="Unban user">
</form>
{% else %}
<form action="/ban_user/{{u.id}}" method="post" action="">
<input type="hidden" name="formkey" value="{{v.formkey}}">
<input type="hidden" name="redir" value="true">
<input autocomplete="off" style="font-size:11px" type="text" class="form-control" maxlength="256" name="reason" placeholder="Ban Reason" oninput="document.getElementById('user-ban-submit').disabled=false" required>
<input autocomplete="off" style="font-size:11px" type="number" step="any" class="form-control" name="days" placeholder="Days (blank = permanent)">
<div class="custom-control custom-checkbox mb-1">
<input autocomplete="off" type="checkbox" id="alts-2-desktop" class="custom-control-input" name="alts" value="1">
<label class="custom-control-label" for="alts-2-desktop">Include alts</label>
</div>
<input autocomplete="off" id="user-ban-submit" type="submit" onclick="disable(this)" class="btn btn-danger" value="Ban user" disabled>
</form>
{% if v.admin_level >= PERMS['USER_BAN'] %}
{% if u.is_suspended %}
<form action="/unban_user/{{u.id}}" method="post" action="">
<input type="hidden" name="formkey" value="{{v.formkey}}">
<input type="hidden" name="redir" value="true">
<input type="submit" onclick="disable(this)" class="btn btn-success" value="Unban user">
</form>
{% else %}
<form action="/ban_user/{{u.id}}" method="post" action="">
<input type="hidden" name="formkey" value="{{v.formkey}}">
<input type="hidden" name="redir" value="true">
<input autocomplete="off" style="font-size:11px" type="text" class="form-control" maxlength="256" name="reason" placeholder="Ban Reason" oninput="document.getElementById('user-ban-submit').disabled=false" required>
<input autocomplete="off" style="font-size:11px" type="number" step="any" class="form-control" name="days" placeholder="Days (blank = permanent)">
<div class="custom-control custom-checkbox mb-1">
<input autocomplete="off" type="checkbox" id="alts-2-desktop" class="custom-control-input" name="alts" value="1">
<label class="custom-control-label" for="alts-2-desktop">Include alts</label>
</div>
<input autocomplete="off" id="user-ban-submit" type="submit" onclick="disable(this)" class="btn btn-danger" value="Ban user" disabled>
</form>
{% endif %}
{% endif %}
<pre></pre>
<pre></pre>
{% if u.shadowbanned %}
<form action="/unshadowban/{{u.id}}" method="post" action="">
<input type="hidden" name="formkey" value="{{v.formkey}}">
<input type="submit" onclick="disable(this)" class="btn btn-success" value="Unshadowban user">
</form>
{% else %}
<form action="/shadowban/{{u.id}}" method="post" action="">
<input type="hidden" name="formkey" value="{{v.formkey}}">
<input autocomplete="off" style="font-size:11px" type="text" class="form-control" maxlength="256" name="reason" placeholder="Shadowban Reason" oninput="document.getElementById('user-shadowban-submit').disabled=false" required>
<div class="custom-control custom-checkbox mb-1">
{% if v.admin_level >= PERMS['USER_SHADOWBAN'] %}
{% if u.shadowbanned %}
<form action="/unshadowban/{{u.id}}" method="post" action="">
<input type="hidden" name="formkey" value="{{v.formkey}}">
<input type="submit" onclick="disable(this)" class="btn btn-success" value="Unshadowban user">
</form>
{% else %}
<form action="/shadowban/{{u.id}}" method="post" action="">
<input type="hidden" name="formkey" value="{{v.formkey}}">
<input autocomplete="off" style="font-size:11px" type="text" class="form-control" maxlength="256" name="reason" placeholder="Shadowban Reason" oninput="document.getElementById('user-shadowban-submit').disabled=false" required>
<div class="custom-control custom-checkbox mb-1">
<input autocomplete="off" type="checkbox" id="shadowban-alts-2-desktop" class="custom-control-input" name="alts" value="1">
<label class="custom-control-label" for="shadowban-alts-2-desktop">Include alts</label>
</div>
<input autocomplete="off" id="user-shadowban-submit" type="submit" onclick="disable(this)" class="btn btn-danger" value="Shadowban user" disabled>
</div>
<input autocomplete="off" id="user-shadowban-submit" type="submit" onclick="disable(this)" class="btn btn-danger" value="Shadowban user" disabled>
</form>
{% endif %}
{% endif %}
<pre></pre>
<pre></pre>
{% if v and v.admin_level >= PERMS['USER_AGENDAPOSTER'] %}
<form id="agendaposter1" class="{% if u.agendaposter %}d-none{% endif %}" action="/agendaposter/{{u.id}}" method="post">
<input type="hidden" name="formkey", value="{{v.formkey}}">
<input autocomplete="off" type="number" step="any" name="days" class="form-control" placeholder="Days (0 or blank = permanent)">
<input type="submit" onclick="disable(this)" class="btn btn-danger" value="Lock Chud Theme">
</form>
<pre></pre>
<a id="unagendaposter" class="{% if not u.agendaposter %}d-none{% endif %} btn btn-success" role="button" onclick="post_toast(this,'/unagendaposter/{{u.id}}','agendaposter1','unagendaposter','d-none')">Disable Chud Theme</a>
{% endif %}
<pre></pre>
{% if v and v.admin_level >= PERMS['USER_BAN']}
<a id="mute-user" class="{% if u.is_muted %}d-none{% endif %} btn btn-danger" role="button" onclick="post_toast(this,'/mute_user/{{u.id}}/1','mute-user','unmute-user','d-none')">Mute</a>
<a id="unmute-user" class="{% if not u.is_muted %}d-none{% endif %} btn btn-success" role="button" onclick="post_toast(this,'/mute_user/{{u.id}}/0','mute-user','unmute-user','d-none')">Unmute</a>
{% endif %}
<pre></pre>
{% if v and v.admin_level >= PERMS['POST_COMMENT_MODERATION'] %}
<form action="/admin/unnuke_user" method="post">
<input type="hidden" name="formkey", value="{{v.formkey}}">
<input type="hidden" name="user" value="{{u.username}}">
<input type="submit" onclick="disable(this)" class="btn btn-success" value="Approve User's Content">
</form>
<pre></pre>
<form action="/admin/nuke_user" method="post">
<input type="hidden" name="formkey", value="{{v.formkey}}">
<input type="hidden" name="user" value="{{u.username}}">
<input type="submit" onclick="disable(this)" class="btn btn-danger" value="Remove User's Content">
</form>
{% endif %}
<pre></pre>
<pre></pre>
<form id="agendaposter1" class="{% if u.agendaposter %}d-none{% endif %}" action="/agendaposter/{{u.id}}" method="post">
<input type="hidden" name="formkey", value="{{v.formkey}}">
<input autocomplete="off" type="number" step="any" name="days" class="form-control" placeholder="Days (0 or blank = permanent)">
<input type="submit" onclick="disable(this)" class="btn btn-danger" value="Lock Chud Theme">
</form>
<pre></pre>
<a id="unagendaposter" class="{% if not u.agendaposter %}d-none{% endif %} btn btn-success" role="button" onclick="post_toast(this,'/unagendaposter/{{u.id}}','agendaposter1','unagendaposter','d-none')">Disable Chud Theme</a>
<pre></pre>
<a id="mute-user" class="{% if u.is_muted %}d-none{% endif %} btn btn-danger" role="button" onclick="post_toast(this,'/mute_user/{{u.id}}/1','mute-user','unmute-user','d-none')">Mute</a>
<a id="unmute-user" class="{% if not u.is_muted %}d-none{% endif %} btn btn-success" role="button" onclick="post_toast(this,'/mute_user/{{u.id}}/0','mute-user','unmute-user','d-none')">Unmute</a>
<pre></pre>
<form action="/admin/unnuke_user" method="post">
<input type="hidden" name="formkey", value="{{v.formkey}}">
<input type="hidden" name="user" value="{{u.username}}">
<input type="submit" onclick="disable(this)" class="btn btn-success" value="Approve User's Content">
</form>
<pre></pre>
<form action="/admin/nuke_user" method="post">
<input type="hidden" name="formkey", value="{{v.formkey}}">
<input type="hidden" name="user" value="{{u.username}}">
<input type="submit" onclick="disable(this)" class="btn btn-danger" value="Remove User's Content">
</form>
<pre></pre>
{% if FEATURES['COUNTRY_CLUB'] -%}
<button id="grant2" class="{% if u.paid_dues %}d-none{% endif %} btn btn-success" onclick="post_toast(this,'/@{{u.username}}/club_allow','grant2','bar2','d-none')">Grant club access</button>
<button id="bar2" class="{% if u.club_allowed == False %}d-none{% endif %} btn btn-danger" onclick="post_toast(this,'/@{{u.username}}/club_ban','grant2','bar2','d-none')">Bar from club</button>
{%- endif %}
{% if FEATURES['COUNTRY_CLUB'] and v and v.admin_level >= PERMS['USER_CLUB_ALLOW_BAN'] %}
<pre></pre>
<button id="grant2" class="{% if u.paid_dues %}d-none{% endif %} btn btn-success" onclick="post_toast(this,'/@{{u.username}}/club_allow','grant2','bar2','d-none')">Grant club access</button>
<button id="bar2" class="{% if u.club_allowed == False %}d-none{% endif %} btn btn-danger" onclick="post_toast(this,'/@{{u.username}}/club_ban','grant2','bar2','d-none')">Bar from club</button>
{% endif %}
{% endif %}
<pre></pre>
<div id="profile--info">
<p id="profile--info--id">User ID: {{u.id}}</p>
@ -379,9 +380,9 @@
<p id="profile--info--truescore">True score: {{u.truecoins}}</p>
<p id="profile--info--winnings">Winnings: {{u.winnings}}</p>
{% if u.is_private %}
<p id="profile--info--private">User has private mode enabled.</p>
<p id="profile--info--private">User has private mode enabled</p>
{% endif %}
{% if v and (v.admin_level > 1 or v.alt) %}
{% if v and (v.admin_level >= PERMS['VIEW_ALTS'] or v.alt) %}
<span id="profile--alts">Alts:</span>
<ul id="profile--alts-list">
{% for account in u.alts_unique %}
@ -440,7 +441,7 @@
{% if u.unban_utc %}<h5 class="text-primary" id="profile-mobile--unban">{{u.unban_string}}</h5>{% endif %}
{% endif %}
{% if v and v.admin_level >= 2 and u.shadowbanned %}
{% if v and v.admin_level >= PERMS['USER_SHADOWBAN'] and u.shadowbanned %}
<h5 class="text-primary" id="profile-mobile--banned">SHADOWBANNED USER{% if u.ban_reason %}: {{u.ban_reason | safe}}{% endif %} (by <a href="/@{{u.shadowbanned}}">@{{u.shadowbanned}}</a>)</h5>
{% endif %}
@ -464,7 +465,7 @@
<span id="profile-mobile--verified"><i class="fas fa-badge-check align-middle ml-2 {% if u.verified=='Glowiefied' %}glow{% endif %}" style="color:{% if u.verifiedcolor %}#{{u.verifiedcolor}}{% else %}#1DA1F2{% endif %}" data-bs-toggle="tooltip" data-bs-placement="bottom" title="{{u.verified}}"></i></span>&nbsp;
{% endif %}
{% if u.admin_level > 1 %}
{% if u.admin_level >= PERMS['ADMIN_MOP_VISIBLE'] %}
<span id="profile-mobile--mop">
<i class="fas fa-broom text-admin align-middle ml-1" data-bs-toggle="tooltip" data-bs-placement="bottom" title="Admin"></i>
</span>
@ -508,7 +509,7 @@
<br><span id="profile-mobile--joined">joined <span id="profile-mobile--joined--time" data-bs-toggle="tooltip" data-bs-placement="bottom" onmouseover="timestamp('profile-mobile--joined--time','{{u.created_utc}}')" class="font-weight-bold">{{u.created_date}}</span></span>
{% if v and v.admin_level >= 2 -%}
{% if v and v.admin_level >= PERMS['VIEW_LAST_ACTIVE'] -%}
<br><span id="profile-mobile--lastactive">last active <span id="profile-mobile--lastactive--time" data-bs-toggle="tooltip" data-bs-placement="bottom" onmouseover="timestamp('profile-mobile--lastactive--time','{{u.last_active}}')" class="font-weight-bold">{{u.last_active_date}}</span></span>
{%- endif %}
</div>
@ -587,16 +588,16 @@
<a class="btn btn-primary" role="button" onclick="post_toast(this,'/settings/block?username={{u.username}}',true)">Block</a>
{% if v.admin_level > 2 %}
{% if SITE != 'rdrama.net' %}
<a id="admin2" class="{% if u.admin_level > 1 %}d-none{% endif %} btn btn-primary" href="javascript:void(0)" onclick="post_toast(this,'/@{{u.username}}/make_admin','admin2','unadmin2','d-none')">Make admin</a>
{% endif %}
{% if v.admin_level >= PERMS['ADMIN_ADD'] and SITE != 'rdrama.net' %}
<a id="admin2" class="{% if u.admin_level >= PERMS['ADMIN_ADD_PERM_LEVEL'] %}d-none{% endif %} btn btn-primary" href="javascript:void(0)" onclick="post_toast(this,'/@{{u.username}}/make_admin','admin2','unadmin2','d-none')">Make admin</a>
{% endif %}
<a id="unadmin2" class="{% if u.admin_level < 2 %}d-none{% endif %} btn btn-primary" href="javascript:void(0)" onclick="post_toast(this,'/@{{u.username}}/remove_admin','admin2','unadmin2','d-none')">Remove admin</a>
{% if v.admin_level >= PERMS['ADMIN_REMOVE'] %}
<a id="unadmin2" class="{% if u.admin_level < 1 %}d-none{% endif %} btn btn-primary" href="javascript:void(0)" onclick="post_toast(this,'/@{{u.username}}/remove_admin','admin2','unadmin2','d-none')">Remove admin</a>
{% endif %}
{% if u.admin_level > 1 %}
<a class="btn btn-primary" role="button" onclick="post_toast(this,'/@{{u.username}}/revert_actions')">Revert admin actions</a>
{% endif %}
{% if v.admin_level >= PERMS['ADMIN_ACTIONS_REVERT'] %}
<a class="btn btn-primary" role="button" onclick="post_toast(this,'/@{{u.username}}/revert_actions')">Revert admin actions</a>
{% endif %}
<form class="d-none toggleable" id='message-mobile' action="/@{{u.username}}/message" onsubmit="submitFormAjax(event)">
@ -631,105 +632,107 @@
<button class="btn btn-primary mt-2 mb-3" onclick="transferBux(true)">Gift</button>
</div>
{% if v.admin_level > 1 %}
{% if v and v.admin_level >= PERMS['USER_MODERATION_TOOLS_VISIBLE'] %}
{% if FEATURES['COUNTRY_CLUB'] -%}
<button id="grant" class="{% if u.paid_dues %}d-none{% endif %} btn btn-success" onclick="post_toast(this,'/@{{u.username}}/club_allow','grant','bar','d-none')">Grant club access</button>
<button id="bar" class="{% if u.club_allowed == False %}d-none{% endif %} btn btn-danger" onclick="post_toast(this,'/@{{u.username}}/club_ban','grant','bar','d-none')">Bar from club</button>
{%- endif %}
{% if FEATURES['COUNTRY_CLUB'] and v.admin_level >= PERMS['USER_CLUB_ALLOW_BAN'] -%}
<button id="grant" class="{% if u.paid_dues %}d-none{% endif %} btn btn-success" onclick="post_toast(this,'/@{{u.username}}/club_allow','grant','bar','d-none')">Grant club access</button>
<button id="bar" class="{% if u.club_allowed == False %}d-none{% endif %} btn btn-danger" onclick="post_toast(this,'/@{{u.username}}/club_ban','grant','bar','d-none')">Bar from club</button>
{%- endif %}
<br><br>
<div class="body d-lg-flex border-bottom">
<div class="w-lg-100">
<form action="/admin/title_change/{{u.id}}" method="post">
<input type="hidden" name="formkey" value="{{v.formkey}}">
<input maxlength=100 autocomplete="off" id="customtitlebody-mobile" type="text" name="title" class="form-control" placeholder='Enter a flair here' value="{% if u.customtitleplain %}{{u.customtitleplain}}{% endif %}">
<div class="d-flex mt-2">
<a class="format" role="button"><i class="btn btn-secondary format d-inline-block m-0 fas fa-smile-beam" onclick="loadEmojis('customtitlebody-mobile')" aria-hidden="true" data-bs-toggle="modal" data-bs-target="#emojiModal" data-bs-toggle="tooltip" data-bs-placement="bottom" title="Add Emoji"></i></a>
&nbsp;&nbsp;&nbsp;
<div class="custom-control custom-checkbox">
<input autocomplete="off" type="checkbox" class="custom-control-input" id="locked-mobile" name="locked" {% if u.flairchanged %}checked{% endif %}>
<label class="custom-control-label" for="locked-mobile">locked</label>
{% if v.admin_level >= PERMS['USER_TITLE_CHANGE'] %}
<div class="w-lg-100">
<form action="/admin/title_change/{{u.id}}" method="post">
<input type="hidden" name="formkey" value="{{v.formkey}}">
<input maxlength=100 autocomplete="off" id="customtitlebody-mobile" type="text" name="title" class="form-control" placeholder='Enter a flair here' value="{% if u.customtitleplain %}{{u.customtitleplain}}{% endif %}">
<div class="d-flex mt-2">
<a class="format" role="button"><i class="btn btn-secondary format d-inline-block m-0 fas fa-smile-beam" onclick="loadEmojis('customtitlebody-mobile')" aria-hidden="true" data-bs-toggle="modal" data-bs-target="#emojiModal" data-bs-toggle="tooltip" data-bs-placement="bottom" title="Add Emoji"></i></a>
&nbsp;&nbsp;&nbsp;
<div class="custom-control custom-checkbox">
<input autocomplete="off" type="checkbox" class="custom-control-input" id="locked-mobile" name="locked" {% if u.flairchanged %}checked{% endif %}>
<label class="custom-control-label" for="locked-mobile">locked</label>
</div>
&nbsp;&nbsp;&nbsp;
<input autocomplete="off" class="btn btn-primary ml-auto" type="submit" onclick="disable(this)" value="Change Flair">
</div>
&nbsp;&nbsp;&nbsp;
<input autocomplete="off" class="btn btn-primary ml-auto" type="submit" onclick="disable(this)" value="Change Flair">
</div>
</form>
</div>
</form>
</div>
{% endif %}
</div>
<pre></pre>
<pre></pre>
{% if u.is_suspended %}
<form action="/unban_user/{{u.id}}" method="post">
<input type="hidden" name="formkey", value="{{v.formkey}}">
<input type="hidden" name="redir" value="true">
<input type="submit" onclick="disable(this)" class="btn btn-success" value="Unban user">
</form>
{% else %}
<form action="/ban_user/{{u.id}}" method="post">
<input type="hidden" name="formkey" value="{{v.formkey}}">
<input type="hidden" name="redir" value="true">
<input autocomplete="off" style="font-size:11px" type="text" class="form-control" maxlength="256" name="reason" placeholder="Ban Reason" oninput="document.getElementById('user-ban-submit2').disabled=false" required>
<input autocomplete="off" style="font-size:11px" type="number" step="any" class="form-control" name="days" placeholder="Days (blank = permanent)">
<div class="custom-control custom-checkbox mb-1">
<input autocomplete="off" type="checkbox" id="alts-2-mobile" class="custom-control-input" name="alts" value="1">
<label class="custom-control-label" for="alts-2-mobile">Include alts</label>
</div>
<input autocomplete="off" id="user-ban-submit2" type="submit" onclick="disable(this)" class="btn btn-danger" value="Ban user" disabled>
</form>
{% if v.admin_level >= PERMS['USER_BAN']}
{% if u.is_suspended %}
<form action="/unban_user/{{u.id}}" method="post">
<input type="hidden" name="formkey", value="{{v.formkey}}">
<input type="hidden" name="redir" value="true">
<input type="submit" onclick="disable(this)" class="btn btn-success" value="Unban user">
</form>
{% else %}
<form action="/ban_user/{{u.id}}" method="post">
<input type="hidden" name="formkey" value="{{v.formkey}}">
<input type="hidden" name="redir" value="true">
<input autocomplete="off" style="font-size:11px" type="text" class="form-control" maxlength="256" name="reason" placeholder="Ban Reason" oninput="document.getElementById('user-ban-submit2').disabled=false" required>
<input autocomplete="off" style="font-size:11px" type="number" step="any" class="form-control" name="days" placeholder="Days (blank = permanent)">
<div class="custom-control custom-checkbox mb-1">
<input autocomplete="off" type="checkbox" id="alts-2-mobile" class="custom-control-input" name="alts" value="1">
<label class="custom-control-label" for="alts-2-mobile">Include alts</label>
</div>
<input autocomplete="off" id="user-ban-submit2" type="submit" onclick="disable(this)" class="btn btn-danger" value="Ban user" disabled>
</form>
{% endif %}
{% endif %}
<pre></pre>
<pre></pre>
{% if u.shadowbanned %}
<form action="/unshadowban/{{u.id}}" method="post">
<input type="hidden" name="formkey", value="{{v.formkey}}">
<input type="submit" onclick="disable(this)" class="btn btn-success" value="Unshadowban user">
</form>
{% else %}
<form action="/shadowban/{{u.id}}" method="post">
<input type="hidden" name="formkey" value="{{v.formkey}}">
<input autocomplete="off" style="font-size:11px" type="text" class="form-control" maxlength="256" name="reason" placeholder="Shadowban Reason" oninput="document.getElementById('user-shadowban-submit2').disabled=false" required>
<div class="custom-control custom-checkbox mb-1">
<input autocomplete="off" type="checkbox" id="shadowban-alts-2-mobile" class="custom-control-input" name="alts" value="1">
<label class="custom-control-label" for="shadowban-alts-2-mobile">Include alts</label>
</div>
<input autocomplete="off" id="user-shadowban-submit2" type="submit" onclick="disable(this)" class="btn btn-danger" value="Shadowban user" disabled>
</form>
{% if v.admin_level >= PERMS['USER_SHADOWBAN']}
{% if u.shadowbanned %}
<form action="/unshadowban/{{u.id}}" method="post">
<input type="hidden" name="formkey", value="{{v.formkey}}">
<input type="submit" onclick="disable(this)" class="btn btn-success" value="Unshadowban user">
</form>
{% else %}
<form action="/shadowban/{{u.id}}" method="post">
<input type="hidden" name="formkey" value="{{v.formkey}}">
<input autocomplete="off" style="font-size:11px" type="text" class="form-control" maxlength="256" name="reason" placeholder="Shadowban Reason" oninput="document.getElementById('user-shadowban-submit2').disabled=false" required>
<div class="custom-control custom-checkbox mb-1">
<input autocomplete="off" type="checkbox" id="shadowban-alts-2-mobile" class="custom-control-input" name="alts" value="1">
<label class="custom-control-label" for="shadowban-alts-2-mobile">Include alts</label>
</div>
<input autocomplete="off" id="user-shadowban-submit2" type="submit" onclick="disable(this)" class="btn btn-danger" value="Shadowban user" disabled>
</form>
{% endif %}
{% endif %}
<pre></pre>
<pre></pre>
<form id="agendaposter2" class="{% if u.agendaposter %}d-none{% endif %}" action="/agendaposter/{{u.id}}" method="post">
<input type="hidden" name="formkey", value="{{v.formkey}}">
<input autocomplete="off" type="number" step="any" name="days" class="form-control" placeholder="Days (0 or blank = permanent)">
<input type="submit" onclick="disable(this)" class="btn btn-danger" value="Lock Chud Theme">
</form>
{% if v.admin_level >= PERMS['USER_AGENDAPOSTER'] %}
<form id="agendaposter2" class="{% if u.agendaposter %}d-none{% endif %}" action="/agendaposter/{{u.id}}" method="post">
<input type="hidden" name="formkey", value="{{v.formkey}}">
<input autocomplete="off" type="number" step="any" name="days" class="form-control" placeholder="Days (0 or blank = permanent)">
<input type="submit" onclick="disable(this)" class="btn btn-danger" value="Lock Chud Theme">
</form>
<pre></pre>
<a id="unagendaposter2" class="{% if not u.agendaposter %}d-none{% endif %} btn btn-success" role="button" onclick="post_toast(this,'/unagendaposter/{{u.id}}','agendaposter2','unagendaposter2','d-none')">Disable Chud Theme</a>
<pre></pre>
{% endif %}
{% if v.admin_level >= PERMS['USER_BAN'] %}
<a id="mute-user2" class="{% if u.is_muted %}d-none{% endif %} btn btn-danger" role="button" onclick="post_toast(this,'/mute_user/{{u.id}}/1','mute-user2','unmute-user2','d-none')">Mute</a>
<a id="unmute-user2" class="{% if not u.is_muted %}d-none{% endif %} btn btn-success" role="button" onclick="post_toast(this,'/mute_user/{{u.id}}/0','mute-user2','unmute-user2','d-none')">Unmute</a>
{% endif %}
<pre></pre>
<a id="unagendaposter2" class="{% if not u.agendaposter %}d-none{% endif %} btn btn-success" role="button" onclick="post_toast(this,'/unagendaposter/{{u.id}}','agendaposter2','unagendaposter2','d-none')">Disable Chud Theme</a>
<pre></pre>
<a id="mute-user2" class="{% if u.is_muted %}d-none{% endif %} btn btn-danger" role="button" onclick="post_toast(this,'/mute_user/{{u.id}}/1','mute-user2','unmute-user2','d-none')">Mute</a>
<a id="unmute-user2" class="{% if not u.is_muted %}d-none{% endif %} btn btn-success" role="button" onclick="post_toast(this,'/mute_user/{{u.id}}/0','mute-user2','unmute-user2','d-none')">Unmute</a>
<pre></pre>
<form action="/admin/unnuke_user" method="post">
<input type="hidden" name="formkey", value="{{v.formkey}}">
<input type="hidden" name="user" value="{{u.username}}">
<input type="submit" onclick="disable(this)" class="btn btn-success" value="Approve User's Content">
</form>
<pre></pre>
<form action="/admin/nuke_user" method="post">
<input type="hidden" name="formkey", value="{{v.formkey}}">
<input type="hidden" name="user" value="{{u.username}}">
<input type="submit" onclick="disable(this)" class="btn btn-danger" value="Remove User's Content">
</form>
{% if v.admin_level >= PERMS['POST_COMMENT_MODERATION'] %}
<form action="/admin/unnuke_user" method="post">
<input type="hidden" name="formkey", value="{{v.formkey}}">
<input type="hidden" name="user" value="{{u.username}}">
<input type="submit" onclick="disable(this)" class="btn btn-success" value="Approve User's Content">
</form>
<pre></pre>
<form action="/admin/nuke_user" method="post">
<input type="hidden" name="formkey", value="{{v.formkey}}">
<input type="hidden" name="user" value="{{u.username}}">
<input type="submit" onclick="disable(this)" class="btn btn-danger" value="Remove User's Content">
</form>
{% endif %}
{% endif %}
{% endif %}
<pre></pre>
@ -739,9 +742,9 @@
<p id="profile-mobile--info--truescore">True score: {{u.truecoins}}</p>
<p id="profile-mobile--info--winnings">Winnings: {{u.winnings}}</p>
{% if u.is_private %}
<p id="profile-mobile--info--private">User has private mode enabled.</p>
<p id="profile-mobile--info--private">User has private mode enabled</p>
{% endif %}
{% if v and (v.admin_level > 1 or v.alt) %}
{% if v and (v.admin_level >= PERMS['VIEW_ALTS'] or v.alt) %}
<span id="profile-mobile--alts">Alts:</span>
<ul id="profile-mobile--alts-list">
{% for account in u.alts_unique %}