add jl5 (for me)

pull/90/head
Aevann 2023-01-22 10:04:49 +02:00
parent 75cb26ccf4
commit 24edb49f3b
17 changed files with 244 additions and 264 deletions

View File

@ -320,7 +320,7 @@ class User(Base):
@lazy @lazy
def mods(self, sub): def mods(self, sub):
if self.is_suspended_permanently or self.shadowbanned: return False if self.is_suspended_permanently or self.shadowbanned: return False
if self.id in {AEVANN_ID}: return True if self.admin_level >= PERMS['MODS_EVERY_HOLE']: return True
try: try:
return any(map(lambda x: x.sub == sub, self.sub_mods)) return any(map(lambda x: x.sub == sub, self.sub_mods))
except: except:

View File

@ -377,28 +377,27 @@ def execute_blackjack(v, target, body, type):
elif hasattr(target, 'is_banned'): elif hasattr(target, 'is_banned'):
target.is_banned = True target.is_banned = True
if CARP_ID and AEVANN_ID: notified_ids = [x[0] for x in g.db.query(User.id).filter(User.admin_level >= PERMS['BLACKJACK_NOTIFICATIONS'])]
extra_info = "unknown entity" extra_info = "unknown entity"
if type == 'submission': if type == 'submission':
extra_info = target.permalink extra_info = target.permalink
elif type == 'chat': elif type == 'chat':
extra_info = "chat message" extra_info = "chat message"
elif type == 'flag': elif type == 'flag':
extra_info = f"reports on {target.permalink}" extra_info = f"reports on {target.permalink}"
elif type == 'modmail': elif type == 'modmail':
extra_info = "modmail" extra_info = "modmail"
elif type in {'comment', 'message'}: elif type in {'comment', 'message'}:
for id in (CARP_ID, AEVANN_ID): for id in notified_ids:
n = Notification(comment_id=target.id, user_id=id) n = Notification(comment_id=target.id, user_id=id)
g.db.add(n) g.db.add(n)
g.db.flush() g.db.flush()
extra_info = None extra_info = None
if extra_info: if extra_info:
for id in (CARP_ID, AEVANN_ID): for id in notified_ids:
send_repeatable_notification(id, f"Blackjack for @{v.username}: {extra_info}") send_repeatable_notification(id, f"Blackjack for @{v.username}: {extra_info}")
return False
return True return True
def execute_antispam_duplicate_comment_check(v:User, body_html:str): def execute_antispam_duplicate_comment_check(v:User, body_html:str):

View File

@ -397,77 +397,78 @@ SUB_MARSEY_URL_LENGTH = 60
################################################################################ ################################################################################
PERMS = { # Minimum admin_level to perform action. PERMS = { # Minimum admin_level to perform action.
'ADMIN_ADD': 3, 'CHAT': 0,
'ADMIN_REMOVE': 3, 'HOLE_CREATE': 0,
'ADMIN_ADD_PERM_LEVEL': 2, # permission level given when user added via site 'USER_BLOCKS_VISIBLE': 0,
'ADMIN_ACTIONS_REVERT': 3, 'USER_FOLLOWS_VISIBLE': 0,
'ADMIN_MOP_VISIBLE': 2, 'USER_VOTERS_VISIBLE': 0,
'ADMIN_HOME_VISIBLE': 2, 'POST_COMMENT_INFINITE_PINGS': 1,
'CHAT': 0, 'POST_COMMENT_DISTINGUISH': 1,
'CHAT_BYPASS_MUTE': 2, 'POST_BYPASS_REPOST_CHECKING': 1,
'DOMAINS_BAN': 3, 'POST_IN_GHOST_THREADS': 1,
'HOLE_CREATE': 0, 'POST_TO_CHANGELOG': 1,
'EDIT_RULES': 3, 'VIEW_CLUB': 1,
'FLAGS_REMOVE': 2, 'VIEW_CHUDRAMA': 1,
'USER_BLOCKS_VISIBLE': 0, 'SITE_BYPASS_READ_ONLY_MODE': 1,
'USER_FOLLOWS_VISIBLE': 0, 'SITE_BYPASS_UNDER_SIEGE_MODE': 1,
'USER_VOTERS_VISIBLE': 0, 'SITE_WARN_ON_INVALID_AUTH': 1,
'POST_COMMENT_INFINITE_PINGS': 1, 'NOTIFICATIONS_REDDIT': 1,
'POST_COMMENT_MODERATION': 2, 'NOTIFICATIONS_SPECIFIC_WPD_COMMENTS': 1,
'POST_COMMENT_DISTINGUISH': 1, 'MESSAGE_BLOCKED_USERS': 1,
'POST_COMMENT_MODERATION_TOOLS_VISIBLE': 2, # note: does not affect API at all 'ADMIN_ADD_PERM_LEVEL': 2,
'POST_BYPASS_REPOST_CHECKING': 1, 'ADMIN_MOP_VISIBLE': 2,
'POST_EDITING': 4, 'ADMIN_HOME_VISIBLE': 2,
'USER_BADGES': 2, 'CHAT_BYPASS_MUTE': 2,
'USER_BAN': 2, 'FLAGS_REMOVE': 2,
'USER_SHADOWBAN': 2, 'POST_COMMENT_MODERATION': 2,
'USER_AGENDAPOSTER': 2, 'POST_COMMENT_MODERATION_TOOLS_VISIBLE': 2,
'USER_LINK': 2, 'USER_BADGES': 2,
'USER_MERGE': 3, # note: extra check for Aevann 'USER_BAN': 2,
'USER_TITLE_CHANGE': 2, 'USER_SHADOWBAN': 2,
'USER_MODERATION_TOOLS_VISIBLE': 2, # note: does not affect API at all 'USER_AGENDAPOSTER': 2,
'POST_IN_GHOST_THREADS': 1, 'USER_LINK': 2,
'POST_TO_CHANGELOG': 1, # note: code contributors can also post to changelog 'USER_TITLE_CHANGE': 2,
'POST_TO_POLL_THREAD': 2, 'USER_MODERATION_TOOLS_VISIBLE': 2,
'POST_BETS': 3, 'POST_TO_POLL_THREAD': 2,
'POST_BETS_DISTRIBUTE': 3, # probably should be the same as POST_BETS but w/e 'BUY_GHOST_AWARD': 2,
'VIEW_PENDING_SUBMITTED_MARSEYS': 3, 'LOTTERY_VIEW_PARTICIPANTS': 2,
'VIEW_PENDING_SUBMITTED_HATS': 3, 'VIEW_MODMAIL': 2,
'MODERATE_PENDING_SUBMITTED_MARSEYS': 3, # note: there is an extra check so that only """carp""" can approve them 'VIEW_PRIVATE_PROFILES': 2,
'MODERATE_PENDING_SUBMITTED_HATS': 3, # note: there is an extra check so that only """carp""" can approve them 'VIEW_ALTS': 2,
'UPDATE_MARSEYS': 3, # note: extra check is here for 4 different users 'VIEW_ACTIVE_USERS': 2,
'UPDATE_HATS': 3, # note: extra check is here for 4 different users 'VIEW_ALT_VOTES': 2,
'BUY_GHOST_AWARD': 2, 'VIEW_LAST_ACTIVE': 2,
'LOTTERY_ADMIN': 3, 'VIEW_VOTE_BUTTONS_ON_USER_PAGE': 2,
'LOTTERY_VIEW_PARTICIPANTS': 2, 'NOTIFICATIONS_ADMIN_PING': 2,
'VIEW_MODMAIL': 2, 'NOTIFICATIONS_HOLE_INACTIVITY_DELETION': 2,
'VIEW_CLUB': 1, 'NOTIFICATIONS_HOLE_CREATION': 2,
'VIEW_CHUDRAMA': 1, 'NOTIFICATIONS_MODERATOR_ACTIONS': 2,
'VIEW_PRIVATE_PROFILES': 2, 'ADMIN_ADD': 3,
'VIEW_ALTS': 2, 'ADMIN_REMOVE': 3,
'VIEW_ACTIVE_USERS': 2, 'ADMIN_ACTIONS_REVERT': 3,
'VIEW_ALT_VOTES': 2, 'DOMAINS_BAN': 3,
'VIEW_LAST_ACTIVE': 2, 'EDIT_RULES': 3,
'VIEW_PATRONS': 3, # note: extra check for Aevann, carp, or snakes 'POST_BETS': 3,
'VIEW_VOTE_BUTTONS_ON_USER_PAGE': 2, 'POST_BETS_DISTRIBUTE': 3,
'SITE_BYPASS_READ_ONLY_MODE': 1, 'VIEW_PENDING_SUBMITTED_MARSEYS': 3,
'SITE_BYPASS_UNDER_SIEGE_MODE': 1, 'VIEW_PENDING_SUBMITTED_HATS': 3,
'SITE_SETTINGS': 3, 'LOTTERY_ADMIN': 3,
'SITE_SETTINGS_SIDEBARS_BANNERS_BADGES': 3, 'SITE_SETTINGS': 3,
'SITE_SETTINGS_SNAPPY_QUOTES': 3, 'SITE_SETTINGS_SIDEBARS_BANNERS_BADGES': 3,
'SITE_SETTINGS_UNDER_ATTACK': 3, 'SITE_SETTINGS_SNAPPY_QUOTES': 3,
'SITE_CACHE_PURGE_CDN': 3, 'SITE_SETTINGS_UNDER_ATTACK': 3,
'SITE_WARN_ON_INVALID_AUTH': 1, 'SITE_CACHE_PURGE_CDN': 3,
'NOTIFICATIONS_ADMIN_PING': 2, 'NOTIFICATIONS_FROM_SHADOWBANNED_USERS': 3,
'NOTIFICATIONS_HOLE_INACTIVITY_DELETION': 2, 'NOTIFICATIONS_MODMAIL': 3,
'NOTIFICATIONS_HOLE_CREATION': 2, 'APPS_MODERATION': 3,
'NOTIFICATIONS_FROM_SHADOWBANNED_USERS': 3, 'POST_EDITING': 4,
'NOTIFICATIONS_MODMAIL': 3, 'MODERATE_PENDING_SUBMITTED_ASSETS': 4,
'NOTIFICATIONS_MODERATOR_ACTIONS': 2, 'UPDATE_ASSETS': 4,
'NOTIFICATIONS_REDDIT': 1, 'VIEW_PATRONS': 4,
'NOTIFICATIONS_SPECIFIC_WPD_COMMENTS': 1, 'BLACKJACK_NOTIFICATIONS': 4,
'MESSAGE_BLOCKED_USERS': 1, 'IGNORE_BADGE_BLACKLIST': 4,
'APPS_MODERATION': 3, 'SEE_GHOST_VOTES': 5,
'MODS_EVERY_HOLE': 5
} }
FEATURES = { FEATURES = {
@ -660,7 +661,7 @@ TIERS_ID_TO_NAME = {
6: "Rich Bich", 6: "Rich Bich",
} }
BADGE_BLACKLIST = { # only grantable by AEVANN_ID BADGE_BLACKLIST = { # only grantable by admins higher than PERMS['IGNORE_BADGE_BLACKLIST']
1, 2, 6, 10, 11, 12, # Alpha, Verified Email, Beta, Recruiter x3 1, 2, 6, 10, 11, 12, # Alpha, Verified Email, Beta, Recruiter x3
16, 17, 143, 21, 22, 23, 24, 25, 26, 27, # Marsey Artist x3 / Patron Tiers 16, 17, 143, 21, 22, 23, 24, 25, 26, 27, # Marsey Artist x3 / Patron Tiers
94, 95, 96, 97, 98, 109, 67, 68, 83, 84, 87, 90, 179, 185, # Award Status except Y'all-seeing eye 94, 95, 96, 97, 98, 109, 67, 68, 83, 84, 87, 90, 179, 185, # Award Status except Y'all-seeing eye

View File

@ -39,155 +39,153 @@ def loggedout_list(v):
return render_template("admin/loggedout.html", v=v, users=users) return render_template("admin/loggedout.html", v=v, users=users)
@app.get('/admin/move/<int:old_id>/<int:new_id>') # @app.get('/admin/move/<int:old_id>/<int:new_id>')
@limiter.limit(DEFAULT_RATELIMIT, key_func=get_ID) # @limiter.limit(DEFAULT_RATELIMIT, key_func=get_ID)
@admin_level_required(PERMS['USER_MERGE']) # @admin_level_required(PERMS['USER_MERGE'])
def move_acc(v:User, new_id, old_id): # def move_acc(v:User, new_id, old_id):
if v.id != AEVANN_ID: abort(403) # if time.time() - session.get('verified', 0) > 10:
# session.pop("lo_user", None)
# path = request.path
# qs = urlencode(dict(request.values))
# argval = quote(f"{path}?{qs}", safe='')
# return redirect(f"/login?redirect={argval}")
if time.time() - session.get('verified', 0) > 10: # old_id = int(old_id)
session.pop("lo_user", None) # new_id = int(new_id)
path = request.path
qs = urlencode(dict(request.values))
argval = quote(f"{path}?{qs}", safe='')
return redirect(f"/login?redirect={argval}")
old_id = int(old_id) # olduser = g.db.get(User, old_id)
new_id = int(new_id) # newuser = g.db.get(User, new_id)
olduser = g.db.get(User, old_id) # attrs = {
newuser = g.db.get(User, new_id) # 'coins',
# 'coins_spent',
# 'coins_spent_on_hats',
# 'comment_count',
# 'currently_held_lottery_tickets',
# 'lootboxes_bought',
# 'marseybux',
# 'post_count',
# 'received_award_count',
# 'total_held_lottery_tickets',
# 'total_lottery_winnings',
# 'truescore',
# }
attrs = { # for attr in attrs:
'coins', # amount = getattr(newuser, attr) + getattr(olduser, attr)
'coins_spent', # setattr(newuser, attr, amount)
'coins_spent_on_hats',
'comment_count',
'currently_held_lottery_tickets',
'lootboxes_bought',
'marseybux',
'post_count',
'received_award_count',
'total_held_lottery_tickets',
'total_lottery_winnings',
'truescore',
}
for attr in attrs: # if newuser.created_utc > olduser.created_utc:
amount = getattr(newuser, attr) + getattr(olduser, attr) # newuser.created_utc = olduser.created_utc
setattr(newuser, attr, amount)
if newuser.created_utc > olduser.created_utc: # g.db.add(newuser)
newuser.created_utc = olduser.created_utc
g.db.add(newuser) # g.db.commit()
g.db.commit() # classes = {
# (AwardRelationship, "user_id"),
# (Badge, "user_id"),
# (CasinoGame, "user_id"),
# (Hat, "user_id"),
# (HatDef, "author_id"),
# (Lottery, "winner_id"),
# (Marsey, "author_id"),
# (Media, "user_id"),
# (Notification, "user_id"),
# (PushSubscription, "user_id"),
classes = { # #mod actions
(AwardRelationship, "user_id"), # (ModAction, "user_id"),
(Badge, "user_id"), # (ModAction, "target_user_id"),
(CasinoGame, "user_id"), # (SubAction, "user_id"),
(Hat, "user_id"), # (SubAction, "target_user_id"),
(HatDef, "author_id"),
(Lottery, "winner_id"),
(Marsey, "author_id"),
(Media, "user_id"),
(Notification, "user_id"),
(PushSubscription, "user_id"),
#mod actions # #holes
(ModAction, "user_id"), # (Mod, "user_id"),
(ModAction, "target_user_id"), # (Exile, "exiler_id"),
(SubAction, "user_id"), # (Exile, "user_id"),
(SubAction, "target_user_id"), # (SubBlock, "user_id"),
# (SubJoin, "user_id"),
# (SubSubscription, "user_id"),
# (Subscription, "user_id"),
#holes # #other users
(Mod, "user_id"), # (User, "is_banned"),
(Exile, "exiler_id"), # (User, "referred_by"),
(Exile, "user_id"), # (User, "shadowbanned"),
(SubBlock, "user_id"), # (Follow, "target_id"),
(SubJoin, "user_id"), # (Follow, "user_id"),
(SubSubscription, "user_id"), # (UserBlock, "user_id"),
(Subscription, "user_id"), # (UserBlock, "target_id"),
# (ViewerRelationship, "user_id"),
# (ViewerRelationship, "viewer_id"),
#other users # #posts and comments
(User, "is_banned"), # (Submission, "author_id"),
(User, "referred_by"), # (Submission, "is_approved"),
(User, "shadowbanned"), # (Comment, "author_id"),
(Follow, "target_id"), # (Comment, "is_approved"),
(Follow, "user_id"), # (Comment, "sentto"),
(UserBlock, "user_id"), # (Comment, "wall_user_id"),
(UserBlock, "target_id"), # (Vote, "user_id"),
(ViewerRelationship, "user_id"), # (CommentVote, "user_id"),
(ViewerRelationship, "viewer_id"), # (Flag, "user_id"),
# (CommentFlag, "user_id"),
# (SaveRelationship, "user_id"),
# (CommentSaveRelationship, "user_id"),
# (SubmissionOptionVote, "user_id"),
# (CommentOptionVote, "user_id"),
# }
#posts and comments # for cls, attr in classes:
(Submission, "author_id"), # items = g.db.query(cls).filter(getattr(cls, attr) == olduser.id)
(Submission, "is_approved"), # for item in items:
(Comment, "author_id"), # setattr(item, attr, newuser.id)
(Comment, "is_approved"), # g.db.add(item)
(Comment, "sentto"), # try: g.db.commit()
(Comment, "wall_user_id"), # except IntegrityError as e:
(Vote, "user_id"), # if isinstance(e.orig, UniqueViolation):
(CommentVote, "user_id"), # g.db.rollback()
(Flag, "user_id"), # g.db.delete(item)
(CommentFlag, "user_id"), # g.db.commit()
(SaveRelationship, "user_id"), # else:
(CommentSaveRelationship, "user_id"), # print(e, flush=True)
(SubmissionOptionVote, "user_id"), # abort(500, str(e))
(CommentOptionVote, "user_id"),
}
for cls, attr in classes: # newuser.stored_subscriber_count = g.db.query(Follow).filter_by(target_id=newuser.id).count()
items = g.db.query(cls).filter(getattr(cls, attr) == olduser.id)
for item in items:
setattr(item, attr, newuser.id)
g.db.add(item)
try: g.db.commit()
except IntegrityError as e:
if isinstance(e.orig, UniqueViolation):
g.db.rollback()
g.db.delete(item)
g.db.commit()
else:
print(e, flush=True)
abort(500, str(e))
newuser.stored_subscriber_count = g.db.query(Follow).filter_by(target_id=newuser.id).count() # g.db.add(newuser)
g.db.add(newuser) # update_statement = f'''
# update submissions set body_html=replace(body_html, '<a href="/id/{olduser.id}">', '<a href="/id/{newuser.id}">') where body_html like '%<a href="/id/{olduser.id}">%';
# update comments set body_html=replace(body_html, '<a href="/id/{olduser.id}">', '<a href="/id/{newuser.id}">') where body_html like '%<a href="/id/{olduser.id}">%';
# update subs set sidebar_html=replace(sidebar_html, '<a href="/id/{olduser.id}">', '<a href="/id/{newuser.id}">') where sidebar_html like '%<a href="/id/{olduser.id}">%';
# update users set bio_html=replace(bio_html, '<a href="/id/{olduser.id}">', '<a href="/id/{newuser.id}">') where bio_html like '%<a href="/id/{olduser.id}">%';
# update users set sig_html=replace(sig_html, '<a href="/id/{olduser.id}">', '<a href="/id/{newuser.id}">') where sig_html like '%<a href="/id/{olduser.id}">%';
# update users set friends_html=replace(friends_html, '<a href="/id/{olduser.id}">', '<a href="/id/{newuser.id}">') where friends_html like '%<a href="/id/{olduser.id}">%';
# update users set enemies_html=replace(enemies_html, '<a href="/id/{olduser.id}">', '<a href="/id/{newuser.id}">') where enemies_html like '%<a href="/id/{olduser.id}">%';
update_statement = f''' # update submissions set body_html=replace(body_html, '<a href="/id/{olduser.id}"><img loading="lazy" src="/pp/{olduser.id}">', '<a href="/id/{newuser.id}"><img loading="lazy" src="/pp/{newuser.id}">') where body_html like '%<a href="/id/{olduser.id}"><img loading="lazy" src="/pp/{olduser.id}">%';
update submissions set body_html=replace(body_html, '<a href="/id/{olduser.id}">', '<a href="/id/{newuser.id}">') where body_html like '%<a href="/id/{olduser.id}">%'; # update comments set body_html=replace(body_html, '<a href="/id/{olduser.id}"><img loading="lazy" src="/pp/{olduser.id}">', '<a href="/id/{newuser.id}"><img loading="lazy" src="/pp/{newuser.id}">') where body_html like '%<a href="/id/{olduser.id}"><img loading="lazy" src="/pp/{olduser.id}">%';
update comments set body_html=replace(body_html, '<a href="/id/{olduser.id}">', '<a href="/id/{newuser.id}">') where body_html like '%<a href="/id/{olduser.id}">%'; # update subs set sidebar_html=replace(sidebar_html, '<a href="/id/{olduser.id}"><img loading="lazy" src="/pp/{olduser.id}">', '<a href="/id/{newuser.id}"><img loading="lazy" src="/pp/{newuser.id}">') where sidebar_html like '%<a href="/id/{olduser.id}"><img loading="lazy" src="/pp/{olduser.id}">%';
update subs set sidebar_html=replace(sidebar_html, '<a href="/id/{olduser.id}">', '<a href="/id/{newuser.id}">') where sidebar_html like '%<a href="/id/{olduser.id}">%'; # update users set bio_html=replace(bio_html, '<a href="/id/{olduser.id}"><img loading="lazy" src="/pp/{olduser.id}">', '<a href="/id/{newuser.id}"><img loading="lazy" src="/pp/{newuser.id}">') where bio_html like '%<a href="/id/{olduser.id}"><img loading="lazy" src="/pp/{olduser.id}">%';
update users set bio_html=replace(bio_html, '<a href="/id/{olduser.id}">', '<a href="/id/{newuser.id}">') where bio_html like '%<a href="/id/{olduser.id}">%'; # update users set sig_html=replace(sig_html, '<a href="/id/{olduser.id}"><img loading="lazy" src="/pp/{olduser.id}">', '<a href="/id/{newuser.id}"><img loading="lazy" src="/pp/{newuser.id}">') where sig_html like '%<a href="/id/{olduser.id}"><img loading="lazy" src="/pp/{olduser.id}">%';
update users set sig_html=replace(sig_html, '<a href="/id/{olduser.id}">', '<a href="/id/{newuser.id}">') where sig_html like '%<a href="/id/{olduser.id}">%'; # update users set friends_html=replace(friends_html, '<a href="/id/{olduser.id}"><img loading="lazy" src="/pp/{olduser.id}">', '<a href="/id/{newuser.id}"><img loading="lazy" src="/pp/{newuser.id}">') where friends_html like '%<a href="/id/{olduser.id}"><img loading="lazy" src="/pp/{olduser.id}">%';
update users set friends_html=replace(friends_html, '<a href="/id/{olduser.id}">', '<a href="/id/{newuser.id}">') where friends_html like '%<a href="/id/{olduser.id}">%'; # update users set enemies_html=replace(enemies_html, '<a href="/id/{olduser.id}"><img loading="lazy" src="/pp/{olduser.id}">', '<a href="/id/{newuser.id}"><img loading="lazy" src="/pp/{newuser.id}">') where enemies_html like '%<a href="/id/{olduser.id}"><img loading="lazy" src="/pp/{olduser.id}">%'; '''
update users set enemies_html=replace(enemies_html, '<a href="/id/{olduser.id}">', '<a href="/id/{newuser.id}">') where enemies_html like '%<a href="/id/{olduser.id}">%';
update submissions set body_html=replace(body_html, '<a href="/id/{olduser.id}"><img loading="lazy" src="/pp/{olduser.id}">', '<a href="/id/{newuser.id}"><img loading="lazy" src="/pp/{newuser.id}">') where body_html like '%<a href="/id/{olduser.id}"><img loading="lazy" src="/pp/{olduser.id}">%'; # g.db.execute(update_statement)
update comments set body_html=replace(body_html, '<a href="/id/{olduser.id}"><img loading="lazy" src="/pp/{olduser.id}">', '<a href="/id/{newuser.id}"><img loading="lazy" src="/pp/{newuser.id}">') where body_html like '%<a href="/id/{olduser.id}"><img loading="lazy" src="/pp/{olduser.id}">%';
update subs set sidebar_html=replace(sidebar_html, '<a href="/id/{olduser.id}"><img loading="lazy" src="/pp/{olduser.id}">', '<a href="/id/{newuser.id}"><img loading="lazy" src="/pp/{newuser.id}">') where sidebar_html like '%<a href="/id/{olduser.id}"><img loading="lazy" src="/pp/{olduser.id}">%';
update users set bio_html=replace(bio_html, '<a href="/id/{olduser.id}"><img loading="lazy" src="/pp/{olduser.id}">', '<a href="/id/{newuser.id}"><img loading="lazy" src="/pp/{newuser.id}">') where bio_html like '%<a href="/id/{olduser.id}"><img loading="lazy" src="/pp/{olduser.id}">%';
update users set sig_html=replace(sig_html, '<a href="/id/{olduser.id}"><img loading="lazy" src="/pp/{olduser.id}">', '<a href="/id/{newuser.id}"><img loading="lazy" src="/pp/{newuser.id}">') where sig_html like '%<a href="/id/{olduser.id}"><img loading="lazy" src="/pp/{olduser.id}">%';
update users set friends_html=replace(friends_html, '<a href="/id/{olduser.id}"><img loading="lazy" src="/pp/{olduser.id}">', '<a href="/id/{newuser.id}"><img loading="lazy" src="/pp/{newuser.id}">') where friends_html like '%<a href="/id/{olduser.id}"><img loading="lazy" src="/pp/{olduser.id}">%';
update users set enemies_html=replace(enemies_html, '<a href="/id/{olduser.id}"><img loading="lazy" src="/pp/{olduser.id}">', '<a href="/id/{newuser.id}"><img loading="lazy" src="/pp/{newuser.id}">') where enemies_html like '%<a href="/id/{olduser.id}"><img loading="lazy" src="/pp/{olduser.id}">%'; '''
g.db.execute(update_statement) # g.db.delete(olduser)
g.db.delete(olduser) # g.db.commit()
g.db.commit() # stats = cache.get(f'{SITE}_stats')
# online = cache.get(CHAT_ONLINE_CACHE_KEY)
# cache.clear()
# cache.set(f'{SITE}_stats', stats)
# cache.set(CHAT_ONLINE_CACHE_KEY, online)
stats = cache.get(f'{SITE}_stats') # return redirect(f"/@{olduser.username}")
online = cache.get(CHAT_ONLINE_CACHE_KEY)
cache.clear()
cache.set(f'{SITE}_stats', stats)
cache.set(CHAT_ONLINE_CACHE_KEY, online)
return redirect(f"/@{olduser.username}")
@ -532,7 +530,7 @@ def under_attack(v):
def admin_badges_grantable_list(v): def admin_badges_grantable_list(v):
query = g.db.query(BadgeDef) query = g.db.query(BadgeDef)
if BADGE_BLACKLIST and v.id not in {AEVANN_ID}: if BADGE_BLACKLIST and v.admin_level < PERMS['IGNORE_BADGE_BLACKLIST']:
query = query.filter(BadgeDef.id.notin_(BADGE_BLACKLIST)) query = query.filter(BadgeDef.id.notin_(BADGE_BLACKLIST))
badge_types = query.order_by(BadgeDef.id).all() badge_types = query.order_by(BadgeDef.id).all()

View File

@ -13,8 +13,6 @@ from files.routes.wrappers import *
from files.__main__ import app, cache, limiter from files.__main__ import app, cache, limiter
ASSET_TYPES = (Marsey, HatDef) ASSET_TYPES = (Marsey, HatDef)
CAN_APPROVE_ASSETS = (AEVANN_ID, CARP_ID)
CAN_UPDATE_ASSETS = (AEVANN_ID, CARP_ID)
@app.get("/submit/marseys") @app.get("/submit/marseys")
@limiter.limit(DEFAULT_RATELIMIT, key_func=get_ID) @limiter.limit(DEFAULT_RATELIMIT, key_func=get_ID)
@ -95,8 +93,6 @@ def submit_marsey(v:User):
def verify_permissions_and_get_asset(cls, asset_type:str, v:User, name:str, make_lower=False): def verify_permissions_and_get_asset(cls, asset_type:str, v:User, name:str, make_lower=False):
if cls not in ASSET_TYPES: raise Exception("not a valid asset type") if cls not in ASSET_TYPES: raise Exception("not a valid asset type")
if AEVANN_ID and v.id not in CAN_APPROVE_ASSETS:
abort(403, f"Only Carp can approve {asset_type}!")
name = name.strip() name = name.strip()
if make_lower: name = name.lower() if make_lower: name = name.lower()
asset = None asset = None
@ -110,7 +106,7 @@ def verify_permissions_and_get_asset(cls, asset_type:str, v:User, name:str, make
@app.post("/admin/approve/marsey/<name>") @app.post("/admin/approve/marsey/<name>")
@limiter.limit(DEFAULT_RATELIMIT, key_func=get_ID) @limiter.limit(DEFAULT_RATELIMIT, key_func=get_ID)
@admin_level_required(PERMS['MODERATE_PENDING_SUBMITTED_MARSEYS']) @admin_level_required(PERMS['MODERATE_PENDING_SUBMITTED_ASSETS'])
def approve_marsey(v, name): def approve_marsey(v, name):
marsey = verify_permissions_and_get_asset(Marsey, "marsey", v, name, True) marsey = verify_permissions_and_get_asset(Marsey, "marsey", v, name, True)
tags = request.values.get('tags').lower().strip() tags = request.values.get('tags').lower().strip()
@ -180,8 +176,8 @@ def remove_asset(cls, type_name:str, v:User, name:str) -> dict[str, str]:
asset = g.db.get(cls, name) asset = g.db.get(cls, name)
if not asset: if not asset:
abort(404, f"This {type_name} '{name}' doesn't exist!") abort(404, f"This {type_name} '{name}' doesn't exist!")
if v.id != asset.submitter_id and v.id not in CAN_APPROVE_ASSETS: if v.id != asset.submitter_id and v.admin_level < PERMS['MODERATE_PENDING_SUBMITTED_ASSETS']:
abort(403, f"Only Carp can remove {type_name}s!") abort(403)
name = asset.name name = asset.name
if v.id != asset.submitter_id: if v.id != asset.submitter_id:
msg = f"@{v.username} has rejected a {type_name} you submitted: `'{name}'`" msg = f"@{v.username} has rejected a {type_name} you submitted: `'{name}'`"
@ -271,7 +267,7 @@ def submit_hat(v:User):
@app.post("/admin/approve/hat/<name>") @app.post("/admin/approve/hat/<name>")
@limiter.limit("3/second;120/minute;200/hour;1000/day") @limiter.limit("3/second;120/minute;200/hour;1000/day")
@limiter.limit("3/second;120/minute;200/hour;1000/day", key_func=get_ID) @limiter.limit("3/second;120/minute;200/hour;1000/day", key_func=get_ID)
@admin_level_required(PERMS['MODERATE_PENDING_SUBMITTED_HATS']) @admin_level_required(PERMS['MODERATE_PENDING_SUBMITTED_ASSETS'])
def approve_hat(v, name): def approve_hat(v, name):
hat = verify_permissions_and_get_asset(HatDef, "hat", v, name, False) hat = verify_permissions_and_get_asset(HatDef, "hat", v, name, False)
description = request.values.get('description').strip() description = request.values.get('description').strip()
@ -340,10 +336,8 @@ def remove_hat(v:User, name):
@app.get("/admin/update/marseys") @app.get("/admin/update/marseys")
@limiter.limit(DEFAULT_RATELIMIT, key_func=get_ID) @limiter.limit(DEFAULT_RATELIMIT, key_func=get_ID)
@admin_level_required(PERMS['UPDATE_MARSEYS']) @admin_level_required(PERMS['UPDATE_ASSETS'])
def update_marseys(v): def update_marseys(v):
if AEVANN_ID and v.id not in CAN_UPDATE_ASSETS:
abort(403)
name = request.values.get('name') name = request.values.get('name')
tags = None tags = None
error = None error = None
@ -360,11 +354,8 @@ def update_marseys(v):
@app.post("/admin/update/marseys") @app.post("/admin/update/marseys")
@limiter.limit(DEFAULT_RATELIMIT, key_func=get_ID) @limiter.limit(DEFAULT_RATELIMIT, key_func=get_ID)
@admin_level_required(PERMS['UPDATE_MARSEYS']) @admin_level_required(PERMS['UPDATE_ASSETS'])
def update_marsey(v): def update_marsey(v):
if AEVANN_ID and v.id not in CAN_UPDATE_ASSETS:
abort(403)
file = request.files["image"] file = request.files["image"]
name = request.values.get('name', '').lower().strip() name = request.values.get('name', '').lower().strip()
tags = request.values.get('tags', '').lower().strip() tags = request.values.get('tags', '').lower().strip()
@ -414,20 +405,15 @@ def update_marsey(v):
@app.get("/admin/update/hats") @app.get("/admin/update/hats")
@limiter.limit(DEFAULT_RATELIMIT, key_func=get_ID) @limiter.limit(DEFAULT_RATELIMIT, key_func=get_ID)
@admin_level_required(PERMS['UPDATE_HATS']) @admin_level_required(PERMS['UPDATE_ASSETS'])
def update_hats(v): def update_hats(v):
if AEVANN_ID and v.id not in CAN_UPDATE_ASSETS:
abort(403)
return render_template("update_assets.html", v=v, type="Hat") return render_template("update_assets.html", v=v, type="Hat")
@app.post("/admin/update/hats") @app.post("/admin/update/hats")
@limiter.limit(DEFAULT_RATELIMIT, key_func=get_ID) @limiter.limit(DEFAULT_RATELIMIT, key_func=get_ID)
@admin_level_required(PERMS['UPDATE_HATS']) @admin_level_required(PERMS['UPDATE_ASSETS'])
def update_hat(v): def update_hat(v):
if AEVANN_ID and v.id not in CAN_UPDATE_ASSETS:
abort(403)
file = request.files["image"] file = request.files["image"]
name = request.values.get('name', '').strip() name = request.values.get('name', '').strip()

View File

@ -171,7 +171,7 @@ def award_thing(v, thing_type, id):
else: else:
safe_username = f"@{author.username}" safe_username = f"@{author.username}"
if SITE == 'rdrama.net' and author.id == PIZZASHILL_ID and v.id not in {AEVANN_ID}: if SITE == 'rdrama.net' and author.id == PIZZASHILL_ID:
abort(403, f"{safe_username} is immune to awards.") abort(403, f"{safe_username} is immune to awards.")
if kind == "benefactor" and author.id == v.id: if kind == "benefactor" and author.id == v.id:

View File

@ -98,7 +98,7 @@ def git_head():
def inject_constants(): def inject_constants():
return {"environ":environ, "SITE":SITE, "SITE_NAME":SITE_NAME, "SITE_FULL":SITE_FULL, return {"environ":environ, "SITE":SITE, "SITE_NAME":SITE_NAME, "SITE_FULL":SITE_FULL,
"AUTOJANNY_ID":AUTOJANNY_ID, "MODMAIL_ID":MODMAIL_ID, "VAPID_PUBLIC_KEY":VAPID_PUBLIC_KEY, "AUTOJANNY_ID":AUTOJANNY_ID, "MODMAIL_ID":MODMAIL_ID, "VAPID_PUBLIC_KEY":VAPID_PUBLIC_KEY,
"listdir":listdir, "os_path":path, "AEVANN_ID":AEVANN_ID, "listdir":listdir, "os_path":path,
"PIZZASHILL_ID":PIZZASHILL_ID, "DEFAULT_COLOR":DEFAULT_COLOR, "PIZZASHILL_ID":PIZZASHILL_ID, "DEFAULT_COLOR":DEFAULT_COLOR,
"COLORS":COLORS, "time":time, "PERMS":PERMS, "FEATURES":FEATURES, "COLORS":COLORS, "time":time, "PERMS":PERMS, "FEATURES":FEATURES,
"HOLE_NAME":HOLE_NAME, "HOLE_STYLE_FLAIR":HOLE_STYLE_FLAIR, "HOLE_REQUIRED":HOLE_REQUIRED, "HOLE_NAME":HOLE_NAME, "HOLE_STYLE_FLAIR":HOLE_STYLE_FLAIR, "HOLE_REQUIRED":HOLE_REQUIRED,

View File

@ -122,7 +122,6 @@ def on_login(account, redir=None):
session.permanent = True session.permanent = True
session["lo_user"] = account.id session["lo_user"] = account.id
session["login_nonce"] = account.login_nonce session["login_nonce"] = account.login_nonce
if account.id == AEVANN_ID: session["verified"] = time.time()
check_for_alts(account) check_for_alts(account)
@ -319,7 +318,7 @@ def sign_up_post(v:Optional[User]):
) )
if users_count == 4: if users_count == 4:
new_user.admin_level = 3 new_user.admin_level = 5
session["history"] = [] session["history"] = []
g.db.add(new_user) g.db.add(new_user)

View File

@ -111,12 +111,9 @@ def daily_chart(v:User):
@limiter.limit(DEFAULT_RATELIMIT, key_func=get_ID) @limiter.limit(DEFAULT_RATELIMIT, key_func=get_ID)
@admin_level_required(PERMS['VIEW_PATRONS']) @admin_level_required(PERMS['VIEW_PATRONS'])
def patrons(v): def patrons(v):
if AEVANN_ID and v.id not in {AEVANN_ID, CARP_ID}:
abort(404)
users = g.db.query(User).filter(User.patron > 0).order_by(User.patron.desc(), User.id).all() users = g.db.query(User).filter(User.patron > 0).order_by(User.patron.desc(), User.id).all()
return render_template("patrons.html", v=v, users=users, benefactor_def=AWARDS['benefactor']) return render_template("admin/patrons.html", v=v, users=users, benefactor_def=AWARDS['benefactor'])
@app.get("/admins") @app.get("/admins")
@app.get("/badmins") @app.get("/badmins")

View File

@ -15,7 +15,7 @@ def vote_info_get(v, link):
else: abort(400) else: abort(400)
except: abort(400) except: abort(400)
if thing.ghost and v.id != AEVANN_ID: if thing.ghost and v.admin_level < PERMS['SEE_GHOST_VOTES']:
abort(403) abort(403)
if thing.author.shadowbanned and not (v and v.admin_level >= PERMS['USER_SHADOWBAN']): if thing.author.shadowbanned and not (v and v.admin_level >= PERMS['USER_SHADOWBAN']):

View File

@ -53,7 +53,7 @@
<li><a href="/chuds">Chudded Users</a></li> <li><a href="/chuds">Chudded Users</a></li>
<li><a href="/grassed">Currently Grassed Users</a></li> <li><a href="/grassed">Currently Grassed Users</a></li>
{%- endif %} {%- endif %}
{% if FEATURES['MARSEYBUX'] and (not AEVANN_ID or v.id in (AEVANN_ID, CARP_ID)) -%} {% if FEATURES['MARSEYBUX'] and v.admin_level >= PERMS['VIEW_PATRONS'] -%}
<li><a href="/patrons">Patrons</a></li> <li><a href="/patrons">Patrons</a></li>
{%- endif %} {%- endif %}
{% if v.admin_level >= PERMS['VIEW_ACTIVE_USERS'] %} {% if v.admin_level >= PERMS['VIEW_ACTIVE_USERS'] %}

View File

@ -369,7 +369,7 @@
{% endif %} {% endif %}
{% if not c.ghost or (v and v.id == AEVANN_ID) %} {% if not c.ghost or (v and v.admin_level >= PERMS['SEE_GHOST_VOTES']) %}
<a href="/votes/{{c.fullname}}" class="btn caction nobackground px-1 text-muted"><i class="fas fa-arrows-v"></i>Votes</a> <a href="/votes/{{c.fullname}}" class="btn caction nobackground px-1 text-muted"><i class="fas fa-arrows-v"></i>Votes</a>
{% endif %} {% endif %}
@ -555,7 +555,7 @@
<div class="modal-body"> <div class="modal-body">
<ul class="list-group comment-actions"> <ul class="list-group comment-actions">
{% if not c.ghost or (v and v.id == AEVANN_ID) %} {% if not c.ghost or (v and v.admin_level >= PERMS['SEE_GHOST_VOTES']) %}
<a href="/votes/{{c.fullname}}"><li class="list-group-item"><i class="fas fa-arrows-v mr-2"></i>Votes</li></a> <a href="/votes/{{c.fullname}}"><li class="list-group-item"><i class="fas fa-arrows-v mr-2"></i>Votes</li></a>
{% endif %} {% endif %}

View File

@ -6,7 +6,7 @@
{% endif %} {% endif %}
{% if not p.ghost or (v and v.id == AEVANN_ID) %} {% if not p.ghost or (v and v.admin_level >= PERMS['SEE_GHOST_VOTES']) %}
<a class="list-inline-item" href="/votes/{{p.fullname}}"><i class="fas fa-arrows-v"></i>Votes</a> <a class="list-inline-item" href="/votes/{{p.fullname}}"><i class="fas fa-arrows-v"></i>Votes</a>
{% endif %} {% endif %}

View File

@ -6,7 +6,7 @@
{% endif %} {% endif %}
{% if not p.ghost or (v and v.id == AEVANN_ID) %} {% if not p.ghost or (v and v.admin_level >= PERMS['SEE_GHOST_VOTES']) %}
<a class="nobackground btn btn-link btn-block btn-lg text-left text-muted" href="/votes/{{p.fullname}}"> <a class="nobackground btn btn-link btn-block btn-lg text-left text-muted" href="/votes/{{p.fullname}}">
<i class="fas fa-arrows-v text-center text-muted mr-2"></i>Votes <i class="fas fa-arrows-v text-center text-muted mr-2"></i>Votes
</a> </a>

View File

@ -76,19 +76,19 @@
<input autocomplete="off" type="text" id="{{hat.name}}-author" class="form-control" maxlength="30" value="{{hat.author.username}}" readonly> <input autocomplete="off" type="text" id="{{hat.name}}-author" class="form-control" maxlength="30" value="{{hat.author.username}}" readonly>
<label class="mt-3" for="{{hat.name}}-name">Name</label> <label class="mt-3" for="{{hat.name}}-name">Name</label>
<input autocomplete="off" type="text" id="{{hat.name}}-name" class="form-control" name="name" maxlength="30" value="{{hat.name}}" pattern='hat[a-zA-Z0-9]{1,24}' placeholder="Required" required {% if v.admin_level < PERMS['MODERATE_PENDING_SUBMITTED_HATS'] %}readonly{% endif %}> <input autocomplete="off" type="text" id="{{hat.name}}-name" class="form-control" name="name" maxlength="30" value="{{hat.name}}" pattern='hat[a-zA-Z0-9]{1,24}' placeholder="Required" required {% if v.admin_level < PERMS['MODERATE_PENDING_SUBMITTED_ASSETS'] %}readonly{% endif %}>
> >
<label class="mt-3" for="{{hat.name}}-description">Description</label> <label class="mt-3" for="{{hat.name}}-description">Description</label>
<input autocomplete="off" type="text" id="{{hat.name}}-description" class="form-control" name="description" maxlength="300" value="{{hat.description}}" pattern='[^<>&\n\t]{1,300}' placeholder="Required" required {% if v.admin_level < PERMS['MODERATE_PENDING_SUBMITTED_HATS'] %}readonly{% endif %}> <input autocomplete="off" type="text" id="{{hat.name}}-description" class="form-control" name="description" maxlength="300" value="{{hat.description}}" pattern='[^<>&\n\t]{1,300}' placeholder="Required" required {% if v.admin_level < PERMS['MODERATE_PENDING_SUBMITTED_ASSETS'] %}readonly{% endif %}>
<div><label class="mt-3" for="{{hat.name}}-price">Price</label></div> <div><label class="mt-3" for="{{hat.name}}-price">Price</label></div>
<input autocomplete="off" type="number" id="{{hat.name}}-price" class="form-control" name="price" min="0" value="{{hat.price}}" placeholder="Required" required {% if v.admin_level < PERMS['MODERATE_PENDING_SUBMITTED_HATS'] %}readonly{% endif %}> <input autocomplete="off" type="number" id="{{hat.name}}-price" class="form-control" name="price" min="0" value="{{hat.price}}" placeholder="Required" required {% if v.admin_level < PERMS['MODERATE_PENDING_SUBMITTED_ASSETS'] %}readonly{% endif %}>
</div> </div>
</div> </div>
<div class="d-flex my-4 mx-3"> <div class="d-flex my-4 mx-3">
<button type="button" class="btn btn-primary ml-auto" data-nonce="{{g.nonce}}" data-onclick="remove_hat(this, '{{hat.name}}')">Remove</button> <button type="button" class="btn btn-primary ml-auto" data-nonce="{{g.nonce}}" data-onclick="remove_hat(this, '{{hat.name}}')">Remove</button>
{% if v.admin_level >= PERMS['MODERATE_PENDING_SUBMITTED_HATS'] %} {% if v.admin_level >= PERMS['MODERATE_PENDING_SUBMITTED_ASSETS'] %}
<button type="button" class="btn btn-primary ml-3" data-nonce="{{g.nonce}}" data-onclick="approve_hat(this, '{{hat.name}}')">Approve</button> <button type="button" class="btn btn-primary ml-3" data-nonce="{{g.nonce}}" data-onclick="approve_hat(this, '{{hat.name}}')">Approve</button>
{% endif %} {% endif %}
</div> </div>

View File

@ -66,15 +66,15 @@
<input autocomplete="off" type="text" id="{{marsey.name}}-author" class="form-control" maxlength="30" value="{{marsey.author}}" readonly> <input autocomplete="off" type="text" id="{{marsey.name}}-author" class="form-control" maxlength="30" value="{{marsey.author}}" readonly>
<label class="mt-3" for="{{marsey.name}}-name">Name</label> <label class="mt-3" for="{{marsey.name}}-name">Name</label>
<input autocomplete="off" type="text" id="{{marsey.name}}-name" class="form-control" name="name" maxlength="30" value="{{marsey.name}}" pattern='marsey[a-z0-9]{1,24}' placeholder="Required" required {% if v.admin_level < PERMS['MODERATE_PENDING_SUBMITTED_MARSEYS'] %}readonly{% endif %}> <input autocomplete="off" type="text" id="{{marsey.name}}-name" class="form-control" name="name" maxlength="30" value="{{marsey.name}}" pattern='marsey[a-z0-9]{1,24}' placeholder="Required" required {% if v.admin_level < PERMS['MODERATE_PENDING_SUBMITTED_ASSETS'] %}readonly{% endif %}>
<label class="mt-3" for="{{marsey.name}}-tags">Tags</label> <label class="mt-3" for="{{marsey.name}}-tags">Tags</label>
<input autocomplete="off" type="text" id="{{marsey.name}}-tags" class="form-control" name="tags" maxlength="200" value="{{marsey.tags}}" pattern='[a-z0-9: ]{1,200}' placeholder="Required" required {% if v.admin_level < PERMS['MODERATE_PENDING_SUBMITTED_MARSEYS'] %}readonly{% endif %}> <input autocomplete="off" type="text" id="{{marsey.name}}-tags" class="form-control" name="tags" maxlength="200" value="{{marsey.tags}}" pattern='[a-z0-9: ]{1,200}' placeholder="Required" required {% if v.admin_level < PERMS['MODERATE_PENDING_SUBMITTED_ASSETS'] %}readonly{% endif %}>
</div> </div>
</div> </div>
<div class="d-flex my-4 mx-3"> <div class="d-flex my-4 mx-3">
<button type="button" class="btn btn-primary ml-auto" data-nonce="{{g.nonce}}" data-onclick="remove_marsey(this, '{{marsey.name}}')">Remove</button> <button type="button" class="btn btn-primary ml-auto" data-nonce="{{g.nonce}}" data-onclick="remove_marsey(this, '{{marsey.name}}')">Remove</button>
{% if v.admin_level >= PERMS['MODERATE_PENDING_SUBMITTED_MARSEYS'] %} {% if v.admin_level >= PERMS['MODERATE_PENDING_SUBMITTED_ASSETS'] %}
<button type="button" class="btn btn-primary ml-3" data-nonce="{{g.nonce}}" data-onclick="approve_marsey(this, '{{marsey.name}}')">Approve</button> <button type="button" class="btn btn-primary ml-3" data-nonce="{{g.nonce}}" data-onclick="approve_marsey(this, '{{marsey.name}}')">Approve</button>
{% endif %} {% endif %}
</div> </div>