Merge branch 'frost' of https://github.com/Aevann1/rDrama into frost

remotes/1693176582716663532/tmp_refs/heads/watchparty
Aevann1 2022-10-10 05:27:37 +00:00
commit 1e8ed876b3
107 changed files with 489 additions and 624 deletions

View File

@ -4026,6 +4026,9 @@ ul.comment-section {
.profile-actions .dropdown-item:hover .fa, .profile-actions .dropdown-item:hover .fas, .profile-actions .dropdown-item:active .far {
color: var(--black);
}
.profile-owned-all-hats {
color: gold;
}
#page .footer h1, #page .footer h2, #page .footer h3, #page .footer h4, #page .footer h5, #page .footer h6, #article .footer h1, #article .footer h2, #article .footer h3, #article .footer h4, #article .footer h5, #article .footer h6 {
font-weight: 600;
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 32 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 31 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 49 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 84 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 89 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 124 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 157 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 42 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 108 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 173 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 209 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 914 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 45 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 47 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.3 KiB

View File

@ -1,5 +1,5 @@
function removeFollower(event, username) {
post_toast(event.target,'/remove_follow/' + username);
function removeFollower(t, username) {
post_toast(t,'/remove_follow/' + username);
let table = document.getElementById("followers-table");
table.removeChild(event.target.parentElement.parentElement);
}
table.removeChild(t.parentElement.parentElement);
}

View File

@ -1,5 +1,5 @@
function removeFollowing(event, username) {
post_toast(event.target,'/unfollow/' + username);
function removeFollowing(t, username) {
post_toast(t,'/unfollow/' + username);
let table = document.getElementById("followers-table");
table.removeChild(event.target.parentElement.parentElement);
}
table.removeChild(t.parentElement.parentElement);
}

File diff suppressed because one or more lines are too long

View File

@ -33,7 +33,7 @@ class OauthApp(Base):
@property
@lazy
def permalink(self):
return f"/admin/app/{self.id}"
return f"{SITE_FULL}/admin/app/{self.id}"
@lazy
def idlist(self, page=1):

View File

@ -208,6 +208,13 @@ class User(Base):
def num_of_owned_hats(self):
return len(self.owned_hats)
@property
@lazy
def hats_owned_proportion_display(self):
total_num_of_hats = g.db.query(HatDef).filter(HatDef.submitter_id == None).count()
proportion = f'{float(self.num_of_owned_hats) / total_num_of_hats:.1%}'
return (proportion, total_num_of_hats)
@property
@lazy
def num_of_designed_hats(self):

View File

@ -191,3 +191,123 @@ def execute_snappy(post, v):
post.comment_count += 1
post.replies = [c]
def execute_zozbot(c, level, parent_submission, v):
if random.random() >= 0.001: return
c2 = Comment(author_id=ZOZBOT_ID,
parent_submission=parent_submission,
parent_comment_id=c.id,
level=level+1,
is_bot=True,
body="zoz",
body_html="<p>zoz</p>",
top_comment_id=c.top_comment_id,
ghost=c.ghost,
distinguish_level=6
)
g.db.add(c2)
g.db.flush()
n = Notification(comment_id=c2.id, user_id=v.id)
g.db.add(n)
c3 = Comment(author_id=ZOZBOT_ID,
parent_submission=parent_submission,
parent_comment_id=c2.id,
level=level+2,
is_bot=True,
body="zle",
body_html="<p>zle</p>",
top_comment_id=c.top_comment_id,
ghost=c.ghost,
distinguish_level=6
)
g.db.add(c3)
g.db.flush()
c4 = Comment(author_id=ZOZBOT_ID,
parent_submission=parent_submission,
parent_comment_id=c3.id,
level=level+3,
is_bot=True,
body="zozzle",
body_html="<p>zozzle</p>",
top_comment_id=c.top_comment_id,
ghost=c.ghost,
distinguish_level=6
)
g.db.add(c4)
zozbot = get_account(ZOZBOT_ID)
zozbot.comment_count += 3
zozbot.coins += 3
g.db.add(zozbot)
def execute_longpostbot(c, level, body, body_html, parent_submission, v):
if not len(c.body.split()) >= 200: return
if "</blockquote>" in body_html: return
body = random.choice(LONGPOST_REPLIES)
if body.startswith(''):
body = body[1:]
vote = CommentVote(user_id=LONGPOSTBOT_ID,
vote_type=-1,
comment_id=c.id,
real = True
)
g.db.add(vote)
c.downvotes = 1
c2 = Comment(author_id=LONGPOSTBOT_ID,
parent_submission=parent_submission,
parent_comment_id=c.id,
level=level+1,
is_bot=True,
body=body,
body_html=f"<p>{body}</p>",
top_comment_id=c.top_comment_id,
ghost=c.ghost
)
g.db.add(c2)
longpostbot = get_account(LONGPOSTBOT_ID)
longpostbot.comment_count += 1
longpostbot.coins += 1
g.db.add(longpostbot)
g.db.flush()
n = Notification(comment_id=c2.id, user_id=v.id)
g.db.add(n)
def execute_basedbot(c, level, body, parent_submission, parent_post, v):
pill = based_regex.match(body)
if level == 1: basedguy = get_account(parent_post.author_id)
else: basedguy = get_account(c.parent_comment.author_id)
basedguy.basedcount += 1
if pill:
if basedguy.pills: basedguy.pills += f", {pill.group(1)}"
else: basedguy.pills += f"{pill.group(1)}"
g.db.add(basedguy)
body2 = f"@{basedguy.username}'s Based Count has increased by 1. Their Based Count is now {basedguy.basedcount}."
if basedguy.pills: body2 += f"\n\nPills: {basedguy.pills}"
body_based_html = sanitize(body2)
c_based = Comment(author_id=BASEDBOT_ID,
parent_submission=parent_submission,
distinguish_level=6,
parent_comment_id=c.id,
level=level+1,
is_bot=True,
body_html=body_based_html,
top_comment_id=c.top_comment_id,
ghost=c.ghost
)
g.db.add(c_based)
g.db.flush()
n = Notification(comment_id=c_based.id, user_id=v.id)
g.db.add(n)

View File

@ -265,6 +265,10 @@ POST_TITLE_LENGTH_LIMIT = 500 # do not make larger than 500 without altering the
POST_TITLE_HTML_LENGTH_LIMIT = 1500 # do not make larger than 1500 without altering the table
POST_BODY_LENGTH_LIMIT = 20000 # do not make larger than 20000 without altering the table
POST_BODY_HTML_LENGTH_LIMIT = 40000 # do not make larger than 40000 without altering the table
COMMENT_BODY_LENGTH_LIMIT = 10000 # do not make larger than 10000 characters without altering the table
COMMENT_BODY_HTML_LENGTH_LIMIT = 20000 # do not make larger than 20000 characters without altering the table
COMMENT_MAX_DEPTH = 200
TRANSFER_MESSAGE_LENGTH_LIMIT = 200 # do not make larger than 10000 characters (comment limit) without altering the table
LOGGEDIN_ACTIVE_TIME = 15 * 60
PFP_DEFAULT_MARSEY = True

View File

@ -195,11 +195,11 @@ def sanitize_raw_title(sanitized):
sanitized = sanitized.strip()
return sanitized[:POST_TITLE_LENGTH_LIMIT]
def sanitize_raw_body(sanitized):
def sanitize_raw_body(sanitized, is_post):
if not sanitized: return ""
sanitized = sanitized.replace('\u200e','').replace('\u200b','').replace("\ufeff", "").replace("\r\n", "\n")
sanitized = sanitized.strip()
return sanitized[:POST_BODY_LENGTH_LIMIT]
return sanitized[:POST_BODY_LENGTH_LIMIT if is_post else COMMENT_BODY_LENGTH_LIMIT]
@with_sigalrm_timeout(5)

View File

@ -853,7 +853,9 @@ def agendaposter(user_id, v):
user.agendaposter = expiry
g.db.add(user)
if days: note = f"for {days} days"
if days:
days_txt = str(days).rstrip('.0')
note = f"for {days_txt} days"
else: note = "permanently"
ma = ModAction(
@ -1015,8 +1017,9 @@ def ban_user(user_id, v):
x.ban(admin=v, reason=reason, days=days)
if days:
if reason: text = f"@{v.username} has banned you for **{days}** days for the following reason:\n\n> {reason}"
else: text = f"@{v.username} has banned you for **{days}** days."
days_txt = str(days).rstrip('.0')
if reason: text = f"@{v.username} has banned you for **{days_txt}** days for the following reason:\n\n> {reason}"
else: text = f"@{v.username} has banned you for **{days_txt}** days."
else:
if reason: text = f"@{v.username} has banned you permanently for the following reason:\n\n> {reason}"
else: text = f"@{v.username} has banned you permanently."
@ -1025,7 +1028,7 @@ def ban_user(user_id, v):
if days == 0: duration = "permanently"
elif days == 1: duration = "for 1 day"
else: duration = f"for {days} days"
else: duration = f"for {days_txt} days"
note = f'reason: "{reason}", duration: {duration}'
ma=ModAction(

View File

@ -209,19 +209,6 @@ def award_thing(v, thing_type, id):
elif author.unban_utc:
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 >= PERMS['USER_BAN']:
log_link = f'/{thing_type}/{thing.id}'
reason = f'<a href="{log_link}">{log_link}</a>'
note = f'reason: "{reason}", duration: for 1 day'
ma=ModAction(
kind="ban_user",
user_id=v.id,
target_user_id=author.id,
_note=note
)
g.db.add(ma)
elif kind == "unban":
if not author.is_suspended or not author.unban_utc or time.time() > author.unban_utc: abort(403)
@ -233,32 +220,11 @@ def award_thing(v, thing_type, id):
author.is_banned = 0
author.ban_reason = None
send_repeatable_notification(author.id, "You have been unbanned!")
if v.admin_level >= PERMS['USER_BAN']:
ma=ModAction(
kind="unban_user",
user_id=v.id,
target_user_id=author.id,
)
g.db.add(ma)
elif kind == "grass":
author.is_banned = AUTOJANNY_ID
author.ban_reason = f"grass award used by @{v.username} on /{thing_type}/{thing.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 >= PERMS['USER_BAN']:
log_link = f'/{thing_type}/{thing.id}'
reason = f'<a href="{log_link}">{log_link}</a>'
note = f'reason: "{reason}", duration: for 30 days'
ma=ModAction(
kind="ban_user",
user_id=v.id,
target_user_id=author.id,
_note=note
)
g.db.add(ma)
elif kind == "pin":
if not FEATURES['PINS']:
abort(403)
@ -294,15 +260,6 @@ def award_thing(v, thing_type, id):
else: author.agendaposter = int(time.time()) + 86400
badge_grant(user=author, badge_id=28)
if v.admin_level >= PERMS['USER_AGENDAPOSTER']:
ma = ModAction(
kind="agendaposter",
user_id=v.id,
target_user_id=author.id,
_note=f"for 1 day"
)
g.db.add(ma)
elif kind == "flairlock":
if thing.ghost: abort(403)
new_name = note[:100].replace("𒐪","")

View File

@ -33,12 +33,7 @@ WORDLE_COLOR_MAPPINGS = {-1: "🟥", 0: "🟨", 1: "🟩"}
@app.get("/logged_out/h/<sub>/post/<pid>/<anything>/<cid>")
@auth_desired_with_logingate
def post_pid_comment_cid(cid, pid=None, anything=None, v=None, sub=None):
try: cid = int(cid)
except: abort(404)
comment = get_comment(cid, v=v)
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 >= PERMS['USER_SHADOWBAN']):
@ -60,9 +55,6 @@ def post_pid_comment_cid(cid, pid=None, anything=None, v=None, sub=None):
elif SITE == 'pcmemes.net': pid = 2487
else: pid = 1
try: pid = int(pid)
except: abort(404)
post = get_post(pid, v=v)
if post.over_18 and not (v and v.over_18) and not session.get('over_18', 0) >= int(time.time()):
@ -163,13 +155,14 @@ def comment(v):
level = parent.level + 1
if parent.author_id == v.id: rts = True
else: abort(400)
if not parent.can_see(v): abort(404)
if parent.deleted_utc != 0: abort(404)
body = request.values.get("body", "").strip().replace('','')
if level > COMMENT_MAX_DEPTH:
return {"error": f"Max comment level is {COMMENT_MAX_DEPTH}"}, 400
body = body.replace('\r\n', '\n')[:10000]
body = sanitize_raw_body(request.values.get("body", ""), False)
if parent_post.id not in ADMIGGERS:
if v.longpost and (len(body) < 280 or ' [](' in body or body.startswith('[](')):
@ -239,7 +232,7 @@ def comment(v):
else:
abort(415)
body = body.strip()
body = body.strip()[:COMMENT_BODY_LENGTH_LIMIT]
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:
@ -266,9 +259,9 @@ def comment(v):
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 < PERMS['POST_COMMENT_MODERATION']:
return {"error": "You can't reply to users who have blocked you, or users you have blocked."}, 403
return {"error": "You can't reply to users who have blocked you or users that you have blocked."}, 403
is_bot = v.id != 12125 and (bool(request.headers.get("Authorization")) or (SITE == 'pcmemes.net' and v.id == SNAPPY_ID))
is_bot = v.id != BBBB_ID and (bool(request.headers.get("Authorization")) or (SITE == 'pcmemes.net' and v.id == SNAPPY_ID))
if len(body) > 50:
now = int(time.time())
@ -308,10 +301,7 @@ def comment(v):
g.db.commit()
return {"error": "Too much spam!"}, 403
if len(body_html) > 20000: abort(400)
if level > 200:
return {"error": "Max comment level is 200"}, 400
if len(body_html) > COMMENT_BODY_HTML_LENGTH_LIMIT: abort(400)
c = Comment(author_id=v.id,
parent_submission=parent_submission,
@ -321,7 +311,7 @@ def comment(v):
is_bot=is_bot,
app_id=v.client.application.id if v.client else None,
body_html=body_html,
body=body[:10000],
body=body,
ghost=parent_post.ghost
)
@ -355,37 +345,7 @@ def comment(v):
g.db.add(choice)
if SITE == 'pcmemes.net' and c.body.lower().startswith("based"):
pill = based_regex.match(body)
if level == 1: basedguy = get_account(parent_post.author_id)
else: basedguy = get_account(c.parent_comment.author_id)
basedguy.basedcount += 1
if pill:
if basedguy.pills: basedguy.pills += f", {pill.group(1)}"
else: basedguy.pills += f"{pill.group(1)}"
g.db.add(basedguy)
body2 = f"@{basedguy.username}'s Based Count has increased by 1. Their Based Count is now {basedguy.basedcount}."
if basedguy.pills: body2 += f"\n\nPills: {basedguy.pills}"
body_based_html = sanitize(body2)
c_based = Comment(author_id=BASEDBOT_ID,
parent_submission=parent_submission,
distinguish_level=6,
parent_comment_id=c.id,
level=level+1,
is_bot=True,
body_html=body_based_html,
top_comment_id=c.top_comment_id,
ghost=c.ghost
)
g.db.add(c_based)
g.db.flush()
n = Notification(comment_id=c_based.id, user_id=v.id)
g.db.add(n)
execute_basedbot(c, level, body, parent_submission, parent_post, v)
if v.agendaposter and not v.marseyawarded and AGENDAPOSTER_PHRASE not in c.body.lower() and parent_post.sub != 'chudrama':
@ -419,101 +379,9 @@ def comment(v):
n = Notification(comment_id=c_jannied.id, user_id=v.id)
g.db.add(n)
if SITE_NAME == 'rDrama' and len(c.body.split()) >= 200 and "<" not in body and "</blockquote>" not in body_html:
body = random.choice(LONGPOST_REPLIES)
if body.startswith(''):
body = body[1:]
vote = CommentVote(user_id=LONGPOSTBOT_ID,
vote_type=-1,
comment_id=c.id,
real = True
)
g.db.add(vote)
c.downvotes = 1
c2 = Comment(author_id=LONGPOSTBOT_ID,
parent_submission=parent_submission,
parent_comment_id=c.id,
level=level+1,
is_bot=True,
body=body,
body_html=f"<p>{body}</p>",
top_comment_id=c.top_comment_id,
ghost=c.ghost
)
g.db.add(c2)
longpostbot = get_account(LONGPOSTBOT_ID)
longpostbot.comment_count += 1
longpostbot.coins += 1
g.db.add(longpostbot)
g.db.flush()
n = Notification(comment_id=c2.id, user_id=v.id)
g.db.add(n)
if SITE_NAME == 'rDrama' and random.random() < 0.001:
c2 = Comment(author_id=ZOZBOT_ID,
parent_submission=parent_submission,
parent_comment_id=c.id,
level=level+1,
is_bot=True,
body="zoz",
body_html="<p>zoz</p>",
top_comment_id=c.top_comment_id,
ghost=c.ghost,
distinguish_level=6
)
g.db.add(c2)
g.db.flush()
n = Notification(comment_id=c2.id, user_id=v.id)
g.db.add(n)
c3 = Comment(author_id=ZOZBOT_ID,
parent_submission=parent_submission,
parent_comment_id=c2.id,
level=level+2,
is_bot=True,
body="zle",
body_html="<p>zle</p>",
top_comment_id=c.top_comment_id,
ghost=c.ghost,
distinguish_level=6
)
g.db.add(c3)
g.db.flush()
c4 = Comment(author_id=ZOZBOT_ID,
parent_submission=parent_submission,
parent_comment_id=c3.id,
level=level+3,
is_bot=True,
body="zozzle",
body_html="<p>zozzle</p>",
top_comment_id=c.top_comment_id,
ghost=c.ghost,
distinguish_level=6
)
g.db.add(c4)
zozbot = get_account(ZOZBOT_ID)
zozbot.comment_count += 3
zozbot.coins += 3
g.db.add(zozbot)
if SITE_NAME == 'rDrama':
execute_longpostbot(c, level, body, body_html, parent_submission, v)
execute_zozbot(c, level, parent_submission, v)
if not v.shadowbanned:
notify_users = NOTIFY_USERS(body, v)
@ -600,17 +468,15 @@ def comment(v):
@limiter.limit("1/second;10/minute;100/hour;200/day", key_func=lambda:f'{SITE}-{session.get("lo_user")}')
@auth_required
def edit_comment(cid, v):
c = get_comment(cid, v=v)
if time.time() - c.created_utc > 7*24*60*60 and not (c.post and c.post.private):
return {"error":"You can't edit comments older than 1 week!"}, 403
if c.author_id != v.id: abort(403)
if not c.post: abort(403)
body = request.values.get("body", "").strip().replace('','')
body = body.replace('\r\n', '\n')[:10000]
body = sanitize_raw_body(request.values.get("body", ""), False)
if len(body) < 1 and not (request.files.get("file") and request.headers.get("cf-ipcountry") != "T1"):
return {"error":"You have to actually type something!"}, 400
@ -674,8 +540,7 @@ def edit_comment(cid, v):
return {"error": "Too much spam!"}, 403
body += process_files()
body = body.strip()
body = body.strip()[:COMMENT_BODY_LENGTH_LIMIT] # process_files potentially adds characters to the post
body_for_sanitize = body
if v.owoify:
@ -687,12 +552,12 @@ def edit_comment(cid, v):
body_html = sanitize(body_for_sanitize, golden=False, limit_pings=5, torture=torture)
if len(body_html) > 20000: abort(400)
if len(body_html) > COMMENT_BODY_HTML_LENGTH_LIMIT: abort(400)
if v.marseyawarded and marseyaward_body_regex.search(body_html):
return {"error":"You can only type marseys!"}, 403
c.body = body[:10000]
c.body = body
c.body_html = body_html
if blackjack and any(i in c.body.lower() for i in blackjack.split()):

View File

@ -21,18 +21,20 @@ def join_discord(v):
@app.get("/discord_redirect")
@auth_required
@is_not_permabanned
def discord_redirect(v):
if v.shadowbanned: abort(400)
now = int(time.time())
state = request.values.get('state')
if not state or not '.' in state: abort(400)
state = state.split('.')
timestamp= state[0]
state= state[1]
now=int(time.time())
state=request.values.get('state','').split('.')
timestamp=state[0]
state=state[1]
if int(timestamp) < now-600:
try:
if int(timestamp) < now-600:
abort(400)
except:
abort(400)
if not validate_hash(f"{timestamp}+{v.id}+discord", state):

View File

@ -189,7 +189,7 @@ def random_post(v):
@app.get("/random_user")
@auth_required
def random_user(v):
u = g.db.query(User.username).filter(User.song != None).order_by(func.random()).first()
u = g.db.query(User.username).filter(User.song != None, User.shadowbanned == None).order_by(func.random()).first()
if u: u = u[0]
else: return "No users have set a profile anthem so far!"

View File

@ -353,7 +353,7 @@ def viewmore(v, pid, sort, offset):
@auth_desired_with_logingate
def morecomments(v, cid):
try: cid = int(cid)
except: abort(400)
except: abort(404)
tcid = g.db.query(Comment.top_comment_id).filter_by(id=cid).one_or_none()[0]
@ -412,8 +412,7 @@ def edit_post(pid, v):
abort(403)
title = sanitize_raw_title(request.values.get("title", ""))
body = sanitize_raw_body(request.values.get("body", ""))
body = sanitize_raw_body(request.values.get("body", ""), True)
if v.id == p.author_id:
if v.longpost and (len(body) < 280 or ' [](' in body or body.startswith('[](')):
@ -695,8 +694,7 @@ def submit_post(v, sub=None):
if '\\' in url: abort(400)
title = sanitize_raw_title(request.values.get("title", ""))
body = sanitize_raw_body(request.values.get("body", ""))
body = sanitize_raw_body(request.values.get("body", ""), True)
def error(error):
if request.headers.get("Authorization") or request.headers.get("xhr"): return {"error": error}, 400
@ -909,7 +907,7 @@ def submit_post(v, sub=None):
if embed and len(embed) > 1500: embed = None
is_bot = v.id != 12125 and bool(request.headers.get("Authorization")) or (SITE == 'pcmemes.net' and v.id == SNAPPY_ID)
is_bot = v.id != BBBB_ID and bool(request.headers.get("Authorization")) or (SITE == 'pcmemes.net' and v.id == SNAPPY_ID)
if request.values.get("ghost") and v.coins >= 100:
v.coins -= 100

View File

@ -12,9 +12,6 @@ import tldextract
@is_not_permabanned
def exile_post(v, pid):
if v.shadowbanned: return {"error": "Internal Server Error"}, 500
try: pid = int(pid)
except: abort(400)
p = get_post(pid)
sub = p.sub
if not sub: abort(400)
@ -354,9 +351,6 @@ def create_sub2(v):
@app.post("/kick/<pid>")
@is_not_permabanned
def kick(v, pid):
try: pid = int(pid)
except: abort(400)
post = get_post(pid)
if not post.sub: abort(403)

View File

@ -21,10 +21,7 @@ import os
import json
from .login import check_for_alts
@app.get("/@<username>/upvoters/<uid>/posts")
@auth_required
def upvoters_posts(v, username, uid):
def upvoters_downvoters(v, username, uid, cls, vote_cls, vote_dir, template, standalone):
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 < 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)
@ -33,7 +30,7 @@ def upvoters_posts(v, username, uid):
page = max(1, int(request.values.get("page", 1)))
listing = g.db.query(Submission).join(Vote).filter(Submission.ghost == False, Submission.is_banned == False, Submission.deleted_utc == 0, Vote.vote_type==1, Submission.author_id==id, Vote.user_id==uid).order_by(Submission.created_utc.desc()).offset(25 * (page - 1)).limit(26).all()
listing = g.db.query(cls).join(vote_cls).filter(cls.ghost == False, cls.is_banned == False, cls.deleted_utc == 0, vote_cls.vote_type==vote_dir, cls.author_id==id, vote_cls.user_id==uid).order_by(cls.created_utc.desc()).offset(25 * (page - 1)).limit(26).all()
listing = [p.id for p in listing]
next_exists = len(listing) > 25
@ -41,56 +38,32 @@ def upvoters_posts(v, username, uid):
listing = get_posts(listing, v=v)
return render_template("voted_posts.html", next_exists=next_exists, listing=listing, page=page, v=v)
return render_template(template, next_exists=next_exists, listing=listing, page=page, v=v, standalone=standalone)
@app.get("/@<username>/upvoters/<uid>/posts")
@auth_required
def upvoters_posts(v, username, uid):
return upvoters_downvoters(v, username, uid, Submission, Vote, 1, "voted_posts.html", None)
@app.get("/@<username>/upvoters/<uid>/comments")
@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 < 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)
page = max(1, int(request.values.get("page", 1)))
listing = g.db.query(Comment).join(CommentVote).filter(Comment.ghost == False, Comment.is_banned == False, Comment.deleted_utc == 0, CommentVote.vote_type==1, Comment.author_id==id, CommentVote.user_id==uid).order_by(Comment.id.desc()).offset(25 * (page - 1)).limit(26).all()
listing = [c.id for c in listing]
next_exists = len(listing) > 25
listing = listing[:25]
listing = get_comments(listing, v=v)
return render_template("voted_comments.html", next_exists=next_exists, listing=listing, page=page, v=v, standalone=True)
return upvoters_downvoters(v, username, uid, Comment, CommentVote, 1, "voted_comments.html", True)
@app.get("/@<username>/downvoters/<uid>/posts")
@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 < 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)
page = max(1, int(request.values.get("page", 1)))
listing = g.db.query(Submission).join(Vote).filter(Submission.ghost == False, Submission.is_banned == False, Submission.deleted_utc == 0, Vote.vote_type==-1, Submission.author_id==id, Vote.user_id==uid).order_by(Submission.created_utc.desc()).offset(25 * (page - 1)).limit(26).all()
listing = [p.id for p in listing]
next_exists = len(listing) > 25
listing = listing[:25]
listing = get_posts(listing, v=v)
return render_template("voted_posts.html", next_exists=next_exists, listing=listing, page=page, v=v)
return upvoters_downvoters(v, username, uid, Submission, Vote, -1, "voted_posts.html", None)
@app.get("/@<username>/downvoters/<uid>/comments")
@auth_required
def downvoters_comments(v, username, uid):
return upvoters_downvoters(v, username, uid, Comment, CommentVote, -1, "voted_comments.html", True)
def upvoting_downvoting(v, username, uid, cls, vote_cls, vote_dir, template, standalone):
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 < 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)
@ -99,32 +72,7 @@ def downvoters_comments(v, username, uid):
page = max(1, int(request.values.get("page", 1)))
listing = g.db.query(Comment).join(CommentVote).filter(Comment.ghost == False, Comment.is_banned == False, Comment.deleted_utc == 0, CommentVote.vote_type==-1, Comment.author_id==id, CommentVote.user_id==uid).order_by(Comment.id.desc()).offset(25 * (page - 1)).limit(26).all()
listing = [c.id for c in listing]
next_exists = len(listing) > 25
listing = listing[:25]
listing = get_comments(listing, v=v)
return render_template("voted_comments.html", next_exists=next_exists, listing=listing, page=page, v=v, standalone=True)
@app.get("/@<username>/upvoting/<uid>/posts")
@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 < 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)
page = max(1, int(request.values.get("page", 1)))
listing = g.db.query(Submission).join(Vote).filter(Submission.ghost == False, Submission.is_banned == False, Submission.deleted_utc == 0, Vote.vote_type==1, Vote.user_id==id, Submission.author_id==uid).order_by(Submission.created_utc.desc()).offset(25 * (page - 1)).limit(26).all()
listing = g.db.query(cls).join(vote_cls).filter(cls.ghost == False, cls.is_banned == False, cls.deleted_utc == 0, vote_cls.vote_type==vote_dir, vote_cls.user_id==id, cls.author_id==uid).order_by(cls.created_utc.desc()).offset(25 * (page - 1)).limit(26).all()
listing = [p.id for p in listing]
next_exists = len(listing) > 25
@ -132,125 +80,64 @@ def upvoting_posts(v, username, uid):
listing = get_posts(listing, v=v)
return render_template("voted_posts.html", next_exists=next_exists, listing=listing, page=page, v=v)
return render_template(template, next_exists=next_exists, listing=listing, page=page, v=v, standalone=standalone)
@app.get("/@<username>/upvoting/<uid>/posts")
@auth_required
def upvoting_posts(v, username, uid):
return upvoting_downvoting(v, username, uid, Submission, Vote, 1, "voted_posts.html", None)
@app.get("/@<username>/upvoting/<uid>/comments")
@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 < 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)
page = max(1, int(request.values.get("page", 1)))
listing = g.db.query(Comment).join(CommentVote).filter(Comment.ghost == False, Comment.is_banned == False, Comment.deleted_utc == 0, CommentVote.vote_type==1, CommentVote.user_id==id, Comment.author_id==uid).order_by(Comment.id.desc()).offset(25 * (page - 1)).limit(26).all()
listing = [c.id for c in listing]
next_exists = len(listing) > 25
listing = listing[:25]
listing = get_comments(listing, v=v)
return render_template("voted_comments.html", next_exists=next_exists, listing=listing, page=page, v=v, standalone=True)
return upvoting_downvoting(v, username, uid, Comment, CommentVote, 1, "voted_comments.html", True)
@app.get("/@<username>/downvoting/<uid>/posts")
@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 < 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)
page = max(1, int(request.values.get("page", 1)))
listing = g.db.query(Submission).join(Vote).filter(Submission.ghost == False, Submission.is_banned == False, Submission.deleted_utc == 0, Vote.vote_type==-1, Vote.user_id==id, Submission.author_id==uid).order_by(Submission.created_utc.desc()).offset(25 * (page - 1)).limit(26).all()
listing = [p.id for p in listing]
next_exists = len(listing) > 25
listing = listing[:25]
listing = get_posts(listing, v=v)
return render_template("voted_posts.html", next_exists=next_exists, listing=listing, page=page, v=v)
return upvoting_downvoting(v, username, uid, Submission, Vote, -1, "voted_posts.html", None)
@app.get("/@<username>/downvoting/<uid>/comments")
@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 < 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)
return upvoting_downvoting(v, username, uid, Comment, CommentVote, -1, "voted_comments.html", True)
page = max(1, int(request.values.get("page", 1)))
listing = g.db.query(Comment).join(CommentVote).filter(Comment.ghost == False, Comment.is_banned == False, Comment.deleted_utc == 0, CommentVote.vote_type==-1, CommentVote.user_id==id, Comment.author_id==uid).order_by(Comment.id.desc()).offset(25 * (page - 1)).limit(26).all()
listing = [c.id for c in listing]
next_exists = len(listing) > 25
listing = listing[:25]
listing = get_comments(listing, v=v)
return render_template("voted_comments.html", next_exists=next_exists, listing=listing, page=page, v=v, standalone=True)
@app.get("/@<username>/upvoted/posts")
@auth_required
def user_upvoted_posts(v, username):
def user_voted(v, username, cls, vote_cls, vote_dir, template, standalone):
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 < 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)))
listing = g.db.query(Submission).join(Vote).filter(
Submission.ghost == False,
Submission.is_banned == False,
Submission.deleted_utc == 0,
Submission.author_id != u.id,
Vote.user_id == u.id,
Vote.vote_type == 1
).order_by(Submission.created_utc.desc()).offset(25 * (page - 1)).limit(26).all()
listing = g.db.query(cls).join(vote_cls).filter(
cls.ghost == False,
cls.is_banned == False,
cls.deleted_utc == 0,
cls.author_id != u.id,
vote_cls.user_id == u.id,
vote_cls.vote_type == vote_dir
).order_by(cls.created_utc.desc()).offset(25 * (page - 1)).limit(26).all()
listing = [p.id for p in listing]
next_exists = len(listing) > 25
listing = listing[:25]
listing = get_posts(listing, v=v)
return render_template("voted_posts.html", next_exists=next_exists, listing=listing, page=page, v=v)
return render_template(template, next_exists=next_exists, listing=listing, page=page, v=v, standalone=standalone)
@app.get("/@<username>/upvoted/posts")
@auth_required
def user_upvoted_posts(v, username):
return user_voted(v, username, Submission, Vote, 1, "voted_posts.html", None)
@app.get("/@<username>/upvoted/comments")
@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 < 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)))
listing = g.db.query(Comment).join(CommentVote).filter(
Comment.ghost == False,
Comment.is_banned == False,
Comment.deleted_utc == 0,
Comment.author_id != u.id,
CommentVote.user_id == u.id,
CommentVote.vote_type == 1
).order_by(Comment.created_utc.desc()).offset(25 * (page - 1)).limit(26).all()
listing = [c.id for c in listing]
next_exists = len(listing) > 25
listing = listing[:25]
listing = get_comments(listing, v=v)
return render_template("voted_comments.html", next_exists=next_exists, listing=listing, page=page, v=v, standalone=True)
return user_voted(v, username, Comment, CommentVote, -1, "voted_comments.html", True)
@app.get("/poorcels")
@ -274,134 +161,70 @@ def agendaposters(v):
users = g.db.query(User).filter(User.agendaposter > 0).order_by(User.username).all()
return render_template("agendaposters.html", v=v, users=users)
def all_upvoters_downvoters(v, username, vote_dir, is_who_simps_hates):
vote_str = 'votes'
simps_haters = 'voters'
vote_name = 'Neutral'
if vote_dir == 1:
vote_str = 'upvotes'
simps_haters = 'simps for' if is_who_simps_hates else 'simps'
vote_name = 'Up'
elif vote_dir == -1:
vote_str = 'downvotes'
simps_haters = 'hates' if is_who_simps_hates else 'haters'
vote_name = 'Down'
id = get_user(username, v=v, include_shadowbanned=False).id
if not (v.id == id or v.admin_level >= PERMS['USER_VOTERS_VISIBLE']):
abort(403)
votes = []
votes2 = []
if is_who_simps_hates:
votes = g.db.query(Submission.author_id, func.count(Submission.author_id)).join(Vote).filter(Submission.ghost == False, Submission.is_banned == False, Submission.deleted_utc == 0, Vote.vote_type==vote_dir, Vote.user_id==id).group_by(Submission.author_id).order_by(func.count(Submission.author_id).desc()).all()
votes2 = g.db.query(Comment.author_id, func.count(Comment.author_id)).join(CommentVote).filter(Comment.ghost == False, Comment.is_banned == False, Comment.deleted_utc == 0, CommentVote.vote_type==vote_dir, CommentVote.user_id==id).group_by(Comment.author_id).order_by(func.count(Comment.author_id).desc()).all()
else:
votes = g.db.query(Vote.user_id, func.count(Vote.user_id)).join(Submission).filter(Submission.ghost == False, Submission.is_banned == False, Submission.deleted_utc == 0, Vote.vote_type==vote_dir, Submission.author_id==id).group_by(Vote.user_id).order_by(func.count(Vote.user_id).desc()).all()
votes2 = g.db.query(CommentVote.user_id, func.count(CommentVote.user_id)).join(Comment).filter(Comment.ghost == False, Comment.is_banned == False, Comment.deleted_utc == 0, CommentVote.vote_type==vote_dir, Comment.author_id==id).group_by(CommentVote.user_id).order_by(func.count(CommentVote.user_id).desc()).all()
votes = Counter(dict(votes)) + Counter(dict(votes2))
total = sum(votes.values())
users = g.db.query(User).filter(User.id.in_(votes.keys())).all()
users2 = []
for user in users:
users2.append((user, votes[user.id]))
users = sorted(users2, key=lambda x: x[1], reverse=True)
try:
pos = [x[0].id for x in users].index(v.id)
pos = (pos+1, users[pos][1])
except: pos = (len(users)+1, 0)
received_given = 'given' if is_who_simps_hates else 'received'
if total == 1: vote_str = vote_str[:-1] # we want to unpluralize if only 1 vote
total = f'{total} {vote_str} {received_given}'
name2 = f'Who @{username} {simps_haters}' if is_who_simps_hates else f'@{username} biggest {simps_haters}'
return render_template("voters.html", v=v, users=users[:25], pos=pos, name=vote_name, name2=name2, total=total)
@app.get("/@<username>/upvoters")
@auth_required
def upvoters(v, username):
id = get_user(username, v=v, include_shadowbanned=False).id
if not (v.id == id or v.admin_level >= PERMS['USER_VOTERS_VISIBLE']):
abort(403)
votes = g.db.query(Vote.user_id, func.count(Vote.user_id)).join(Submission).filter(Submission.ghost == False, Submission.is_banned == False, Submission.deleted_utc == 0, Vote.vote_type==1, Submission.author_id==id).group_by(Vote.user_id).order_by(func.count(Vote.user_id).desc()).all()
votes2 = g.db.query(CommentVote.user_id, func.count(CommentVote.user_id)).join(Comment).filter(Comment.ghost == False, Comment.is_banned == False, Comment.deleted_utc == 0, CommentVote.vote_type==1, Comment.author_id==id).group_by(CommentVote.user_id).order_by(func.count(CommentVote.user_id).desc()).all()
votes = Counter(dict(votes)) + Counter(dict(votes2))
total = sum(votes.values())
users = g.db.query(User).filter(User.id.in_(votes.keys())).all()
users2 = []
for user in users: users2.append((user, votes[user.id]))
users = sorted(users2, key=lambda x: x[1], reverse=True)
try:
pos = [x[0].id for x in users].index(v.id)
pos = (pos+1, users[pos][1])
except: pos = (len(users)+1, 0)
if total == 1: total=f'{total} upvote received'
else: total=f'{total} upvotes received'
return render_template("voters.html", v=v, users=users[:25], pos=pos, name='Up', name2=f'@{username} biggest simps', total=total)
return all_upvoters_downvoters(v, username, 1, False)
@app.get("/@<username>/downvoters")
@auth_required
def downvoters(v, username):
id = get_user(username, v=v, include_shadowbanned=False).id
if not (v.id == id or v.admin_level >= PERMS['USER_VOTERS_VISIBLE']):
abort(403)
votes = g.db.query(Vote.user_id, func.count(Vote.user_id)).join(Submission).filter(Submission.ghost == False, Submission.is_banned == False, Submission.deleted_utc == 0, Vote.vote_type==-1, Submission.author_id==id).group_by(Vote.user_id).order_by(func.count(Vote.user_id).desc()).all()
votes2 = g.db.query(CommentVote.user_id, func.count(CommentVote.user_id)).join(Comment).filter(Comment.ghost == False, Comment.is_banned == False, Comment.deleted_utc == 0, CommentVote.vote_type==-1, Comment.author_id==id).group_by(CommentVote.user_id).order_by(func.count(CommentVote.user_id).desc()).all()
votes = Counter(dict(votes)) + Counter(dict(votes2))
total = sum(votes.values())
users = g.db.query(User).filter(User.id.in_(votes.keys())).all()
users2 = []
for user in users: users2.append((user, votes[user.id]))
users = sorted(users2, key=lambda x: x[1], reverse=True)
try:
pos = [x[0].id for x in users].index(v.id)
pos = (pos+1, users[pos][1])
except: pos = (len(users)+1, 0)
if total == 1: total=f'{total} downvote received'
else: total=f'{total} downvotes received'
return render_template("voters.html", v=v, users=users[:25], pos=pos, name='Down', name2=f'@{username} biggest haters', total=total)
return all_upvoters_downvoters(v, username, -1, False)
@app.get("/@<username>/upvoting")
@auth_required
def upvoting(v, username):
id = get_user(username, v=v, include_shadowbanned=False).id
if not (v.id == id or v.admin_level >= PERMS['USER_VOTERS_VISIBLE']):
abort(403)
votes = g.db.query(Submission.author_id, func.count(Submission.author_id)).join(Vote).filter(Submission.ghost == False, Submission.is_banned == False, Submission.deleted_utc == 0, Vote.vote_type==1, Vote.user_id==id).group_by(Submission.author_id).order_by(func.count(Submission.author_id).desc()).all()
votes2 = g.db.query(Comment.author_id, func.count(Comment.author_id)).join(CommentVote).filter(Comment.ghost == False, Comment.is_banned == False, Comment.deleted_utc == 0, CommentVote.vote_type==1, CommentVote.user_id==id).group_by(Comment.author_id).order_by(func.count(Comment.author_id).desc()).all()
votes = Counter(dict(votes)) + Counter(dict(votes2))
total = sum(votes.values())
users = g.db.query(User).filter(User.id.in_(votes.keys())).all()
users2 = []
for user in users: users2.append((user, votes[user.id]))
users = sorted(users2, key=lambda x: x[1], reverse=True)
try:
pos = [x[0].id for x in users].index(v.id)
pos = (pos+1, users[pos][1])
except: pos = (len(users)+1, 0)
if total == 1: total=f'{total} upvote given'
else: total=f'{total} upvotes given'
return render_template("voters.html", v=v, users=users[:25], pos=pos, name='Up', name2=f'Who @{username} simps for', total=total)
return all_upvoters_downvoters(v, username, 1, True)
@app.get("/@<username>/downvoting")
@auth_required
def downvoting(v, username):
id = get_user(username, v=v, include_shadowbanned=False).id
if not (v.id == id or v.admin_level >= PERMS['USER_VOTERS_VISIBLE']):
abort(403)
votes = g.db.query(Submission.author_id, func.count(Submission.author_id)).join(Vote).filter(Submission.ghost == False, Submission.is_banned == False, Submission.deleted_utc == 0, Vote.vote_type==-1, Vote.user_id==id).group_by(Submission.author_id).order_by(func.count(Submission.author_id).desc()).all()
votes2 = g.db.query(Comment.author_id, func.count(Comment.author_id)).join(CommentVote).filter(Comment.ghost == False, Comment.is_banned == False, Comment.deleted_utc == 0, CommentVote.vote_type==-1, CommentVote.user_id==id).group_by(Comment.author_id).order_by(func.count(Comment.author_id).desc()).all()
votes = Counter(dict(votes)) + Counter(dict(votes2))
total = sum(votes.values())
users = g.db.query(User).filter(User.id.in_(votes.keys())).all()
users2 = []
for user in users: users2.append((user, votes[user.id]))
users = sorted(users2, key=lambda x: x[1], reverse=True)
try:
pos = [x[0].id for x in users].index(v.id)
pos = (pos+1, users[pos][1])
except: pos = (len(users)+1, 0)
if total == 1: total=f'{total} downvote given'
else: total=f'{total} downvotes given'
return render_template("voters.html", v=v, users=users[:25], pos=pos, name='Down', name2=f'Who @{username} hates', total=total)
return all_upvoters_downvoters(v, username, -1, True)
@app.post("/@<username>/suicide")
@limiter.limit("1/second;5/day")
@ -452,7 +275,7 @@ def transfer_coins(v, username):
notif_text = f":marseycapitalistmanlet: @{v.username} has gifted you {amount-tax} coins!"
if reason:
if len(reason) > 200: return {"error": "Reason is too long, max 200 characters"},400
if len(reason) > TRANSFER_MESSAGE_LENGTH_LIMIT: return {"error": f"Reason is too long, max {TRANSFER_MESSAGE_LENGTH_LIMIT} characters"},400
notif_text += f"\n\n> {reason}"
log_message += f"\n\n> {reason}"
@ -743,7 +566,7 @@ def message2(v, username):
@auth_required
def messagereply(v):
body = request.values.get("body", "").strip().replace('','')
body = body.replace('\r\n', '\n')[:10000]
body = body.replace('\r\n', '\n')[:COMMENT_BODY_LENGTH_LIMIT]
if not body and not request.files.get("file"): return {"error": "Message is empty!"}, 400
@ -1009,8 +832,6 @@ def u_username(username, v=None):
next_exists=next_exists,
is_following=is_following)
if request.headers.get("Authorization") or request.path.endswith(".json"):
return {"data": [x.json for x in listing]}

View File

@ -100,7 +100,7 @@
<h4>Configuration</h4>
<ul>
{% if v.admin_level >= PERMS['HOLE_CREATE'] %}
<li><a href="/create_hole">Create {{ HOLE_NAME | capitalize }}</a></li>
<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>
@ -150,7 +150,7 @@
<h4>Server Status</h4>
<div>
Live Revision: <code>{{ gitref }}</code> <br>
Live Revision: <code>{{gitref}}</code> <br>
</div>
{% endblock %}

View File

@ -32,8 +32,8 @@
</td>
<td>{{badge.description}}</td>
{%- set ct = counts[badge.id] if badge.id in counts else (0, 0) %}
<td class="badges-rarity-qty"><a href="/badge_owners/{{badge.id}}">{{ ct[0] }}</a></td>
<td class="badges-rarity-ratio">{{ "{:0.3f}".format(ct[1]) }}%</td>
<td class="badges-rarity-qty"><a href="/badge_owners/{{badge.id}}">{{ct[0]}}</a></td>
<td class="badges-rarity-ratio">{{"{:0.3f}".format(ct[1])}}%</td>
</tr>
{% endfor %}
</table>
@ -41,4 +41,4 @@
<script defer src="{{'js/sort_table.js' | asset}}"></script>
{% endblock %}
{% endblock %}

View File

@ -138,7 +138,7 @@
{% if c.bannedfor %}
<i class="fas fa-hammer-crash text-danger" data-bs-toggle="tooltip" data-bs-placement="bottom" title="User was banned for this comment {{c.bannedfor}}"></i>
{% 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.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 >= 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 %}

View File

@ -258,7 +258,7 @@
<img alt="/h/{{sub}} banner" onclick="expandDesktopImage()" src="{{sub.banner_url}}" width=100% style="object-fit:cover;max-height:min(42vh,30vw)!important">
</a>
{% elif SITE_NAME == 'rDrama' %}
<a href="https://secure.transequality.org/site/Donation2?df_id=1480">
<a rel="nofollow noopener noreferrer" href="https://secure.transequality.org/site/Donation2?df_id=1480">
{% if v and (v.is_banned or v.agendaposter) %}
<img alt="site banner" src="/i/{{SITE_NAME}}/banner2.webp?v=2000" width="100%">
{% else %}

View File

@ -11,11 +11,11 @@
<tbody>
<tr>
<td>Gumroad (subscription)</td>
<td><a href="{{GUMROAD_LINK}}">{{GUMROAD_LINK}}</a></td>
<td><a rel="nofollow noopener noreferrer" href="{{GUMROAD_LINK}}">{{GUMROAD_LINK}}</a></td>
</tr>
<tr>
<td>Gumroad (one-time)</td>
<td><a href="https://kippy.gumroad.com/l/onetime">https://kippy.gumroad.com/l/onetime</a></td>
<td><a rel="nofollow noopener noreferrer" href="https://kippy.gumroad.com/l/onetime">https://kippy.gumroad.com/l/onetime</a></td>
</tr>
<tr>
<td>Ethereum/Brave Attention Token</td>
@ -28,4 +28,4 @@
</tbody>
</table>
</div>
{% endblock %}
{% endblock %}

View File

@ -11,7 +11,7 @@
<tbody>
<tr>
<td>Kofi</td>
<td><a href="{{KOFI_LINK}}">{{KOFI_LINK}}</a></td>
<td><a rel="nofollow noopener noreferrer" href="{{KOFI_LINK}}">{{KOFI_LINK}}</a></td>
</tr>
<tr>
<td>Ethereum/Brave Attention Token</td>
@ -28,4 +28,4 @@
</tbody>
</table>
</div>
{% endblock %}
{% endblock %}

View File

@ -11,7 +11,7 @@
<tbody>
<tr>
<td>Gumroad</td>
<td><a href="{{GUMROAD_LINK}}">{{GUMROAD_LINK}}</a></td>
<td><a rel="nofollow noopener noreferrer" href="{{GUMROAD_LINK}}">{{GUMROAD_LINK}}</a></td>
</tr>
<tr>
<td>Ethereum/Brave Attention Token</td>
@ -27,13 +27,13 @@
</tr>
<tr>
<td>NFTs</td>
<td><a href="https://opensea.io/collection/marsey">https://opensea.io/collection/marsey</a></td>
<td><a rel="nofollow noopener noreferrer" href="https://opensea.io/collection/marsey">https://opensea.io/collection/marsey</a></td>
</tr>
<tr>
<td>Merch</td>
<td><a href="https://redbubble.com/people/rdramanet/explore?sortOrder=top%20selling">https://redbubble.com/people/rdramanet/explore?sortOrder=top%20selling</a></td>
<td><a rel="nofollow noopener noreferrer" href="https://redbubble.com/people/rdramanet/explore?sortOrder=top%20selling">https://redbubble.com/people/rdramanet/explore?sortOrder=top%20selling</a></td>
</tr>
</tbody>
</table>
</div>
{% endblock %}
{% endblock %}

View File

@ -1,7 +1,7 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta name="description" content="The true home of IP2." />
<meta name="description" content="rdrama.net caters to drama in all forms such as: Real life, videos, photos, gossip, rumors, news sites, Reddit, and Beyond™. There isn&#39;t drama we won&#39;t touch, and we want it all!" />
<meta http-equiv="Content-Security-Policy" content="script-src 'self' 'unsafe-inline' ajax.cloudflare.com; connect-src 'self'; object-src 'none';" />
@ -38,9 +38,9 @@
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no" />
<meta name="thumbnail" content="/i/PCM/site_preview.webp?v=3009" />
<meta name="thumbnail" content="/i/rDrama/site_preview.webp?v=3009" />
<link rel="icon" type="image/webp" href="/i/PCM/icon.webp?v=3009" />
<link rel="icon" type="image/webp" href="/i/rDrama/icon.webp?v=3009" />
<title>502 Bad Gateway</title>
@ -49,58 +49,58 @@
<meta name="format-detection" content="telephone=no" />
<meta name="viewport" content="width=device-width,initial-scale=1" />
<link rel="apple-touch-icon" sizes="180x180" href="/i/PCM/icon.webp?v=3009" />
<link rel="manifest" href="/assets/manifest_PCM.json?v=6" />
<link rel="mask-icon" href="/i/PCM/icon.webp?v=3009" />
<link rel="shortcut icon" href="/i/PCM/icon.webp?v=3009" />
<meta name="apple-mobile-web-app-title" content="PCM" />
<meta name="application-name" content="PCM" />
<link rel="apple-touch-icon" sizes="180x180" href="/i/rDrama/icon.webp?v=3009" />
<link rel="manifest" href="/assets/manifest_rDrama.json?v=6" />
<link rel="mask-icon" href="/i/rDrama/icon.webp?v=3009" />
<link rel="shortcut icon" href="/i/rDrama/icon.webp?v=3009" />
<meta name="apple-mobile-web-app-title" content="rDrama" />
<meta name="application-name" content="rDrama" />
<meta name="msapplication-TileColor" content="#ff66ac" />
<meta name="msapplication-config" content="/assets/browserconfig.xml?v=3009" />
<meta name="theme-color" content="#ff66ac" />
<link rel="apple-touch-startup-image" sizes="320x480" href="/i/PCM/icon.webp?v=3009" />
<link rel="apple-touch-startup-image" sizes="640x960" href="/i/PCM/icon.webp?v=3009" />
<link rel="apple-touch-icon" sizes="640x1136" href="/i/PCM/icon.webp?v=3009" />
<link rel="apple-touch-icon" sizes="750x1334" href="/i/PCM/icon.webp?v=3009" />
<link rel="apple-touch-startup-image" sizes="768x1004" href="/i/PCM/icon.webp?v=3009" />
<link rel="apple-touch-startup-image" sizes="768x1024" href="/i/PCM/icon.webp?v=3009" />
<link rel="apple-touch-startup-image" sizes="828x1792" href="/i/PCM/icon.webp?v=3009" />
<link rel="apple-touch-startup-image" sizes="1024x748" href="/i/PCM/icon.webp?v=3009" />
<link rel="apple-touch-startup-image" sizes="1024x768" href="/i/PCM/icon.webp?v=3009" />
<link rel="apple-touch-startup-image" sizes="1125x2436" href="/i/PCM/icon.webp?v=3009" />
<link rel="apple-touch-startup-image" sizes="1242x2208" href="/i/PCM/icon.webp?v=3009" />
<link rel="apple-touch-startup-image" sizes="1242x2688" href="/i/PCM/icon.webp?v=3009" />
<link rel="apple-touch-startup-image" sizes="1334x750" href="/i/PCM/icon.webp?v=3009" />
<link rel="apple-touch-startup-image" sizes="1536x2008" href="/i/PCM/icon.webp?v=3009" />
<link rel="apple-touch-startup-image" sizes="1536x2048" href="/i/PCM/icon.webp?v=3009" />
<link rel="apple-touch-startup-image" sizes="1668x2224" href="/i/PCM/icon.webp?v=3009" />
<link rel="apple-touch-startup-image" sizes="1792x828" href="/i/PCM/icon.webp?v=3009" />
<link rel="apple-touch-startup-image" sizes="2048x1496" href="/i/PCM/icon.webp?v=3009" />
<link rel="apple-touch-startup-image" sizes="2048x1536" href="/i/PCM/icon.webp?v=3009" />
<link rel="apple-touch-startup-image" sizes="2048x2732" href="/i/PCM/icon.webp?v=3009" />
<link rel="apple-touch-startup-image" sizes="2208x1242" href="/i/PCM/icon.webp?v=3009" />
<link rel="apple-touch-startup-image" sizes="2224x1668" href="/i/PCM/icon.webp?v=3009" />
<link rel="apple-touch-startup-image" sizes="2436x1125" href="/i/PCM/icon.webp?v=3009" />
<link rel="apple-touch-startup-image" sizes="2668x1242" href="/i/PCM/icon.webp?v=3009" />
<link rel="apple-touch-startup-image" sizes="2737x2048" href="/i/PCM/icon.webp?v=3009" />
<link rel="apple-touch-startup-image" sizes="320x480" href="/i/rDrama/icon.webp?v=3009" />
<link rel="apple-touch-startup-image" sizes="640x960" href="/i/rDrama/icon.webp?v=3009" />
<link rel="apple-touch-icon" sizes="640x1136" href="/i/rDrama/icon.webp?v=3009" />
<link rel="apple-touch-icon" sizes="750x1334" href="/i/rDrama/icon.webp?v=3009" />
<link rel="apple-touch-startup-image" sizes="768x1004" href="/i/rDrama/icon.webp?v=3009" />
<link rel="apple-touch-startup-image" sizes="768x1024" href="/i/rDrama/icon.webp?v=3009" />
<link rel="apple-touch-startup-image" sizes="828x1792" href="/i/rDrama/icon.webp?v=3009" />
<link rel="apple-touch-startup-image" sizes="1024x748" href="/i/rDrama/icon.webp?v=3009" />
<link rel="apple-touch-startup-image" sizes="1024x768" href="/i/rDrama/icon.webp?v=3009" />
<link rel="apple-touch-startup-image" sizes="1125x2436" href="/i/rDrama/icon.webp?v=3009" />
<link rel="apple-touch-startup-image" sizes="1242x2208" href="/i/rDrama/icon.webp?v=3009" />
<link rel="apple-touch-startup-image" sizes="1242x2688" href="/i/rDrama/icon.webp?v=3009" />
<link rel="apple-touch-startup-image" sizes="1334x750" href="/i/rDrama/icon.webp?v=3009" />
<link rel="apple-touch-startup-image" sizes="1536x2008" href="/i/rDrama/icon.webp?v=3009" />
<link rel="apple-touch-startup-image" sizes="1536x2048" href="/i/rDrama/icon.webp?v=3009" />
<link rel="apple-touch-startup-image" sizes="1668x2224" href="/i/rDrama/icon.webp?v=3009" />
<link rel="apple-touch-startup-image" sizes="1792x828" href="/i/rDrama/icon.webp?v=3009" />
<link rel="apple-touch-startup-image" sizes="2048x1496" href="/i/rDrama/icon.webp?v=3009" />
<link rel="apple-touch-startup-image" sizes="2048x1536" href="/i/rDrama/icon.webp?v=3009" />
<link rel="apple-touch-startup-image" sizes="2048x2732" href="/i/rDrama/icon.webp?v=3009" />
<link rel="apple-touch-startup-image" sizes="2208x1242" href="/i/rDrama/icon.webp?v=3009" />
<link rel="apple-touch-startup-image" sizes="2224x1668" href="/i/rDrama/icon.webp?v=3009" />
<link rel="apple-touch-startup-image" sizes="2436x1125" href="/i/rDrama/icon.webp?v=3009" />
<link rel="apple-touch-startup-image" sizes="2668x1242" href="/i/rDrama/icon.webp?v=3009" />
<link rel="apple-touch-startup-image" sizes="2737x2048" href="/i/rDrama/icon.webp?v=3009" />
</head>
<body id="error-502">
<a href="https://secure.transequality.org/site/Donation2?df_id=1480">
<img alt="site banner" src="/i/PCM/cached.webp?v=3009" width="100%" />
<a rel="nofollow noopener noreferrer" href="https://secure.transequality.org/site/Donation2?df_id=1480">
<img alt="site banner" src="/i/rDrama/cached.webp?v=3009" width="100%" />
</a>
<nav class="shadow-md fixed-top">
<div class="navbar navbar-expand-md navbar-light" id="navbar">
<div class="container-fluid" style="padding: 0;">
<a href="/" class="navbar-brand mr-auto">
<img id="header--icon" alt="header icon" src="/i/PCM/headericon.webp?v=3009" />
<img id="header--icon" alt="header icon" src="/i/rDrama/headericon.webp?v=3009" />
</a>
<div id="logo-container" class="flex-grow-1 logo-container">
<a href="/">
<img class="ml-1" id="logo" alt="logo" src="/i/PCM/logo.webp?v=3009" width="70" />
<img class="ml-1" id="logo" alt="logo" src="/i/rDrama/logo.webp?v=3009" width="70" />
</a>
</div>

View File

@ -24,7 +24,7 @@
<td>{% include "user_in_table.html" %}</td>
<td {% if follow.created_utc > 1599343262 %}data-time="{{follow.created_utc}}"{% endif %}></td>
{% if v.id == u.id %}
<td><div class="btn btn-danger pr-2" onclick="removeFollower(event, '{{user.username}}')">Remove follow</div></td>
<td><div class="btn btn-danger pr-2" onclick="removeFollower(this, '{{user.username}}')">Remove follow</div></td>
{% endif %}
</tr>
{% endfor %}

View File

@ -22,7 +22,7 @@
<td>{{loop.index}}</td>
<td>{% include "user_in_table.html" %}</td>
{% if v.id == u.id %}
<td><div class="btn btn-danger" onclick="removeFollowing(event, '{{user.username}}')">Unfollow</div></td>
<td><div class="btn btn-danger" onclick="removeFollowing(this, '{{user.username}}')">Unfollow</div></td>
{% endif %}
</tr>
{% endfor %}
@ -31,4 +31,4 @@
<script defer src="{{'js/following.js' | asset}}"></script>
{% endblock %}
{% endblock %}

View File

@ -521,7 +521,7 @@ line breaks
This is a &lt;a href='https://www.w3schools.com/tags/tag_a.asp'&gt;link&lt;/a&gt;
</td>
<td>
This is a <a href='https://www.w3schools.com/tags/tag_a.asp'>link</a>
This is a <a rel="nofollow noopener noreferrer" href='https://www.w3schools.com/tags/tag_a.asp'>link</a>
</td>
</tr>
<tr>

View File

@ -40,7 +40,7 @@
' throwing shade right now',
]
-%}
{{g.loggedin_counter+g.loggedout_counter}} {{ VISITORS_HERE_FLAVOR|random|safe }} ({{ g.loggedin_counter }} logged in)
{{g.loggedin_counter+g.loggedout_counter}} {{VISITORS_HERE_FLAVOR|random|safe}} ({{g.loggedin_counter}} logged in)
{% endif %}
{% else %}
{{g.loggedin_counter+g.loggedout_counter}} people here now ({{g.loggedin_counter}} logged in)
@ -225,7 +225,7 @@
</div>
<div class="text-left pl-2">
<div style="color: #{{v.name_color}}" class="text-small font-weight-bold"><span id="header--username" {% if v.patron %}class="patron" style="background-color:#{{v.name_color}}"{% endif %}>{{v.user_name}}</span></div>
<div class="header--currency"><img alt="coins" class="mr-1 ml-1" data-bs-toggle="tooltip" data-bs-placement="bottom" src="{{'coins.webp' | asset_siteimg}}" title="coins" aria-label="coins"><span id="user-coins-amount">{{v.coins}}</span>{% if not FEATURES['PROCOINS'] %} Coin{{ help.plural(v.coins) }}{% endif %}</div>
<div class="header--currency"><img alt="coins" class="mr-1 ml-1" data-bs-toggle="tooltip" data-bs-placement="bottom" src="{{'coins.webp' | asset_siteimg}}" title="coins" aria-label="coins"><span id="user-coins-amount">{{v.coins}}</span>{% if not FEATURES['PROCOINS'] %} Coin{{help.plural(v.coins)}}{% endif %}</div>
{% if FEATURES['PROCOINS'] %}
<div class="header--currency"><img alt="marseybux" class="mr-1 ml-1" data-bs-toggle="tooltip" data-bs-placement="bottom" src="/i/marseybux.webp?v=2000" title="Marseybux" aria-label="Marseybux"><span id="user-bux-amount">{{v.procoins}}</span></div>
{% endif %}
@ -253,8 +253,8 @@
<a class="dropdown-item" rel="nofollow noopener noreferrer" href="https://rdrama.net/post/18459"><i class="fas fa-bug fa-fw mr-3"></i>Bugs/Suggestions</a>
{% if SITE_NAME == 'rDrama' %}
<a class="dropdown-item" href="https://t.me/rdramanet"><i class="fab fa-telegram fa-fw mr-3"></i>Telegram Channel</a>
<a class="dropdown-item" href="https://t.me/+tOgq7xeeir83OTU0"><i class="fab fa-telegram fa-fw mr-3"></i>Telegram Chat</a>
<a rel="nofollow noopener noreferrer" class="dropdown-item" href="https://t.me/rdramanet"><i class="fab fa-telegram fa-fw mr-3"></i>Telegram Channel</a>
<a rel="nofollow noopener noreferrer" class="dropdown-item" href="https://t.me/+tOgq7xeeir83OTU0"><i class="fab fa-telegram fa-fw mr-3"></i>Telegram Chat</a>
<a class="dropdown-item" href="/discord"><i class="fab fa-discord fa-fw mr-3"></i>Discord</a>
{% endif %}
@ -319,8 +319,8 @@
<a class="nav-item nav-link" rel="nofollow noopener noreferrer" href="https://rdrama.net/post/18459"><i class="fas fa-bug fa-fw mr-3"></i>Bugs/Suggestions</a>
{% if SITE_NAME == 'rDrama' %}
<a class="nav-item nav-link" href="https://t.me/rdramanet"><i class="fab fa-telegram fa-fw mr-3"></i>Telegram Channel</a>
<a class="nav-item nav-link" href="https://t.me/+tOgq7xeeir83OTU0"><i class="fab fa-telegram fa-fw mr-3"></i>Telegram Chat</a>
<a rel="nofollow noopener noreferrer" class="nav-item nav-link" href="https://t.me/rdramanet"><i class="fab fa-telegram fa-fw mr-3"></i>Telegram Channel</a>
<a rel="nofollow noopener noreferrer" class="nav-item nav-link" href="https://t.me/+tOgq7xeeir83OTU0"><i class="fab fa-telegram fa-fw mr-3"></i>Telegram Chat</a>
<a class="nav-item nav-link" href="/discord"><i class="fab fa-discord fa-fw mr-3"></i>Discord</a>
{% endif %}

View File

@ -204,7 +204,7 @@
</style>
<div id="mobile-prompt-container" class="fixed-top">
<div id="mobile-prompt" href="javascript:void(0)" data-bs-toggle="tooltip" data-bs-container="#mobile-prompt-container" data-bs-placement="top" data-bs-trigger="click" data-bs-html="true" title="<i class='beg-icon fas fa-x'></i>Install the {{SITE_NAME}} webapp by saving this page to your home screen!"></div>
<div id="mobile-prompt" data-bs-toggle="tooltip" data-bs-container="#mobile-prompt-container" data-bs-placement="top" data-bs-trigger="click" data-bs-html="true" title="<i class='beg-icon fas fa-x'></i>Install the {{SITE_NAME}} webapp by saving this page to your home screen!"></div>
</div>
<script>
@ -213,7 +213,7 @@
document.addEventListener('DOMContentLoaded', function() {
const tt = bootstrap.Tooltip.getOrCreateInstance(document.getElementById('mobile-prompt'))
tt.show()
document.getElementsByClassName('tooltip')[0].onclick = function(event){
document.getElementsByClassName('tooltip')[0].onclick = function() {
tt.hide()
var xhr = new XMLHttpRequest();
xhr.withCredentials=true;

View File

@ -29,6 +29,6 @@ set JOURNOID_BANNERS = [
-%}
{% set journoid = JOURNOID_BANNERS|random %}
<a id="srd-link" href="{{ journoid[1] }}">{{ journoid[0] }}</a>
<a rel="nofollow noopener noreferrer" id="srd-link" href="{{journoid[1]}}">{{journoid[0]}}</a>
<span id="srd-separator">&mdash;</span>
<a id="srd-discuss" href="{{ journoid[2] }}">(discuss)</a>
<a id="srd-discuss" href="{{journoid[2]}}">(discuss)</a>

View File

@ -12,10 +12,13 @@
img.thumb {
border-radius: 4px;
}
.remove-streamer {
width: 50%
}
</style>
<script>
function go_to(e, link) {
if (!e.target.classList.contains('donttrigger'))
if (!e.target.classList.contains('remove-streamer'))
window.open(link, '_blank');
}
</script>
@ -59,7 +62,7 @@
<form action="/live/remove" method="post">
<input type="hidden" name="formkey" value="{{v.formkey}}">
<input type="hidden" name="id" value="{{id}}">
<input autocomplete="off" class="btn btn-primary ml-auto donttrigger" data-click="disable(this);this.parentElement.submit()" onclick="areyousure(this)" value="Remove">
<input autocomplete="off" class="btn btn-primary ml-auto remove-streamer" data-click="disable(this);this.parentElement.submit()" onclick="areyousure(this)" value="Remove">
</form>
</td>
{% endif %}
@ -84,7 +87,7 @@
<form action="/live/remove" method="post">
<input type="hidden" name="formkey" value="{{v.formkey}}">
<input type="hidden" name="id" value="{{id}}">
<input autocomplete="off" class="btn btn-primary ml-auto donttrigger" data-click="disable(this);this.parentElement.submit()" onclick="areyousure(this)" value="Remove">
<input autocomplete="off" class="btn btn-primary ml-auto remove-streamer" data-click="disable(this);this.parentElement.submit()" onclick="areyousure(this)" value="Remove">
</form>
</td>
{% endif %}

View File

@ -16,7 +16,7 @@
<td>
<img class="contain" alt="2{{user.patron}}" loading="lazy" width=29.33 height=32 src="/i/{{SITE_NAME}}/patron_badges/2{{user.patron}}.webp?v=1">
{% if user.patron_utc %}
<i class="{{ benefactor_def['icon'] }} {{ benefactor_def['color'] }} px-1"></i>
<i class="{{benefactor_def['icon']}} {{benefactor_def['color']}} px-1"></i>
{% endif %}
</td>
</tr>

View File

@ -56,8 +56,8 @@
{% endif %}
{% 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>
<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>
{% endif %}
{% if v.admin_level >= PERMS['POST_COMMENT_MODERATION'] %}

View File

@ -60,9 +60,9 @@
{% if FEATURES['PROCOINS'] %}
<span class="text-small text-muted pl-1">Must be same email as the one you used to donate on
{% if KOFI_TOKEN %}
<a class="text-primary" href="{{KOFI_LINK}}">Kofi</a>
<a rel="nofollow noopener noreferrer" class="text-primary" href="{{KOFI_LINK}}">Kofi</a>
{% else %}
<a class="text-primary" href="{{GUMROAD_LINK}}">Gumroad</a>
<a rel="nofollow noopener noreferrer" class="text-primary" href="{{GUMROAD_LINK}}">Gumroad</a>
{% endif %}
</span>
{% endif %}
@ -275,4 +275,4 @@
</div>
</div>
{% endblock %}
{% endblock %}

View File

@ -29,11 +29,11 @@
<a class="btn btn-primary btn-block" href="/post/4103">BUGS/SUGGESTIONS MEGATHREAD</a>
<a class="btn btn-primary btn-block" href="/post/9694" >OFFICIAL CONSPIRACY THEORY THREAD</a>
<a class="btn btn-primary btn-block" href="/post/10415">OFFICIAL GAMBLING THREAD</a>
<a class="btn btn-primary btn-block" href="https://imgur.com/a/UFGJybS">PCM Watermark Collection</a>
<a class="btn btn-primary btn-block" href="https://imgur.com/a/HxBfECG">TRS</a>
<a class="btn btn-primary btn-block" href="https://imgur.com/a/Wkw11eX">Current RV Cutouts</a>
<a class="btn btn-primary btn-block" href="https://imgur.com/a/B3XHKnD">PCM Shitposter Cutouts (1/?)</a>
<a class="btn btn-primary btn-block" href="https://imgur.com/a/2wDZddF">PCM Shitposter Cutouts (2/?)</a>
<a rel="nofollow noopener noreferrer" class="btn btn-primary btn-block" href="https://imgur.com/a/UFGJybS">PCM Watermark Collection</a>
<a rel="nofollow noopener noreferrer" class="btn btn-primary btn-block" href="https://imgur.com/a/HxBfECG">TRS</a>
<a rel="nofollow noopener noreferrer" class="btn btn-primary btn-block" href="https://imgur.com/a/Wkw11eX">Current RV Cutouts</a>
<a rel="nofollow noopener noreferrer" class="btn btn-primary btn-block" href="https://imgur.com/a/B3XHKnD">PCM Shitposter Cutouts (1/?)</a>
<a rel="nofollow noopener noreferrer" class="btn btn-primary btn-block" href="https://imgur.com/a/2wDZddF">PCM Shitposter Cutouts (2/?)</a>
<p class="mt-4"> Rules: No doxing, No CP or other clearly illegal shit. Thanks.</p>
<p class="mt-4"> This website has nothing to do with Political Compass Memes.</p>
@ -48,4 +48,4 @@
<img class="mb-4" alt="sidebar image" onclick="expandDesktopImage()" loading="lazy" src="{{image}}" width=100%>
</a>
{% endif %}
</div>
</div>

View File

@ -39,7 +39,7 @@
{% if error %}
<p class="mb-0">
<span class="text-danger text-small" style="vertical-align: sub;">{{ error }}</span>
<span class="text-danger text-small" style="vertical-align: sub;">{{error}}</span>
</p>
{% endif %}
@ -59,4 +59,4 @@
</form>
{% endblock %}
{% endblock %}

Some files were not shown because too many files have changed in this diff Show More