WIP: [DO NOT MERGE] logged out user #20

Closed
justcool393 wants to merge 31 commits from <deleted>:logged-out-user into master
35 changed files with 974 additions and 994 deletions

View File

@ -17,7 +17,6 @@ from files.helpers.sorting_and_time import *
def normalize_urls_runtime(body, v):
if not v: return body
if v.reddit != 'old.reddit.com':
body = reddit_to_vreddit_regex.sub(rf'\1https://{v.reddit}/\2/', body)
if v.nitter:
@ -142,7 +141,7 @@ class Comment(Base):
replies = db.query(Comment).filter_by(parent_comment_id=self.id).order_by(Comment.stickied)
if not self.parent_submission: sort='old'
return sort_objects(sort, replies, Comment,
include_shadowbanned=(v and v.can_see_shadowbanned)).all()
include_shadowbanned=v.can_see_shadowbanned).all()
@property
@ -242,17 +241,18 @@ class Comment(Base):
@lazy
def realbody(self, v):
if self.post and self.post.club and not (v and (v.paid_dues or v.id in [self.author_id, self.post.author_id] or (self.parent_comment and v.id == self.parent_comment.author_id))):
return f"<p>{CC} ONLY</p>"
if self.deleted_utc != 0 and not (v and (v.admin_level >= PERMS['POST_COMMENT_MODERATION'] or v.id == self.author.id)): return "[Deleted by user]"
if self.is_banned and not (v and v.admin_level >= PERMS['POST_COMMENT_MODERATION']) and not (v and v.id == self.author.id): return ""
if not v or v.id != self.author_id:
if self.deleted_utc != 0 and not v.admin_level >= PERMS['POST_COMMENT_MODERATION']: return "[Deleted by user]"
if self.author.shadowbanned and not v.admin_level >= PERMS['USER_SHADOWBAN']: return "[Deleted by user]"
if self.is_banned and not v.admin_level >= PERMS['POST_COMMENT_MODERATION']: return "[Removed by admins]"
if self.post.club and not v.paid_dues: return f"{CC} ONLY"
body = self.body_html or ""
if body:
body = censor_slurs(body, v)
body = normalize_urls_runtime(body, v)
if not v or v.controversial:
if v.controversial:
captured = []
for i in controversial_regex.finditer(body):
if i.group(1) in captured: continue
@ -297,37 +297,27 @@ class Comment(Base):
@lazy
def plainbody(self, v):
if self.post and self.post.club and not (v and (v.paid_dues or v.id in [self.author_id, self.post.author_id] or (self.parent_comment and v.id == self.parent_comment.author_id))):
return f"{CC} ONLY"
if self.deleted_utc != 0 and not (v and (v.admin_level >= PERMS['POST_COMMENT_MODERATION'] or v.id == self.author.id)): return "[Deleted by user]"
if self.is_banned and not (v and v.admin_level >= PERMS['POST_COMMENT_MODERATION']) and not (v and v.id == self.author.id): return ""
if not v or v.id != self.author_id:
if self.deleted_utc != 0 and not v.admin_level >= PERMS['POST_COMMENT_MODERATION']: return "[Deleted by user]"
if self.author.shadowbanned and not v.admin_level >= PERMS['USER_SHADOWBAN']: return "[Deleted by user]"
if self.is_banned and not v.admin_level >= PERMS['POST_COMMENT_MODERATION']: return "[Removed by admins]"
if self.post and self.post.club and not v.id == self.post.author_id and not v.paid_dues: return f"{CC} ONLY"
body = self.body
if not body: return ""
body = censor_slurs(body, v).replace('<img loading="lazy" data-bs-toggle="tooltip" alt=":marseytrain:" title=":marseytrain:" src="/e/marseytrain.webp">', ':marseytrain:')
return body
@lazy
def collapse_for_user(self, v, path):
if v and self.author_id == v.id: return False
if path == '/admin/removed/comments': return False
if self.author.shadowbanned and not v.shadowbanned: return True
if '?context' in path or f'/{self.id}' in path: return False
if self.over_18 and not (v and v.over_18) and not (self.post and self.post.over_18): return True
if self.over_18 and not v.over_18 and not (self.post and self.post.over_18): return True
if self.is_banned: return True
if self.author.shadowbanned and not (v and v.shadowbanned): return True
if (self.wordle_result) and (not self.body or len(self.body_html) <= 100) and 9 > self.level > 1: return True
if v and v.filter_words and self.body and any(x in self.body for x in v.filter_words): return True
if v.filter_words and self.body and any(x in self.body for x in v.filter_words): return True
return False
@property
@ -336,7 +326,7 @@ class Comment(Base):
@lazy
def filtered_flags(self, v):
return [f for f in self.flags if (v and v.shadowbanned) or not f.user.shadowbanned]
return [f for f in self.flags if v.shadowbanned or not f.user.shadowbanned]
@lazy
def active_flags(self, v):

View File

@ -244,7 +244,7 @@ class Submission(Base):
if url.startswith("https://old.reddit.com/r/") and '/comments/' in url and "sort=" not in url:
if "?" in url: url += "&context=9"
else: url += "?context=8"
if not v or v.controversial: url += "&sort=controversial"
if v.controversial: url += "&sort=controversial"
elif url.startswith("https://watchpeopledie.tv/videos/"):
# Semi-temporary fix for self-hosted unproxied video serving
url = url.replace("https://watchpeopledie.tv/videos/",
@ -270,9 +270,11 @@ class Submission(Base):
@lazy
def realbody(self, v, listing=False):
if self.club and not (v and (v.paid_dues or v.id == self.author_id)): return f"<p>{CC} ONLY</p>"
if self.deleted_utc != 0 and not (v and (v.admin_level >= PERMS['POST_COMMENT_MODERATION'] or v.id == self.author.id)): return "[Deleted by user]"
if self.is_banned and not (v and v.admin_level >= PERMS['POST_COMMENT_MODERATION']) and not (v and v.id == self.author.id): return ""
if not v or v.id != self.author_id:
if self.deleted_utc != 0 and not v.admin_level >= PERMS['POST_COMMENT_MODERATION']: return "[Deleted by user]"
if self.author.shadowbanned and not v.admin_level >= PERMS['USER_SHADOWBAN']: return "[Deleted by user]"
if self.is_banned and not v.admin_level >= PERMS['POST_COMMENT_MODERATION']: return "[Removed by admins]"
if self.club and not v.paid_dues: return f"{CC} ONLY"
body = self.body_html or ""
@ -328,9 +330,11 @@ class Submission(Base):
@lazy
def plainbody(self, v):
if self.deleted_utc != 0 and not (v and (v.admin_level >= PERMS['POST_COMMENT_MODERATION'] or v.id == self.author.id)): return "[Deleted by user]"
if self.is_banned and not (v and v.admin_level >= PERMS['POST_COMMENT_MODERATION']) and not (v and v.id == self.author.id): return ""
if self.club and not (v and (v.paid_dues or v.id == self.author_id)): return f"<p>{CC} ONLY</p>"
if not v or v.id != self.author_id:
if self.deleted_utc != 0 and not v.admin_level >= PERMS['POST_COMMENT_MODERATION']: return "[Deleted by user]"
if self.author.shadowbanned and not v.admin_level >= PERMS['USER_SHADOWBAN']: return "[Deleted by user]"
if self.is_banned and not v.admin_level >= PERMS['POST_COMMENT_MODERATION']: return "[Removed by admins]"
if self.club and not v.paid_dues: return f"{CC} ONLY"
body = self.body
if not body: return ""
@ -380,7 +384,7 @@ class Submission(Base):
@lazy
def filtered_flags(self, v):
return [f for f in self.flags if (v and v.shadowbanned) or not f.user.shadowbanned]
return [f for f in self.flags if v.shadowbanned or not f.user.shadowbanned]
@lazy
def active_flags(self, v):

File diff suppressed because it is too large Load Diff

View File

@ -214,7 +214,7 @@ PERMS = { # Minimum admin_level to perform action.
'FLAGS_REMOVE': 2,
'VOTES_VISIBLE': 0,
'USER_BLOCKS_VISIBLE': 0,
'USER_FOLLOWS_VISIBLE': 0,
'USER_FOLLOWS_VISIBLE': -1,
'USER_VOTERS_VISIBLE': 0,
'POST_COMMENT_INFINITE_PINGS': 1,
'POST_COMMENT_MODERATION': 2,

View File

@ -4,7 +4,7 @@ from flask import *
from sqlalchemy import and_, any_, or_
from sqlalchemy.orm import joinedload, selectinload
from files.classes import Comment, CommentVote, Hat, Sub, Submission, User, UserBlock, Vote
from files.classes import Comment, CommentVote, Hat, Sub, Submission, LoggedOutUser, User, UserBlock, Vote
from files.helpers.const import AUTOJANNY_ID
def sanitize_username(username:str) -> str:
@ -31,7 +31,7 @@ def get_id(username:str, graceful=False) -> Optional[int]:
return user[0]
def get_user(username:Optional[str], v:Optional[User]=None, graceful=False, include_blocks=False, include_shadowbanned=True) -> Optional[User]:
def get_user(username:Optional[str], v:Optional[LoggedOutUser]=None, graceful=False, include_blocks=False, include_shadowbanned=True) -> Optional[User]:
if not username:
if graceful: return None
abort(404)
@ -51,7 +51,7 @@ def get_user(username:Optional[str], v:Optional[User]=None, graceful=False, incl
user = user.one_or_none()
if not user or (user.shadowbanned and not (include_shadowbanned or (v and v.can_see_shadowbanned))):
if not user or (user.shadowbanned and not (include_shadowbanned or v.can_see_shadowbanned)):
if graceful: return None
abort(404)
@ -77,7 +77,7 @@ def get_users(usernames:Iterable[str], graceful=False) -> List[User]:
return users
def get_account(id:Union[str, int], v:Optional[User]=None, graceful=False, include_blocks=False, include_shadowbanned=True) -> Optional[User]:
def get_account(id:Union[str, int], v:Optional[LoggedOutUser]=None, graceful=False, include_blocks=False, include_shadowbanned=True) -> Optional[User]:
try:
id = int(id)
except:
@ -86,7 +86,7 @@ def get_account(id:Union[str, int], v:Optional[User]=None, graceful=False, inclu
user = g.db.get(User, id)
if not user or (user.shadowbanned and not (include_shadowbanned or (v and v.can_see_shadowbanned))):
if not user or (user.shadowbanned and not (include_shadowbanned or v.can_see_shadowbanned)):
if not graceful: abort(404)
else: return None
@ -95,7 +95,7 @@ def get_account(id:Union[str, int], v:Optional[User]=None, graceful=False, inclu
return user
def get_post(i:Union[str, int], v:Optional[User]=None, graceful=False) -> Optional[Submission]:
def get_post(i:Union[str, int], v:Optional[LoggedOutUser]=None, graceful=False) -> Optional[Submission]:
try: i = int(i)
except:
if graceful: return None
@ -145,7 +145,7 @@ def get_post(i:Union[str, int], v:Optional[User]=None, graceful=False) -> Option
return x
def get_posts(pids:Iterable[int], v:Optional[User]=None, eager:bool=False) -> List[Submission]:
def get_posts(pids:Iterable[int], v:Optional[LoggedOutUser]=None, eager:bool=False) -> List[Submission]:
if not pids: return []
if v:
@ -205,7 +205,7 @@ def get_posts(pids:Iterable[int], v:Optional[User]=None, eager:bool=False) -> Li
return sorted(output, key=lambda x: pids.index(x.id))
def get_comment(i:Union[str, int], v:Optional[User]=None, graceful=False) -> Optional[Comment]:
def get_comment(i:Union[str, int], v:Optional[LoggedOutUser]=None, graceful=False) -> Optional[Comment]:
try: i = int(i)
except:
if graceful: return None
@ -222,7 +222,7 @@ def get_comment(i:Union[str, int], v:Optional[User]=None, graceful=False) -> Opt
return add_vote_and_block_props(comment, v, CommentVote)
def add_block_props(target:Union[Submission, Comment, User], v:Optional[User]):
def add_block_props(target:Union[Submission, Comment, User], v:Optional[LoggedOutUser]):
if not v: return target
id = None
@ -257,8 +257,11 @@ def add_block_props(target:Union[Submission, Comment, User], v:Optional[User]):
target.is_blocked = block and block.target_id == v.id
return target
def add_vote_props(target:Union[Submission, Comment], v:Optional[User], vote_cls):
def add_vote_props(target:Union[Submission, Comment], v:Optional[LoggedOutUser], vote_cls):
if hasattr(target, 'voted'): return target
if not v:
target.voted = 0
return target
vt = g.db.query(vote_cls.vote_type).filter_by(user_id=v.id)
if vote_cls == Vote:
@ -271,14 +274,14 @@ def add_vote_props(target:Union[Submission, Comment], v:Optional[User], vote_cls
target.voted = vt.vote_type if vt else 0
return target
def add_vote_and_block_props(target:Union[Submission, Comment], v:Optional[User], vote_cls):
def add_vote_and_block_props(target:Union[Submission, Comment], v:Optional[LoggedOutUser], vote_cls):
if not v: return target
target = add_block_props(target, v)
return add_vote_props(target, v, vote_cls)
def get_comments(cids:Iterable[int], v:Optional[User]=None) -> List[Comment]:
def get_comments(cids:Iterable[int], v:Optional[LoggedOutUser]=None) -> List[Comment]:
if not cids: return []
if v:
if isinstance(v, User):
output = get_comments_v_properties(v, True, None, Comment.id.in_(cids))[1]
else:
output = g.db.query(Comment).join(Comment.author).filter(User.shadowbanned == None, Comment.id.in_(cids)).all()
@ -326,7 +329,7 @@ def get_comments_v_properties(v:User, include_shadowbanned=True, should_keep_fun
else: dump.append(comment)
return (comments, output)
def get_sub_by_name(sub:str, v:Optional[User]=None, graceful=False) -> Optional[Sub]:
def get_sub_by_name(sub:str, v:Optional[LoggedOutUser]=None, graceful=False) -> Optional[Sub]:
if not sub:
if graceful: return None
else: abort(404)

View File

@ -274,7 +274,7 @@ def sanitize(sanitized, golden=True, limit_pings=0, showmore=True, count_marseys
sanitized = reddit_regex.sub(r'\1<a href="https://old.reddit.com/\2" rel="nofollow noopener" target="_blank">/\2</a>', sanitized)
sanitized = sub_regex.sub(r'\1<a href="/\2">/\2</a>', sanitized)
v = getattr(g, 'v', None)
v = g.v
names = set(m.group(2) for m in mention_regex.finditer(sanitized))
if limit_pings and len(names) > limit_pings and not v.admin_level >= PERMS['POST_COMMENT_INFINITE_PINGS']: abort(406)

View File

@ -1,4 +1,5 @@
import secrets
from files.classes.user import LoggedOutUser
from files.helpers.const import *
from files.helpers.settings import get_setting
from files.helpers.cloudflare import CLOUDFLARE_AVAILABLE
@ -28,6 +29,7 @@ def before_request():
g.webview = '; wv) ' in ua
g.inferior_browser = 'iphone' in ua or 'ipad' in ua or 'ipod' in ua or 'mac os' in ua or ' firefox/' in ua
g.is_tor = request.headers.get("cf-ipcountry") == "T1"
g.v = LoggedOutUser()
request.path = request.path.rstrip('/')
if not request.path: request.path = '/'
@ -41,7 +43,7 @@ def before_request():
def after_request(response):
if response.status_code < 400:
if CLOUDFLARE_AVAILABLE and CLOUDFLARE_COOKIE_VALUE and getattr(g, 'desires_auth', False):
logged_in = bool(getattr(g, 'v', None))
logged_in = bool(g.v)
response.set_cookie("lo", CLOUDFLARE_COOKIE_VALUE if logged_in else '', max_age=60*60*24*365 if logged_in else 1)
if getattr(g, 'db', None):
g.db.commit()

View File

@ -39,7 +39,7 @@ user_ids_to_socket_ids = {}
@app.get("/chat")
@is_not_permabanned
def chat(v):
if TRUESCORE_CHAT_LIMIT and v.truescore < TRUESCORE_CHAT_LIMIT and not v.club_allowed:
if not v.can_see_chat:
abort(403, f"Need at least {TRUESCORE_CHAT_LIMIT} truescore for access to chat.")
return render_template("chat.html", v=v, messages=messages)
@ -50,7 +50,7 @@ def chat(v):
@ratelimit_user("3/second;10/minute")
def speak(data, v):
if v.is_banned: return '', 403
if TRUESCORE_CHAT_LIMIT and v.truescore < TRUESCORE_CHAT_LIMIT and not v.club_allowed: return '', 403
if not v.can_see_chat: return '', 403
vname = v.username.lower()
if vname in muted and not v.admin_level >= PERMS['CHAT_BYPASS_MUTE']:

View File

@ -30,10 +30,10 @@ WORDLE_COLOR_MAPPINGS = {-1: "🟥", 0: "🟨", 1: "🟩"}
@app.get("/h/<sub>/comment/<cid>")
@app.get("/h/<sub>/post/<pid>/<anything>/<cid>")
@auth_desired_with_logingate
def post_pid_comment_cid(cid, pid=None, anything=None, v=None, sub=None):
def post_pid_comment_cid(v, cid, pid=None, anything=None, sub=None):
comment = get_comment(cid, v=v)
if not User.can_see(v, comment): abort(404)
if comment.post and comment.post.club and not User.can_see_content(v, comment): abort(403)
if not v.can_see(comment): abort(404)
if comment.post and comment.post.club and not v.can_see_content(comment): abort(403)
if v and request.values.get("read"):
notif = g.db.query(Notification).filter_by(comment_id=cid, user_id=v.id, read=False).one_or_none()
@ -47,7 +47,7 @@ def post_pid_comment_cid(cid, pid=None, anything=None, v=None, sub=None):
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()):
if post.over_18 and not v.over_18 and not session.get('over_18', 0) >= int(time.time()):
if v and v.client: abort(403, "This content is not suitable for some users and situations.")
else: return render_template("errors/nsfw.html", v=v), 403
@ -74,10 +74,8 @@ def post_pid_comment_cid(cid, pid=None, anything=None, v=None, sub=None):
execute_shadowban_viewers_and_voters(v, comment)
if v and v.client: return top_comment.json
else:
if post.is_banned and not (v and (v.admin_level >= PERMS['POST_COMMENT_MODERATION'] or post.author_id == v.id)): template = "submission_banned.html"
else: template = "submission.html"
return render_template(template, v=v, p=post, sort=sort, comment_info=comment_info, render_replies=True, sub=post.subr)
else:
return render_template("submission.html", v=v, p=post, sort=sort, comment_info=comment_info, render_replies=True, sub=post.subr)
@app.post("/comment")
@limiter.limit("1/second;20/minute;200/hour;1000/day")
@ -113,7 +111,7 @@ def comment(v):
if parent_post.club and not (v and (v.paid_dues or v.id == parent_post.author_id)): abort(403)
if not User.can_see(v, parent): abort(404)
if not v.can_see(parent): abort(404)
if parent.deleted_utc != 0: abort(404)
if level > COMMENT_MAX_DEPTH: abort(400, f"Max comment level is {COMMENT_MAX_DEPTH}")

View File

@ -35,6 +35,7 @@ def error(e):
if request.headers.get("Authorization") or request.headers.get("xhr"):
return {"error": title, "code": e.code, "description": msg, "details": details}, e.code
img = ERROR_MARSEYS.get(e.code, 'marseyl')
# TODO: make sure v isn't required from anything error.html needs
return render_template('errors/error.html', err=True, title=title, msg=msg, details=details, img=img), e.code
@app.errorhandler(401)

View File

@ -43,7 +43,7 @@ def front_all(v, sub=None, subdomain=None):
#### WPD TEMP #### end special front logic
if sub:
sub = get_sub_by_name(sub, graceful=True)
if sub and not User.can_see(v, sub): abort(403)
if sub and not v.can_see(sub): abort(403)
if (request.path.startswith('/h/') or request.path.startswith('/s/')) and not sub: abort(404)
@ -101,7 +101,7 @@ def front_all(v, sub=None, subdomain=None):
def frontlist(v=None, sort="hot", page=1, t="all", ids_only=True, filter_words='', gt=0, lt=0, sub=None, site=None, pins=True, holes=True):
posts = g.db.query(Submission)
if v and v.hidevotedon:
if v.hidevotedon:
posts = posts.outerjoin(Vote,
and_(Vote.submission_id == Submission.id, Vote.user_id == v.id)
).filter(Vote.submission_id == None)
@ -137,7 +137,7 @@ def frontlist(v=None, sort="hot", page=1, t="all", ids_only=True, filter_words='
posts=posts.filter(not_(Submission.title.ilike(f'%{word}%')))
posts = sort_objects(sort, posts, Submission,
include_shadowbanned=(v and v.can_see_shadowbanned))
include_shadowbanned=v.can_see_shadowbanned)
if v: size = v.frontsize or 0
else: size = PAGE_SIZE
@ -255,7 +255,7 @@ def comment_idlist(v=None, page=1, sort="new", t="all", gt=0, lt=0, site=None):
comments = apply_time_filter(t, comments, Comment)
comments = sort_objects(sort, comments, Comment,
include_shadowbanned=(v and v.can_see_shadowbanned))
include_shadowbanned=v.can_see_shadowbanned)
comments = comments.offset(PAGE_SIZE * (page - 1)).limit(PAGE_SIZE + 1).all()
return [x[0] for x in comments]

View File

@ -8,7 +8,7 @@ from files.__main__ import app
@app.get("/giphy")
@app.get("/giphy<path>")
@auth_required
def giphy(v=None, path=None):
def giphy(v, path=None):
searchTerm = request.values.get("searchTerm", "").strip()
limit = 48

View File

@ -4,7 +4,6 @@ from os import environ, listdir, path
from jinja2 import pass_context
from files.classes.user import User
from files.helpers.assetcache import assetcache_path
from files.helpers.const import *
from files.helpers.settings import get_settings
@ -57,7 +56,7 @@ def inject_constants():
"KOFI_TOKEN":KOFI_TOKEN, "KOFI_LINK":KOFI_LINK,
"approved_embed_hosts":approved_embed_hosts,
"site_settings":get_settings(), "EMAIL":EMAIL, "calc_users":calc_users,
"max": max, "min": min, "user_can_see":User.can_see,
"max": max, "min": min,
"TELEGRAM_LINK":TELEGRAM_LINK, "EMAIL_REGEX_PATTERN":EMAIL_REGEX_PATTERN,
"CONTENT_SECURITY_POLICY_DEFAULT":CONTENT_SECURITY_POLICY_DEFAULT,
"CONTENT_SECURITY_POLICY_HOME":CONTENT_SECURITY_POLICY_HOME,

View File

@ -135,12 +135,12 @@ def submit_get(v, sub=None):
@app.get("/h/<sub>/post/<pid>")
@app.get("/h/<sub>/post/<pid>/<anything>")
@auth_desired_with_logingate
def post_id(pid, anything=None, v=None, sub=None):
def post_id(v, pid, anything=None, sub=None):
post = get_post(pid, v=v)
if not User.can_see(v, post): abort(403)
if not User.can_see_content(v, post) and post.club: abort(403)
if not v.can_see(post): abort(403)
if not v.can_see_content(post) and post.club: abort(403)
if post.over_18 and not (v and v.over_18) and session.get('over_18', 0) < int(time.time()):
if post.over_18 and not v.over_18 and session.get('over_18', 0) < int(time.time()):
if g.is_api_or_xhr: return {"error":"Must be 18+ to view"}, 451
return render_template("errors/nsfw.html", v=v)
@ -157,7 +157,7 @@ def post_id(pid, anything=None, v=None, sub=None):
pinned = [c[0] for c in comments.filter(Comment.stickied != None).all()]
comments = comments.filter(Comment.level == 1, Comment.stickied == None)
comments = sort_objects(sort, comments, Comment,
include_shadowbanned=(v and v.can_see_shadowbanned))
include_shadowbanned=v.can_see_shadowbanned)
comments = [c[0] for c in comments.all()]
else:
pinned = g.db.query(Comment).filter(Comment.parent_submission == post.id, Comment.stickied != None).all()
@ -220,12 +220,7 @@ def post_id(pid, anything=None, v=None, sub=None):
if v and v.client:
return post.json(g.db)
template = "submission.html"
if (post.is_banned or post.author.shadowbanned) \
and not (v and (v.admin_level >= PERMS['POST_COMMENT_MODERATION'] or post.author_id == v.id)):
template = "submission_banned.html"
return render_template(template, v=v, p=post, ids=list(ids),
return render_template("submission.html", v=v, p=post, ids=list(ids),
sort=sort, render_replies=True, offset=offset, sub=post.subr,
fart=get_setting('Fart mode'))
@ -247,7 +242,7 @@ def viewmore(v, pid, sort, offset):
comments, output = get_comments_v_properties(v, True, None, Comment.parent_submission == pid, Comment.stickied == None, Comment.id.notin_(ids), Comment.level < 10)
comments = comments.filter(Comment.level == 1)
comments = sort_objects(sort, comments, Comment,
include_shadowbanned=(v and v.can_see_shadowbanned))
include_shadowbanned=v.can_see_shadowbanned)
comments = [c[0] for c in comments.all()]
else:
@ -348,7 +343,7 @@ def edit_post(pid, v):
body = body.strip()[:POST_BODY_LENGTH_LIMIT] # process_files() may be adding stuff to the body
if body != p.body:
if v and v.admin_level >= PERMS['POST_BETS']:
if v.admin_level >= PERMS['POST_BETS']:
for i in bet_regex.finditer(body):
body = body.replace(i.group(0), "")
body_html = filter_emojis_only(i.group(1))
@ -750,7 +745,7 @@ def submit_post(v, sub=None):
return error("There's a 2048 character limit for URLs.")
bets = []
if v and v.admin_level >= PERMS['POST_BETS']:
if v.admin_level >= PERMS['POST_BETS']:
for i in bet_regex.finditer(body):
bets.append(i.group(1))
body = body.replace(i.group(0), "")
@ -818,7 +813,7 @@ def submit_post(v, sub=None):
for text in [post.body, post.title, post.url]:
if not execute_blackjack(v, post, text, 'submission'): break
if v and v.admin_level >= PERMS['POST_BETS']:
if v.admin_level >= PERMS['POST_BETS']:
for bet in bets:
body_html = filter_emojis_only(bet)
if len(body_html) > 500: abort(400, "Bet option too long!")

View File

@ -153,7 +153,7 @@ def searchposts(v):
posts = apply_time_filter(t, posts, Submission)
posts = sort_objects(sort, posts, Submission,
include_shadowbanned=(v and v.can_see_shadowbanned))
include_shadowbanned=v.can_see_shadowbanned)
total = posts.count()
@ -255,7 +255,7 @@ def searchcomments(v):
comments = comments.filter(Comment.created_utc < before)
comments = sort_objects(sort, comments, Comment,
include_shadowbanned=(v and v.can_see_shadowbanned))
include_shadowbanned=v.can_see_shadowbanned)
total = comments.count()

View File

@ -127,7 +127,6 @@ def admins(v):
@app.get("/modlog")
@auth_required
def log(v):
try: page = max(int(request.values.get("page", 1)), 1)
except: page = 1
@ -137,7 +136,7 @@ def log(v):
kind = request.values.get("kind")
if v and v.admin_level >= PERMS['USER_SHADOWBAN']: types = ACTIONTYPES
if v.admin_level >= PERMS['USER_SHADOWBAN']: types = ACTIONTYPES
else: types = ACTIONTYPES2
if kind and kind not in types:
@ -145,7 +144,7 @@ def log(v):
actions = []
else:
actions = g.db.query(ModAction)
if not (v and v.admin_level >= PERMS['USER_SHADOWBAN']):
if not (v.admin_level >= PERMS['USER_SHADOWBAN']):
actions = actions.filter(ModAction.kind.notin_([
"shadowban","unshadowban",
"mod_mute_user","mod_unmute_user",
@ -182,7 +181,7 @@ def log_item(id, v):
admins = [x[0] for x in g.db.query(User.username).filter(User.admin_level >= PERMS['ADMIN_MOP_VISIBLE']).all()]
if v and v.admin_level >= PERMS['USER_SHADOWBAN']: types = ACTIONTYPES
if v.admin_level >= PERMS['USER_SHADOWBAN']: types = ACTIONTYPES
else: types = ACTIONTYPES2
return render_template("log.html", v=v, actions=[action], next_exists=False, page=1, action=action, admins=admins, types=types, single_user_url='admin')

View File

@ -670,12 +670,12 @@ def visitors(v):
@cache.memoize(timeout=86400)
def userpagelisting(user:User, site=None, v=None, page:int=1, sort="new", t="all"):
if user.shadowbanned and not (v and v.can_see_shadowbanned): return []
if user.shadowbanned and not v.can_see_shadowbanned: return []
posts = g.db.query(Submission.id).filter_by(author_id=user.id, is_pinned=False)
if not (v and (v.admin_level >= PERMS['POST_COMMENT_MODERATION'] or v.id == user.id)):
posts = posts.filter_by(is_banned=False, private=False, ghost=False, deleted_utc=0)
posts = apply_time_filter(t, posts, Submission)
posts = sort_objects(sort, posts, Submission, include_shadowbanned=v and v.can_see_shadowbanned)
posts = sort_objects(sort, posts, Submission, include_shadowbanned=v.can_see_shadowbanned)
posts = posts.offset(PAGE_SIZE * (page - 1)).limit(PAGE_SIZE+1).all()
return [x[0] for x in posts]
@ -803,7 +803,7 @@ def u_username_comments(username, v=None):
comments = apply_time_filter(t, comments, Comment)
comments = sort_objects(sort, comments, Comment,
include_shadowbanned=(v and v.can_see_shadowbanned))
include_shadowbanned=v.can_see_shadowbanned)
comments = comments.offset(PAGE_SIZE * (page - 1)).limit(PAGE_SIZE+1).all()
ids = [x.id for x in comments]

View File

@ -17,7 +17,7 @@ def vote_info_get(v, link):
if thing.ghost and v.id != AEVANN_ID: abort(403)
if isinstance(thing, Submission):
if thing.author.shadowbanned and not (v and v.admin_level >= PERMS['USER_SHADOWBAN']):
if thing.author.shadowbanned and not v.admin_level >= PERMS['USER_SHADOWBAN']:
thing_id = g.db.query(Submission.id).filter_by(upvotes=thing.upvotes, downvotes=thing.downvotes).order_by(Submission.id).first()[0]
else: thing_id = thing.id
@ -25,7 +25,7 @@ def vote_info_get(v, link):
downs = g.db.query(Vote).filter_by(submission_id=thing_id, vote_type=-1).order_by(Vote.created_utc).all()
elif isinstance(thing, Comment):
if thing.author.shadowbanned and not (v and v.admin_level >= PERMS['USER_SHADOWBAN']):
if thing.author.shadowbanned and not v.admin_level >= PERMS['USER_SHADOWBAN']:
thing_id = g.db.query(Comment.id).filter_by(upvotes=thing.upvotes, downvotes=thing.downvotes).order_by(Comment.id).first()[0]
else: thing_id = thing.id
@ -54,7 +54,7 @@ def vote_post_comment(target_id, new, v, cls, vote_cls):
else:
abort(404)
if not User.can_see(v, target): abort(404)
if not v.can_see(target): abort(404)
coin_delta = 1
if v.id == target.author.id:

View File

@ -33,10 +33,10 @@ def calc_users(v):
return ''
def get_logged_in_user():
if hasattr(g, 'v'): return g.v
if g.v: return g.v
if not getattr(g, 'db', None): g.db = db_session()
g.desires_auth = True
v = None
v = g.v
token = request.headers.get("Authorization","").strip()
if token:
client = g.db.query(ClientAuth).filter(ClientAuth.access_token == token).one_or_none()
@ -67,9 +67,8 @@ def get_logged_in_user():
if request.method.lower() != "get" and get_setting('Read-only mode') and not (v and v.admin_level >= PERMS['SITE_BYPASS_READ_ONLY_MODE']):
abort(403)
g.v = v
if v:
g.v = v
v.poor = session.get('poor')
# Check against last_active + ACTIVE_TIME to reduce frequency of
# UPDATEs in exchange for a ±ACTIVE_TIME margin of error.
@ -149,7 +148,7 @@ def feature_required(x):
def ratelimit_user(limit:Union[str, Callable[[], str]]=DEFAULT_RATELIMIT_USER):
'''
Ratelimits based on a user. This requires at least auth_required (or stronger) to be present,
otherwise logged out users will receive 500s
otherwise logged out users may receive errenous 429s
'''
def inner(func):
@functools.wraps(func)

View File

@ -14,7 +14,7 @@
<div class="settings-section rounded">
<div class="d-lg-flex">
<div class="title w-lg-25">
<label for="over18"><a href="{{app.permalink}}" {% if v and v.newtab and not g.webview %}target="_blank"{% endif %}>{{app.app_name}}</a></label>
<label for="over18"><a href="{{app.permalink}}" {% if v.newtab and not g.webview %}target="_blank"{% endif %}>{{app.app_name}}</a></label>
</div>
<div class="body w-lg-100">

View File

@ -1 +1 @@
{% if v and v.admin_level >= PERMS['USER_SHADOWBAN'] and user.shadowbanned %}<i class="fas fa-user-times text-admin" data-bs-toggle="tooltip" data-bs-placement="bottom" title='Shadowbanned by @{{user.shadowbanned}}{% if user.ban_reason %} for "{{user.ban_reason}}"{% endif %}'></i>{% endif %}
{% if v.admin_level >= PERMS['USER_SHADOWBAN'] and user.shadowbanned %}<i class="fas fa-user-times text-admin" data-bs-toggle="tooltip" data-bs-placement="bottom" title='Shadowbanned by @{{user.shadowbanned}}{% if user.ban_reason %} for "{{user.ban_reason}}"{% endif %}'></i>{% endif %}

View File

@ -24,7 +24,7 @@
{% set replies=c.replies(sort=sort, v=v, db=g.db) %}
{% endif %}
{% if c.is_blocking and not c.ghost or (c.is_banned or c.deleted_utc) and not (v and v.admin_level >= PERMS['POST_COMMENT_MODERATION']) and not (v and v.id==c.author_id) %}
{% if c.is_blocking and not c.ghost or (c.is_banned or c.deleted_utc) and not v.admin_level >= PERMS['POST_COMMENT_MODERATION'] and not (v and v.id==c.author_id) %}
<div id="comment-{{c.id}}" class="comment">
<span class="comment-collapse-desktop d-mob-none" style="border-left: 2px solid #{{c.author.name_color}}"onclick="collapse_comment('{{c.id}}', this.parentElement)"></span>
@ -88,7 +88,7 @@
{% endif %}
{% if c.post.sub %}
<span class="ml-1"> in <a href="/h/{{c.post.sub}}" {% if v and v.newtab and not g.webview %}target="_blank"{% endif %}>/h/{{c.post.sub}}</a></span>
<span class="ml-1"> in <a href="/h/{{c.post.sub}}" {% if v.newtab and not g.webview %}target="_blank"{% endif %}>/h/{{c.post.sub}}</a></span>
{% endif %}
{% elif c.author_id==AUTOJANNY_ID %}
<span class="font-weight-bold">Notification</span>
@ -141,7 +141,7 @@
{% if c.active_flags(v) %}<button type="button" class="btn btn-primary" style="padding:1px 5px; font-size:10px" onclick="document.getElementById('flaggers-{{c.id}}').classList.toggle('d-none')">{{c.active_flags(v)}} Report{{macros.plural(c.active_flags(v))}}</button>{% 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 v.admin_level >= PERMS['USER_SHADOWBAN'] and c.author.shadowbanned %}<i class="fas fa-user-times text-admin" data-bs-toggle="tooltip" data-bs-placement="bottom" title='Shadowbanned by @{{c.author.shadowbanned}} for "{{c.author.ban_reason}}"'></i>{% endif %}
{% if c.stickied %}
<i id='pinned-{{c.id}}'class="fas fa-thumbtack fa-rotate--45 text-admin" data-bs-toggle="tooltip" data-bs-placement="bottom" title="Pinned by @{{c.stickied}}" {% if c.stickied_utc %}onmouseover="pinned_timestamp('pinned-{{c.id}}')" data-timestamp={{c.stickied_utc}} {% endif %}></i>
{% endif %}
@ -291,7 +291,7 @@
<button type="button" id="cancel-edit-{{c.id}}" onclick="toggleEdit('{{c.id}}');remove_dialog()" class="btn btn-link text-muted ml-auto cancel-form fl-r commentmob">Cancel</button>
</form>
<div id="preview-edit-{{c.id}}" class="preview mb-3 mt-5"></div>
<div class="form-text text-small p-0 m-0"><a href="/formatting" {% if v and v.newtab and not g.webview %}target="_blank"{% endif %}>Formatting help</a></div>
<div class="form-text text-small p-0 m-0"><a href="/formatting" {% if v.newtab and not g.webview %}target="_blank"{% endif %}>Formatting help</a></div>
</div>
{% endif %}
<div id="comment-{{c.id}}-actions" class="comment-actions{% if voted==1 %} upvoted{% elif voted==-1 %} downvoted{% endif %}">
@ -361,14 +361,6 @@
</div>
<ul class="d-none d-md-flex list-inline text-right text-md-left"><li>
{% if v and request.path.startswith('/@') and v.admin_level < PERMS['VIEW_VOTE_BUTTONS_ON_USER_PAGE'] %}
{% if voted==1 %}
@ -540,7 +532,7 @@
<button type="button" onclick="document.getElementById('reply-to-{{c.id}}').classList.add('d-none');remove_dialog()" class="btn btn-link text-muted ml-auto cancel-form fl-r commentmob">Cancel</button>
</form>
<div id="form-preview-{{c.fullname}}" class="preview mb-3 mt-5"></div>
<div class="form-text text-small p-0 m-0"><a href="/formatting" {% if v and v.newtab and not g.webview %}target="_blank"{% endif %}>Formatting help</a></div>
<div class="form-text text-small p-0 m-0"><a href="/formatting" {% if v.newtab and not g.webview %}target="_blank"{% endif %}>Formatting help</a></div>
</div>
</div>
@ -739,7 +731,7 @@
{% endif %}
{% endmacro %}
{% for comment in comments if user_can_see(v, comment) %}
{% for comment in comments if v.can_see(comment) %}
{{single_comment(comment)}}
{% endfor %}
@ -806,19 +798,17 @@
{% if v %}
<script defer src="{{'js/marked.js' | asset}}"></script>
<script defer src="{{'js/comments_v.js' | asset}}"></script>
{% if v.admin_level >= PERMS['POST_COMMENT_MODERATION_TOOLS_VISIBLE'] %}
<script defer src="{{'js/comments_admin.js' | asset}}"></script>
{% endif %}
{% endif %}
<script defer src="{{'js/clipboard.js' | asset}}"></script>
{% if v and v.admin_level >= PERMS['POST_COMMENT_MODERATION_TOOLS_VISIBLE'] %}
<script defer src="{{'js/comments_admin.js' | asset}}"></script>
{% endif %}
<script defer src="{{'js/comments+submission_listing.js' | asset}}"></script>
<script defer src="{{'js/comments.js' | asset}}"></script>
<script>
{% if p and (not v or v.highlightcomments) %}
{% if p and v.highlightcomments %}
comments = JSON.parse(localStorage.getItem("comment-counts")) || {}
lastCount = comments['{{p.id}}']
if (lastCount)
@ -903,5 +893,4 @@
}
</script>
{% endif %}
</body>

View File

@ -104,10 +104,9 @@
</div>
<script defer src="{{'js/lozad.js' | asset}}"></script>
<script defer src="{{'js/lite-youtube.js' | asset}}"></script>
{% if v and v.spider %}
{% if not err and v.spider %}
<script defer src="{{'js/critters.js' | asset}}"></script>
<script defer src="{{'js/spider.js' | asset}}"></script>
{% endif %}

View File

@ -1,5 +1,4 @@
<div class="container d-inline-flex d-lg-none">
<div class="row fixed-bottom bg-white border-top p-2" id="mobile-bottom-navigation-bar"
style="z-index: 1000; bottom: 0px; transition: bottom cubic-bezier(0, 0, 0.2, 1) 220ms;">
@ -11,7 +10,7 @@
</div>
</a>
</button>
{% if v and v.defaultsorting == 'new' %}
{% if v and v.defaultsorting == 'new' %} {# v check is required because the default template is used in error.html #}
<button type="button" class="col px-0 btn btn-dead m-0" style="background: None !important; border: None;">
<a href="/?sort=hot&t=all" class="text-decoration-none">
<div class="text-center {% if request.full_path=='/?sort=hot&t=all' %}text-primary{% else %}text-muted{% endif %}">
@ -20,7 +19,7 @@
</div>
</a>
</button>
{% else %}
{% elif not err %}
<button type="button" class="col px-0 btn btn-dead m-0" style="background: None !important; border: None;">
<a href="/?sort=new&t=all" class="text-decoration-none">
<div class="text-center {% if request.full_path=='/?sort=new&t=all' %}text-primary{% else %}text-muted{% endif %}">
@ -67,7 +66,7 @@
</a>
</button>
{%- endif %}
{% else %}
{% elif not err %}
<button type="button" class="col px-0 mr-3 btn btn-dead m-0" style="background: None !important; border: None;">
<a href="/signup" class="text-decoration-none">
<div class="text-center text-muted">
@ -79,5 +78,4 @@
{% endif %}
</div>
</div>
<script defer src="{{'js/mobile_navigation_bar.js' | asset}}"></script>

View File

@ -38,7 +38,7 @@
<strong class="pop-coins text-black"></strong>
<span class="text-black">coins</span>
</span>
<a href="/" {% if v and v.newtab and not g.webview %}target="_blank"{% endif %} class="pop-viewmore ml-auto text-decoration-none">
<a href="/" {% if v.newtab and not g.webview %}target="_blank"{% endif %} class="pop-viewmore ml-auto text-decoration-none">
<span class="ml-3">View</span>
<i class="fas fa-arrow-right fa-sm px-1"></i>
</a>

View File

@ -7,7 +7,7 @@
</head>
{{html_head.html_head(true, false, true, none, "Settings", false)}}
<body id="settings" {% if SITE_NAME == 'rDrama' and v and (v.is_banned or v.agendaposter) %}style="overflow-x: hidden;background:url(/assets/images/backgrounds/anime/1.webp?v=3) center center fixed; background-color: var(--background)"{% elif v and v.background %}style="overflow-x: hidden;background:url(/assets/images/backgrounds/{{v.background}}?v=3) center center fixed; background-color: var(--background){% if 'anime' not in v.background %};background-size: cover{% endif %}"{% endif %}>
<body id="settings" {% if SITE_NAME == 'rDrama' and (v.is_banned or v.agendaposter) %}style="overflow-x: hidden;background:url(/assets/images/backgrounds/anime/1.webp?v=3) center center fixed; background-color: var(--background)"{% elif v.background %}style="overflow-x: hidden;background:url(/assets/images/backgrounds/{{v.background}}?v=3) center center fixed; background-color: var(--background){% if 'anime' not in v.background %};background-size: cover{% endif %}"{% endif %}>
{% include "header.html" %}
<div class="container">
<div class="row justify-content-around">

View File

@ -124,7 +124,7 @@
</form>
</div>
</div>
<div class="text-small text-muted mt-3">All image files are supported. Max file size is {% if v and v.patron %}16{% else %}8{% endif %} MB.</div>
<div class="text-small text-muted mt-3">All image files are supported. Max file size is {% if v.patron %}16{% else %}8{% endif %} MB.</div>
</div>
</div>
{% if FEATURES['USERS_PROFILE_BANNER'] -%}
@ -146,7 +146,7 @@
</form>
</div>
</div>
<div class="text-small text-muted mt-3">All image files are supported. Max file size is {% if v and v.patron %}16{% else %}8{% endif %} MB.</div>
<div class="text-small text-muted mt-3">All image files are supported. Max file size is {% if v.patron %}16{% else %}8{% endif %} MB.</div>
</div>
</div>
{%- endif %}

View File

@ -3,7 +3,7 @@
<!DOCTYPE html>
<html lang="en">
{{html_head.html_head(true, false, true, none, none)}}
<body id="settings2" {% if SITE_NAME == 'rDrama' and v and (v.is_banned or v.agendaposter) %}style="overflow-x: hidden;background:url(/assets/images/backgrounds/anime/1.webp?v=3) center center fixed; background-color: var(--background)"{% elif v and v.background %}style="overflow-x: hidden;background:url(/assets/images/backgrounds/{{v.background}}?v=3) center center fixed; background-color: var(--background){% if 'anime' not in v.background %};background-size: cover{% endif %}"{% endif %}>
<body id="settings2" {% if SITE_NAME == 'rDrama' and (v.is_banned or v.agendaposter) %}style="overflow-x: hidden;background:url(/assets/images/backgrounds/anime/1.webp?v=3) center center fixed; background-color: var(--background)"{% elif v.background %}style="overflow-x: hidden;background:url(/assets/images/backgrounds/{{v.background}}?v=3) center center fixed; background-color: var(--background){% if 'anime' not in v.background %};background-size: cover{% endif %}"{% endif %}>
{% include "header.html" %}
@ -29,7 +29,7 @@
<li class="nav-item">
<a class="nav-link{% if request.path == '/banned' %} active{% endif %}" href="/banned"><i class="fas fa-user-slash pr-2"></i>Permabanned Users</a>
</li>
{% if v and v.admin_level >= PERMS['USER_BLOCKS_VISIBLE'] -%}
{% if v.admin_level >= PERMS['USER_BLOCKS_VISIBLE'] -%}
<li class="nav-item">
<a class="nav-link{% if request.path == '/blocks' %} active{% endif %}" href="/blocks"><i class="fas fa-user-slash pr-2"></i>Blocks</a>
</li>

View File

@ -1,9 +1,6 @@
{% extends "default.html" %}
{% block pagetitle %}Edit {{SITE_NAME}} sidebar{% endblock %}
{% block content %}
{% if error %}
<div class="alert alert-danger alert-dismissible fade show mb-3 mt-4" role="alert">
<i class="fas fa-exclamation-circle my-auto"></i>
@ -28,7 +25,6 @@
</div>
{% endif %}
<div class="title w-lg-25 mt-5">
<label class="text-lg" for="stealth">Stealth Mode</label>
</div>
@ -40,17 +36,13 @@
<span class="text-small text-muted">Make this hole blocked by default (users can visit it to unblock it).</span>
</div>
<h5 class=" mt-5">Marsey</h5>
<div class="settings-section rounded">
<div class="d-flex">
<div class="title w-lg-25 text-md-center">
<img loading="lazy" alt="sub marsey picture" src="{{sub.marsey_url}}" class="profile-pic-75">
</div>
<div class="body w-lg-100 my-auto">
<div class="d-flex">
@ -62,34 +54,22 @@
Update<input autocomplete="off" type="file" accept="image/*" {% if g.is_tor %}disabled{% endif %} hidden name="marsey" onchange="form.submit()">
</label>
</form>
</div>
</div>
<div class="text-small text-muted mt-3">All image files are supported. Max file size is {% if v and v.patron %}16{% else %}8{% endif %} MB.</div>
<div class="text-small text-muted mt-3">All image files are supported. Max file size is {% if v.patron %}16{% else %}8{% endif %} MB.</div>
</div>
</div>
</div>
<h5 class=" mt-5">Sidebar Picture</h5>
<div class="settings-section rounded">
<div class="d-flex">
<div class="title w-lg-25 text-md-center">
<img loading="lazy" alt="sub sidebar picture" src="{{sub.sidebar_url}}" class="profile-pic-75">
</div>
<div class="body w-lg-100 my-auto">
<div class="d-flex">
<div>
<form action="/h/{{sub}}/sidebar_image" method="post" enctype="multipart/form-data">
<input type="hidden" name="formkey" value="{{v|formkey}}">
@ -97,35 +77,21 @@
Update<input autocomplete="off" type="file" accept="image/*" {% if g.is_tor %}disabled{% endif %} hidden name="sidebar" onchange="form.submit()">
</label>
</form>
</div>
</div>
<div class="text-small text-muted mt-3">All image files are supported. Max file size is {% if v and v.patron %}16{% else %}8{% endif %} MB.</div>
<div class="text-small text-muted mt-3">All image files are supported. Max file size is {% if v.patron %}16{% else %}8{% endif %} MB.</div>
</div>
</div>
</div>
<h5 class=" mt-5">Banner</h5>
<div class="settings-section rounded">
<div class="d-flex">
<div class="title w-lg-75 text-md-center">
<img loading="lazy" alt="/h/{[sub.name]} banner" src="{{sub.banner_url}}" class="banner-pic-135">
</div>
<div class="body w-lg-100 my-auto">
<div class="d-flex">
<div>
<form action="/h/{{sub}}/banner" method="post" enctype="multipart/form-data">
<input type="hidden" name="formkey" value="{{v|formkey}}">
@ -133,21 +99,13 @@
Update<input autocomplete="off" type="file" {% if g.is_tor %}disabled{% endif %} accept="image/*" hidden name="banner" onchange="form.submit()">
</label>
</form>
</div>
</div>
<div class="text-small text-muted mt-3">All image files are supported. Max file size is {% if v and v.patron %}16{% else %}8{% endif %} MB.</div>
<div class="text-small text-muted mt-3">All image files are supported. Max file size is {% if v.patron %}16{% else %}8{% endif %} MB.</div>
</div>
</div>
</div>
<div class="row my-5 pt-5">
<div class="col col-md-8">
<div class="settings">
@ -193,5 +151,4 @@
</div>
</div>
</div>
{% endblock %}

View File

@ -3,23 +3,17 @@
{% set downs=p.downvotes %}
{% set score=ups-downs %}
{% if v %}
{% set voted=p.voted if p.voted else 0 %}
{% else %}
{% set voted=-2 %}
{% endif %}
{% set v_forbid_deleted = (p.deleted_utc != 0) and not (v and v.admin_level >= PERMS['POST_COMMENT_MODERATION']) and not (v and v.id == p.author_id) %}
{% set voted = p.voted if v else -2 %}
{% set appear_deleted = (p.deleted_utc != 0 and not v.admin_level >= PERMS['POST_COMMENT_MODERATION']) or
(p.author.shadowbanned and not v.admin_level >= PERMS['USER_SHADOWBAN'] and not (v and v.id == p.author_id)) %}
{% set v_forbid_deleted = appear_deleted or (p.is_banned and not v.admin_level >= PERMS['POST_COMMENT_MODERATION']) and not (v and v.id == p.author_id) %}
{% block title %}
<style>
body > .container {
padding-left: 20px !important;
padding-right: 20px !important;
}
</style>
{% include "awards.html" %}
{% if SITE_NAME == 'PCM' %}
{% include "awards_PCM.html" %}
@ -27,9 +21,7 @@
{% endblock %}
{% block pagetype %}thread{% endblock %}
{% block actionsModal %}
{% if v %}
<div class="modal fade d-md-none" id="actionsModal" tabindex="-1" role="dialog" aria-labelledby="actionsModalTitle" aria-hidden="true">
<div class="modal-dialog modal-dialog-centered" role="document">
@ -71,15 +63,13 @@
{% endif %}
<div class="row mb-3">
<div id="post-root" class="col-12">
<div class="card border-0 mt-3 {% if p.stickied %}stickied{% endif %} {% if voted==1 %}upvoted{% elif voted==-1 %} downvoted{% endif %}">
<div id="post-{{p.id}}" class="actual-post {% if p.is_banned %}banned{% endif %} {% if p.deleted_utc %}deleted {% endif %} {% if p.award_count('tilt', v) %}p-3{% endif %} {% if p.award_count('glowie', v) %}glow{% endif %} d-flex flex-row-reverse flex-nowrap justify-content-end">
<div id="post-{{p.id}}" class="actual-post {% if p.is_banned %}banned{% endif %} {% if appear_deleted %}deleted {% endif %} {% if p.award_count('tilt', v) %}p-3{% endif %} {% if p.award_count('glowie', v) %}glow{% endif %} d-flex flex-row-reverse flex-nowrap justify-content-end">
{% if not p.is_image and p.thumb_url and not p.embed_url %}
<div class="card-header bg-transparent border-0 d-none d-md-flex flex-row flex-nowrap pl-3 p-0">
<a rel="nofollow noopener" href="{{p.realurl(v)}}" style="height: fit-content"{% if not v or v.newtabexternal %}target="_blank"{% endif %}><img loading="lazy" src="{{p.thumb_url}}" class="post-img d-mob-none" alt="Unable to load image"></a>
<a rel="nofollow noopener" href="{{p.realurl(v)}}" style="height: fit-content"{% if v.newtabexternal %}target="_blank"{% endif %}><img loading="lazy" src="{{p.thumb_url}}" class="post-img d-mob-none" alt="Unable to load image"></a>
</div>
{% endif %}
@ -110,7 +100,7 @@
<i class="{{a.class_list}} px-1" data-bs-toggle="tooltip" data-bs-placement="bottom" title="{{a.title}} Award given by @{{a.user.username}}"></i>
{% endfor %}
{% if v and v.admin_level >= PERMS['USER_SHADOWBAN'] and p.author.shadowbanned %}<i class="fas fa-user-times text-admin" data-bs-toggle="tooltip" data-bs-placement="bottom" title='Shadowbanned by @{{p.author.shadowbanned}} for "{{p.author.ban_reason}}"'></i>{% endif %}
{% if v.admin_level >= PERMS['USER_SHADOWBAN'] and p.author.shadowbanned %}<i class="fas fa-user-times text-admin" data-bs-toggle="tooltip" data-bs-placement="bottom" title='Shadowbanned by @{{p.author.shadowbanned}} for "{{p.author.ban_reason}}"'></i>{% endif %}
{% if p.stickied %}
<i id='pinned-{{p.id}}' class="fas fa-thumbtack fa-rotate--45 text-admin" data-bs-toggle="tooltip" data-bs-placement="bottom" title="Pinned by @{{p.stickied}}" {% if p.stickied_utc %}onmouseover="pinned_timestamp('pinned-{{p.id}}')" data-timestamp={{p.stickied_utc}} {% endif %}></i>
@ -157,7 +147,7 @@
{% endif %}
{% endif %}
<span data-bs-toggle="tooltip" data-bs-placement="bottom" id="timestamp" onmouseover="timestamp('timestamp','{{p.created_utc}}')">&nbsp;{{p.age_string}}</span>
({% if p.is_image %}image post{% elif p.is_video %}video post{% elif p.is_audio %}audio post{% elif p.domain %}<a href="/search/posts/?q=domain%3A{{p.domain}}&sort=new&t=all" class="post-meta-domain" {% if not v or v.newtabexternal %}target="_blank"{% endif %}>{{p.domain|truncate(50, True)}}</a>{% else %}text post{% endif %})
({% if p.is_image %}image post{% elif p.is_video %}video post{% elif p.is_audio %}audio post{% elif p.domain %}<a href="/search/posts/?q=domain%3A{{p.domain}}&sort=new&t=all" class="post-meta-domain" {% if v.newtabexternal %}target="_blank"{% endif %}>{{p.domain|truncate(50, True)}}</a>{% else %}text post{% endif %})
{% if p.edited_utc %}
<span class="ml-2">Edited <span data-bs-toggle="tooltip" data-bs-placement="bottom" onmouseover="timestamp('edited_timestamp','{{p.edited_utc}}')" id="edited_timestamp">{{p.edited_string}}</span></span>
@ -176,7 +166,7 @@
{% endif %}
{% if p.realurl(v) and not v_forbid_deleted %}
<h1 id="post-title" class="card-title post-title text-left mb-md-3 {% if p.author.agendaposter and p.sub != 'chudrama' %}agendaposter{% endif %}">
<a {% if p.author.rainbow %}class="rainbow-text"{% endif %} {% if not v or v.newtabexternal %}target="_blank"{% endif %} rel="nofollow noopener" href="{{p.realurl(v)}}">
<a {% if p.author.rainbow %}class="rainbow-text"{% endif %} {% if v.newtabexternal %}target="_blank"{% endif %} rel="nofollow noopener" href="{{p.realurl(v)}}">
{% if p.club %}<span class="patron font-weight-bolder mr-1" style="background-color:red; font-size:12px; line-height:2;">{{CC}}</span>{% endif %}
{% if p.flair %}<span class="patron font-weight-bolder mr-1" style="background-color:var(--primary); font-size:12px; line-height:2;">{{p.flair | safe}}</span>{% endif %}
{{p.realtitle(v) | safe}}
@ -190,71 +180,65 @@
</h1>
{% endif %}
{% if not v_forbid_deleted %}
<div id="post-body" class="post-body mt-3">
{% if p.realurl(v) %}
{% if not p.embed_url and not p.is_image %}
<a rel="nofollow noopener" href="{{p.realurl(v)}}" {% if not v or v.newtabexternal %}target="_blank"{% endif %}>
<div class="d-flex {% if p.is_video or p.is_audio %}d-md-none{% endif %} justify-content-between align-items-center border rounded p-2 mb-3">
<span>{{p.realurl(v)}}</span>
<i class="fas fa-external-link-alt text-small"></i>
</div>
</a>
{% endif %}
{% endif %}
{% if p.embed_url %}
{% if p.domain == "twitter.com" %}
{{p.embed_url | safe}}
{% if v and v.theme.split("_")[0] in ["light", "coffee", "4chan"] %}
<script defer src="{{'js/twitterlight.js' | asset}}"></script>
{% else %}
<script defer src="{{'js/twitter.js' | asset}}"></script>
{% if not v_forbid_deleted %}
{% if p.realurl(v) %}
{% if not p.embed_url and not p.is_image %}
<a rel="nofollow noopener" href="{{p.realurl(v)}}" {% if v.newtabexternal %}target="_blank"{% endif %}>
<div class="d-flex {% if p.is_video or p.is_audio %}d-md-none{% endif %} justify-content-between align-items-center border rounded p-2 mb-3">
<span>{{p.realurl(v)}}</span>
<i class="fas fa-external-link-alt text-small"></i>
</div>
</a>
{% endif %}
{% endif %}
{% if p.embed_url %}
{% if p.domain == "twitter.com" %}
{{p.embed_url | safe}}
{% if v.theme.split("_")[0] in ["light", "coffee", "4chan"] %}
<script defer src="{{'js/twitterlight.js' | asset}}"></script>
{% else %}
<script defer src="{{'js/twitter.js' | asset}}"></script>
{% endif %}
{% elif p.domain in ['youtu.be','youtube.com'] and p.embed_url and p.embed_url.startswith('<lite-youtube') %}
{{p.embed_url | safe}}
{% endif %}
{% elif p.domain in ['youtu.be','youtube.com'] and p.embed_url and p.embed_url.startswith('<lite-youtube') %}
{{p.embed_url | safe}}
{% endif %}
{% endif %}
<div id="post-text" class="{% if p.author.agendaposter and p.sub != 'chudrama' %}agendaposter{% endif %} {% if p.author.rainbow %}rainbow-text{% endif %}">
{% if p.is_image %}
<div class="row no-gutters mb-4">
<div class="col">
<a {% if not v or v.newtabexternal %}target="_blank"{% endif %} rel="nofollow noopener" href="{{p.realurl(v)}}">
<img onclick="expandDesktopImage()" src="{{p.realurl(v)}}" class="img-fluid" style="max-height:500px" alt="Unable to load image">
</a>
{% if not v_forbid_deleted %}
{% if p.is_image %}
<div class="row no-gutters mb-4">
<div class="col">
<a {% if v.newtabexternal %}target="_blank"{% endif %} rel="nofollow noopener" href="{{p.realurl(v)}}">
<img onclick="expandDesktopImage()" src="{{p.realurl(v)}}" class="img-fluid" style="max-height:500px" alt="Unable to load image">
</a>
</div>
</div>
</div>
{% elif p.is_video %}
<div class="row no-gutters mb-4">
<div class="col">
<video controls preload="none" src="{{p.realurl(v)}}"></video>
{% elif p.is_video %}
<div class="row no-gutters mb-4">
<div class="col">
<video controls preload="none" src="{{p.realurl(v)}}"></video>
</div>
</div>
</div>
{% elif p.is_audio %}
<div class="row no-gutters mb-4">
<div class="col">
<audio controls preload="none" src="{{p.realurl(v)}}"></audio>
{% elif p.is_audio %}
<div class="row no-gutters mb-4">
<div class="col">
<audio controls preload="none" src="{{p.realurl(v)}}"></audio>
</div>
</div>
</div>
{% endif %}
{% endif %}
{{p.realbody(v) | safe}}
{% if p.is_banned and p.ban_reason %}
<div class="text-removed mb-0">removed by @{{p.ban_reason}} (Admin)</div>
{% endif %}
</div>
</div>
{% else %}
<div id="post-body" class="post-body mt-3">
<div id="post-text"><code>[Deleted by author.]</code></div>
</div>
{% endif %}
{% if v and (v.id==p.author_id or v.admin_level >= PERMS['POST_EDITING']) and not v.is_suspended %}
{% if v and (v.id==p.author_id and not v.is_suspended) or v.admin_level >= PERMS['POST_EDITING'] %}
<div id="edit-post-body-{{p.id}}" class="d-none comment-write collapsed child">
<form id="post-edit-form-{{p.id}}" action="/edit_post/{{p.id}}" method="post" enctype="multipart/form-data">
<input type="hidden" name="formkey" value="{{v|formkey}}">
@ -279,7 +263,7 @@
<button type="button" onclick="togglePostEdit('{{p.id}}');remove_dialog()" class="btn btn-link text-muted ml-auto cancel-form fl-r">Cancel</button>
</form>
<div id="post-edit-{{p.id}}" class="preview mb-3 mt-5"></div>
<div class="form-text text-small p-0 m-0"><a href="/formatting" {% if v and v.newtab and not g.webview %}target="_blank"{% endif %}>Formatting help</a></div>
<div class="form-text text-small p-0 m-0"><a href="/formatting" {% if v.newtab and not g.webview %}target="_blank"{% endif %}>Formatting help</a></div>
</div>
{% endif %}
@ -298,7 +282,7 @@
<div class="post-actions mt-2">
<ul class="list-inline text-right d-flex">
<a class="list-inline-item" {% if v and v.newtab and not g.webview %}target="_blank"{% endif %} href="{{p.permalink}}">
<a class="list-inline-item" {% if v.newtab and not g.webview %}target="_blank"{% endif %} href="{{p.permalink}}">
<i class="fas fa-comment-dots mr-2"></i>{{p.comment_count}}
<span class="text-info d-none {{p.id}}-new-comments"></span>
</a>
@ -338,14 +322,8 @@
</div>
{% endif %}
</div>
</div>
</div>
</div>
@ -459,7 +437,7 @@
<button type="button" id="save-reply-to-{{p.fullname}}" form="reply-to-{{p.fullname}}" class="btn btn-primary text-whitebtn ml-auto fl-r" onclick="post_comment('{{p.fullname}}');remove_dialog()">Comment</button>
</form>
<div id="form-preview-{{p.fullname}}" class="preview mb-3 mt-5"></div>
<div class="form-text text-small p-0 m-0"><a href="/formatting" {% if v and v.newtab and not g.webview %}target="_blank"{% endif %}>Formatting help</a></div>
<div class="form-text text-small p-0 m-0"><a href="/formatting" {% if v.newtab and not g.webview %}target="_blank"{% endif %}>Formatting help</a></div>
</div>
{% else %}
<div class="comment-write mb-3">
@ -542,35 +520,27 @@
</div>
{% if v and v.id==p.author_id %}
{% include "modals/delete_post.html" %}
{% endif %}
{% if v %}
{% include "modals/delete_post.html" if v.id == p.author_id else '' ignore missing %}
{% include "modals/report_post.html" %}
{% if v.id == p.author_id or v.admin_level >= PERMS['POST_EDITING'] %}
<script defer src="{{'js/togglePostEdit.js' | asset}}"></script>
{% endif %}
{% if v.admin_level >= PERMS['POST_COMMENT_MODERATION'] %}
<script defer src="{{'js/pinpost.js' | asset}}"></script>
{% endif %}
{% endif %}
{% if v and (v.id == p.author_id or v.admin_level >= PERMS['POST_EDITING']) %}
<script defer src="{{'js/togglePostEdit.js' | asset}}"></script>
{% endif %}
{% if not v or v.highlightcomments %}
{% if v.highlightcomments %}
<script defer src="{{'js/highlightcomments.js' | asset}}"></script>
{% endif %}
{% if v and v.admin_level >= PERMS['POST_COMMENT_MODERATION'] %}
<script defer src="{{'js/pinpost.js' | asset}}"></script>
{% endif %}
<script defer src="{{'js/clipboard.js' | asset}}"></script>
{% include "comments.html" if not p.replies else '' ignore missing %}
{% if not p.replies %}
{% include "comments.html" %}
{% endif %}
{% if v.highlightcomments %}
<script>
(() => {
{% if not v or v.highlightcomments %}
document.addEventListener('DOMContentLoaded', function() {
showNewCommentCounts('{{p.id}}', {{p.comment_count}})
{% if "?context" not in request.full_path %}
@ -582,9 +552,9 @@
localStorage.setItem("comment-counts", JSON.stringify(comments))
{% endif %}
})
{% endif %}
})()
</script>
{% endif %}
{% if success %}
<script>

View File

@ -1,142 +0,0 @@
{% extends "submission.html" %}
{% set score=p.score %}
{% if v %}
{% set voted=p.voted %}
{% set adjust=voted %}
{% else %}
{% set voted=-2 %}
{% set adjust=0 %}
{% endif %}
{% block title %}
<title>{{p.plaintitle(v)}}</title>
{% if p.is_banned %}
{% else %}
{% endif %}
{% endblock %}
{% block content %}
<div class="mb-2 p-3">
<div class="col-12">
<div id="post-{{p.id}}" class="banned {% if p.award_count('glowie', v) %}glow{% endif %} card d-flex flex-row-reverse flex-nowrap justify-content-end border-0 p-0 {% if voted==1 %} upvoted{% elif voted==-1 %} downvoted{% endif %}">
<div class="card-block my-md-auto">
<div class="post-meta text-left d-md-none mb-1">{% if p.over_18 %}<span class="badge badge-danger">+18</span> {% endif %}{% if p.is_banned %}removed by @{{p.ban_reason}} (Admin){% else %}[Deleted by user]{% endif %}</div>
<h5 class="card-title post-title text-left mb-0 mb-md-1">{{p.plaintitle(v)}}</h5>
<div class="post-meta text-left d-mob-none">{% if p.over_18 %}<span class="badge badge-danger">+18</span> {% endif %}{% if p.is_banned %}removed by @{{p.ban_reason}} (Admin){% else %}[Deleted by user]{% endif %}</div>
</div>
<div id="voting" class="d-md-block my-auto mr-3 text-center">
<div class="post-{{p.id}}-up arrow-up mx-auto">
</div>
<span class="post-{{p.id}}-score-up score-up text-muted{% if voted!=1 %} d-none{% endif %}">âś–</span>
<span class="post-{{p.id}}-score-none score text-muted{% if voted!=0 and voted!=-2 %} d-none{% endif %}">âś–</span>
<span class="post-{{p.id}}-score-down score-down text-muted{% if voted!=-1 %} d-none{% endif %}">âś–</span>
<div class="post-{{p.id}}-down arrow-down mx-auto">
</div>
</div>
</div>
{% if v and v.admin_level >= PERMS['POST_COMMENT_MODERATION'] and p.body_html %}
<div class="post-body mt-4 mb-2">
{{p.body_html | safe}}
</div>
{% endif %}
</div>
</div>
<div class="row mb-2 p-3">
<div class="col-12">
<div class="post-actions d-mob-none">
<ul class="list-inline text-left mb-2">
<li class="list-inline-item"><a href="{{p.permalink}}"><i
class="fas fa-comment-dots mr-2"></i>{{p.comment_count}} Comment{{'s' if p.comment_count != 1 else ''}}</a>
</li>
</ul>
</div>
</div>
</div>
<div class="comment-section">
{% with comments=p.replies %}
{% include "comments.html" %}
{% endwith %}
</div>
{% if offset %}
<script>
function viewmore(pid,sort,offset,ids) {
btn = document.getElementById("viewbtn");
btn.disabled = true;
btn.innerHTML = "Requesting...";
const form = new FormData();
const xhr = new XMLHttpRequest();
xhr.open("get", `/viewmore/${pid}/${sort}/${offset}?ids=${ids}`);
xhr.setRequestHeader('xhr', 'xhr');
xhr.onload=function(){
if (xhr.status==200) {
let e = document.getElementById(`viewmore-${offset}`);
e.innerHTML = xhr.response.replace(/data-src/g, 'src').replace(/data-cfsrc/g, 'src').replace(/style="display:none;visibility:hidden;"/g, '');
bs_trigger(e)
comments = JSON.parse(localStorage.getItem("old-comment-counts")) || {}
lastCount = comments['{{p.id}}']
if (lastCount)
{
{% for c in p.comments %}
{% if not (v and v.id==c.author_id) and not c.voted %}
if ({{c.created_utc*1000}} > lastCount.t)
try {document.getElementById("comment-{{c.id}}-only").classList.add('unread')}
catch(e) {}
{% endif %}
{% endfor %}
}
}
btn.disabled = false;
}
xhr.send(form)
}
</script>
{% endif %}
{% endblock %}
{% block mobileactions %}
<div class="row fixed-top bg-white shadow d-inline-flex d-md-none p-3" id="footer-actions" style="z-index: 3; top: 48px; transition: top cubic-bezier(0, 0, 0.2, 1) 220ms;">
<div class="col text-center">
<div class="post-actions mx-auto">
<ul class="list-inline">
<li id="voting-mobile" class="voting list-inline-item{% if voted==1 %} upvoted{% elif voted==-1 %} downvoted{% endif %}">
<span class="arrow-mobile-up mr-2 arrow-mobile-up">
<i class="fas fa-arrow-alt-up mx-0"></i>
</span>
<span class="post-{{p.id}}-score-mobile-up score-up text-muted{% if voted!=1 %} d-none{% endif %}">âś–</span>
<span class="post-{{p.id}}-score-mobile-none score text-muted{% if voted!=0 and voted!=-2 %} d-none{% endif %}">âś–</span>
<span class="post-{{p.id}}-score-mobile-down score-down text-muted{% if voted!=-1 %} d-none{% endif %}">âś–</span>
<span class="arrow-mobile-down arrow-mobile-down ml-2 my-0">
<i class="fas fa-arrow-alt-down mx-0"></i>
</span>
</li>
</ul>
</div>
</div>
</div>
{% endblock %}

View File

@ -10,29 +10,27 @@
{% set cc='COUNTRY CLUB' %}
{% endif %}
{% if not v or v.highlightcomments %}
{% if v.highlightcomments %}
<script defer src="{{'js/highlightcomments.js' | asset}}"></script>
{% endif %}
{% if v and v.admin_level > 1 %}
{% if v and v.admin_level >= PERMS['POST_COMMENT_MODERATION'] %}
<script defer src="{{'js/pinpost.js' | asset}}"></script>
{% endif %}
{% include "popover.html" %}
{% for p in listing if user_can_see(v, p) %}
{% for p in listing if v.can_see(p) %}
{% set ups=p.upvotes %}
{% set downs=p.downvotes %}
{% set score=ups-downs %}
{% if v %}
{% set voted= p.voted %}
{% else %}
{% set voted=-2 %}
{% endif %}
{% set voted = p.voted if v else -2 %}
{% set v_forbid_deleted = (p.deleted_utc != 0 or p.is_banned) and not (v and v.admin_level >= PERMS['POST_COMMENT_MODERATION']) and not (v and v.id == p.author_id) %}
{% set appear_deleted = (p.deleted_utc != 0 and not v.admin_level >= PERMS['POST_COMMENT_MODERATION']) or
(p.author.shadowbanned and not v.admin_level >= PERMS['USER_SHADOWBAN'] and not (v and v.id == p.author_id)) %}
{% set v_forbid_deleted = appear_deleted or (p.is_banned and not v.admin_level >= PERMS['POST_COMMENT_MODERATION']) and not (v and v.id == p.author_id) %}
{% if p.active_flags(v) %}
<div id="flaggers-{{p.id}}" class="flaggers d-none">
@ -45,7 +43,7 @@
</div>
{% endif %}
<div id="post-{{p.id}}" class="actual-post {% if p.unread %}unread{% else %}card{% endif %} {% if p.is_banned %} banned{% endif %}{% if p.deleted_utc %} deleted{% endif %}{% if p.stickied %} stickied{% endif %}{% if voted==1 %} upvoted{% elif voted==-1 %} downvoted{% endif %}{% if p.over_18 %} nsfw{% endif %}">
<div id="post-{{p.id}}" class="actual-post {% if p.unread %}unread{% else %}card{% endif %} {% if p.is_banned %} banned{% endif %}{% if appear_deleted %} deleted{% endif %}{% if p.stickied %} stickied{% endif %}{% if voted==1 %} upvoted{% elif voted==-1 %} downvoted{% endif %}{% if p.over_18 %} nsfw{% endif %}">
<div class="d-flex flex-row-reverse flex-md-row flex-nowrap" style="align-items:flex-start">
<div class="voting my-2 d-none d-md-flex pr-2">
@ -82,7 +80,7 @@
{% if p.club and not (v and (v.paid_dues or v.id == p.author_id)) %}
<img alt="post thumnail" loading="lazy" src="/e/marseyglow.webp" class="post-img">
{% elif not p.url %}
<a {% if v and v.newtab and not g.webview %}target="_blank"{% endif %} href="{{p.permalink}}">
<a {% if v.newtab and not g.webview %}target="_blank"{% endif %} href="{{p.permalink}}">
<img alt="post thumnail" loading="lazy" src="{{p.thumb_url}}" class="post-img">
</a>
{% elif p.is_image %}
@ -98,7 +96,7 @@
<img onclick="toggleyoutube('{{p.id}}')" alt="post thumnail" loading="lazy" src="{{p.thumb_url}}" class="post-img">
</a>
{% else %}
<a {% if not v or v.newtabexternal %}target="_blank"{% endif %} rel="nofollow noopener" href="{{p.realurl(v)}}">
<a {% if v.newtabexternal %}target="_blank"{% endif %} rel="nofollow noopener" href="{{p.realurl(v)}}">
<img alt="post thumnail" loading="lazy" src="{{p.thumb_url}}" class="post-img">
<i class="ext-link fas fa-external-link"></i>
</a>
@ -138,7 +136,7 @@
<i class="{{a.class_list}} px-1" data-bs-toggle="tooltip" data-bs-placement="bottom" title="{{a.title}} Award given by @{{a.user.username}}"></i>
{% endfor %}
{% if v and v.admin_level >= PERMS['USER_SHADOWBAN'] and p.author.shadowbanned %}
{% if v.admin_level >= PERMS['USER_SHADOWBAN'] and p.author.shadowbanned %}
<i class="fas fa-user-times text-admin" data-bs-toggle="tooltip" data-bs-placement="bottom" title='Shadowbanned by @{{p.author.shadowbanned}} for "{{p.author.ban_reason}}"'></i>
{% endif %}
@ -190,7 +188,7 @@
{% endif %}
<span data-bs-toggle="tooltip" data-bs-placement="bottom" onmouseover="timestamp('timestamp-{{p.id}}','{{p.created_utc}}')" id="timestamp-{{p.id}}">&nbsp;{{p.age_string}}</span>
&nbsp;
({% if p.is_image %}image post{% elif p.is_video %}video post{% elif p.is_audio %}audio post{% elif p.domain %}<a href="/search/posts/?q=domain%3A{{p.domain}}&sort=new&t=all" class="post-meta-domain" {% if v and v.newtab and not g.webview %}target="_blank"{% endif %}>{{p.domain|truncate(50, True)}}</a>{% else %}text post{% endif %})
({% if p.is_image %}image post{% elif p.is_video %}video post{% elif p.is_audio %}audio post{% elif p.domain %}<a href="/search/posts/?q=domain%3A{{p.domain}}&sort=new&t=all" class="post-meta-domain" {% if v.newtab and not g.webview %}target="_blank"{% endif %}>{{p.domain|truncate(50, True)}}</a>{% else %}text post{% endif %})
{% if p.edited_utc %}
<span class="ml-2">Edited <span data-bs-toggle="tooltip" data-bs-placement="bottom" id="edited_timestamp-{{p.id}}" onmouseover="timestamp('edited_timestamp-{{p.id}}','{{p.edited_utc}}')">{{p.edited_string}}</span></span>
{% endif %}
@ -199,7 +197,7 @@
</div>
<h5 class="card-title post-title text-left w-lg-95 pb-0 pb-md-1">
<a id="{{p.id}}-title" {% if v and v.newtab and not g.webview %}target="_blank"{% endif %} href="{{p.permalink}}" class="{% if p.sub %}sub{% endif %} stretched-link {% if p.author.agendaposter and p.sub != 'chudrama' %}agendaposter{% endif %}">
<a id="{{p.id}}-title" {% if v.newtab and not g.webview %}target="_blank"{% endif %} href="{{p.permalink}}" class="{% if p.sub %}sub{% endif %} stretched-link {% if p.author.agendaposter and p.sub != 'chudrama' %}agendaposter{% endif %}">
{% if p.club %}<span class="patron font-weight-bolder mr-1" style="background-color:red; font-size:12px; line-height:2;">{{CC}}</span>{% endif %}
{% if p.flair %}<span class="patron font-weight-bolder mr-1" style="background-color:var(--primary); font-size:12px; line-height:2;">{{p.flair | safe}}</span>{% endif %}
{{p.realtitle(v) | safe}}
@ -213,7 +211,7 @@
{% if p.realbody(v, listing=True) %}
<button type="button" class="list-inline-item ml-2" onclick="expandText('{{p.id}}')"><i class="fas fa-expand-alt mx-0 text-expand-icon-{{p.id}}"></i></button>
{% endif %}
<a class="list-inline-item" {% if v and v.newtab and not g.webview %}target="_blank"{% endif %} href="{{p.permalink}}">
<a class="list-inline-item" {% if v.newtab and not g.webview %}target="_blank"{% endif %} href="{{p.permalink}}">
<i class="fas fa-comment-dots mr-2"></i>{{p.comment_count}}
<span class="text-info d-none {{p.id}}-new-comments"></span>
</a>
@ -225,7 +223,7 @@
<div class="post-actions">
<ul class="list-inline text-right d-flex">
<li class="list-inline-item mr-auto">
<a {% if v and v.newtab and not g.webview %}target="_blank"{% endif %} href="{{p.permalink}}">
<a {% if v.newtab and not g.webview %}target="_blank"{% endif %} href="{{p.permalink}}">
<i class="fas fa-comment-dots ml-0 mr-2"></i>{{p.comment_count}}
<span class="text-info d-none {{p.id}}-new-comments"></span>
</a>
@ -305,13 +303,13 @@
</div>
{% endif %}
{% if v.highlightcomments %}
<script>
{% if not v or v.highlightcomments %}
document.addEventListener('DOMContentLoaded', function() {
showNewCommentCounts({{p.id}}, {{p.comment_count}})
})
{% endif %}
</script>
{% endif %}
{% if v and v.admin_level >= PERMS['POST_COMMENT_MODERATION'] %}
@ -326,22 +324,22 @@
</div>
{% endif %}
{% if p.is_image and not p.over_18 and ((v and v.cardview) or (not v and CARD_VIEW)) %}
{% if p.is_image and not p.over_18 and v.cardview %}
<div style="text-align: center" class="mt-3 mb-4">
<a {% if v and v.newtab and not g.webview %}target="_blank"{% endif %} rel="nofollow noopener" href="{{p.realurl(v)}}">
<a {% if v.newtab and not g.webview %}target="_blank"{% endif %} rel="nofollow noopener" href="{{p.realurl(v)}}">
<img loading="lazy" data-src="{{p.realurl(v)}}" src="/i/l.webp" class="img-fluid" style="max-height:20rem" alt="Unable to load image">
</a>
</div>
{% elif p.is_video %}
<div id="video-{{p.id}}" style="text-align: center" class="{% if p.over_18 or not ((v and v.cardview) or (not v and CARD_VIEW)) %}d-none{% endif %} mt-4">
<div id="video-{{p.id}}" style="text-align: center" class="{% if p.over_18 or not v.cardview %}d-none{% endif %} mt-4">
<video id="video2-{{p.id}}" controls preload="none" src="{{p.realurl(v)}}"></video>
</div>
{% elif p.is_audio %}
<div id="video-{{p.id}}" style="text-align: center" class="{% if p.over_18 or not ((v and v.cardview) or (not v and CARD_VIEW)) %}d-none{% endif %} mt-4">
<div id="video-{{p.id}}" style="text-align: center" class="{% if p.over_18 or not v.cardview %}d-none{% endif %} mt-4">
<audio id="video2-{{p.id}}" controls preload="none" src="{{p.realurl(v)}}"></audio>
</div>
{% elif p.is_youtube %}
<div id="video-{{p.id}}" class="{% if p.over_18 or not ((v and v.cardview) or (not v and CARD_VIEW)) %}d-none{% endif %} mt-3 mb-4 youtube_embed">
<div id="video-{{p.id}}" class="{% if p.over_18 or not v.cardview %}d-none{% endif %} mt-3 mb-4 youtube_embed">
{{p.embed_url | safe}}
</div>
{% endif %}

View File

@ -87,7 +87,7 @@
<div id="preview" class="preview my-3"></div>
<div class="form-text text-small my-1"><a href="/formatting" {% if v and v.newtab and not g.webview %}target="_blank"{% endif %}>Formatting help</a></div>
<div class="form-text text-small my-1"><a href="/formatting" {% if v.newtab and not g.webview %}target="_blank"{% endif %}>Formatting help</a></div>
<div class="custom-control custom-checkbox">
<input autocomplete="off" type="checkbox" class="custom-control-input" id="post-notify" name="notify" onchange="savetext()" checked>

View File

@ -86,7 +86,7 @@
<img alt="marseybux" class="ml-1 mb-1 mr-2" data-bs-toggle="tooltip" data-bs-placement="bottom" title="Marseybux" height="20" width="46" src="/i/marseybux.webp?v=2000">
{% endif %}
{% if PERMS['USER_FOLLOWS_VISIBLE'] == 0 or (v and v.admin_level >= PERMS['USER_FOLLOWS_VISIBLE']) -%}
{% if v.admin_level >= PERMS['USER_FOLLOWS_VISIBLE'] -%}
<a class="mr-2" href="/@{{u.username}}/followers" id="profile--followers">{{u.stored_subscriber_count}} follower{{'s' if u.stored_subscriber_count != 1 else ''}}</a>
<a class="mr-2" href="/@{{u.username}}/following" id="profile--following">follows {{u.follow_count}} user{{'s' if u.follow_count != 1 else ''}}</a>
@ -94,7 +94,7 @@
<span id="profile--joined">joined <span id="profile--joined--time" data-bs-toggle="tooltip" data-bs-placement="bottom" onmouseover="timestamp('profile--joined--time','{{u.created_utc}}')">{{u.created_date}}</span></span>
{% if v and v.admin_level >= PERMS['VIEW_LAST_ACTIVE'] -%}
{% if v.admin_level >= PERMS['VIEW_LAST_ACTIVE'] -%}
<span id="profile--lastactive" class="ml-2">last active <span id="profile--lastactive--time" data-bs-toggle="tooltip" data-bs-placement="bottom" onmouseover="timestamp('profile--lastactive--time','{{u.last_active}}')">{{u.last_active_date}}</span></span>
{%- endif %}
</div>
@ -295,7 +295,7 @@
<i class="fas fa-broom text-admin align-middle ml-1" data-bs-toggle="tooltip" data-bs-placement="bottom" title="Admin"></i>
</span>
{% endif %}
{% if v and v.id != u.id and v.has_follower(u) %}
{% if v.has_follower(u) %}
<span class="followsyou badge badge-secondary text-small align-middle mx-1" id="profile-mobile--follows-you">Follows you</span>
{% endif %}
@ -320,7 +320,7 @@
<img alt="marseybux" class="ml-1 mb-1 mr-2" data-bs-toggle="tooltip" data-bs-placement="bottom" title="Marseybux" height="15" width="35" src="/i/marseybux.webp?v=2000">
{% endif %}
{% if PERMS['USER_FOLLOWS_VISIBLE'] == 0 or (v and v.admin_level >= PERMS['USER_FOLLOWS_VISIBLE']) -%}
{% if v.admin_level >= PERMS['USER_FOLLOWS_VISIBLE'] -%}
<a href="/@{{u.username}}/followers" class="font-weight-bold mr-2" id="profile-mobile--followers">{{u.stored_subscriber_count}} follower{{'s' if u.stored_subscriber_count != 1 else ''}}</a>
<a href="/@{{u.username}}/following" class="font-weight-bold mr-2" id="profile-mobile--following" style="display:block">follows {{u.follow_count}} user{{'s' if u.follow_count != 1 else ''}}</a>
@ -332,7 +332,7 @@
<br><span id="profile-mobile--joined">joined <span id="profile-mobile--joined--time" data-bs-toggle="tooltip" data-bs-placement="bottom" onmouseover="timestamp('profile-mobile--joined--time','{{u.created_utc}}')" class="font-weight-bold">{{u.created_date}}</span></span>
{% if v and v.admin_level >= PERMS['VIEW_LAST_ACTIVE'] -%}
{% if v.admin_level >= PERMS['VIEW_LAST_ACTIVE'] -%}
<br><span id="profile-mobile--lastactive">last active <span id="profile-mobile--lastactive--time" data-bs-toggle="tooltip" data-bs-placement="bottom" onmouseover="timestamp('profile-mobile--lastactive--time','{{u.last_active}}')" class="font-weight-bold">{{u.last_active_date}}</span></span>
{%- endif %}
</div>

View File

@ -15,7 +15,7 @@ def worker_abort(worker):
from flask import g, request
if g and request:
worker.log.warning(f"While serving {request.method} {request.url}")
u = getattr(g, 'v', None)
u = g.v
if u:
worker.log.warning(f"User: {u.username!r} id:{u.id}")
else: