diff --git a/files/assets/js/comments_v.js b/files/assets/js/comments_v.js index 1635b6a69..3a918b3a6 100644 --- a/files/assets/js/comments_v.js +++ b/files/assets/js/comments_v.js @@ -50,7 +50,7 @@ function getSelectionTextHtml() { return html; } -function ToggleReplyBox(id) { +function toggleReplyBox(id) { const element = document.getElementById(id); const textarea = element.getElementsByTagName('textarea')[0] element.classList.toggle('d-none') @@ -142,7 +142,7 @@ function post_reply(id){ document.getElementById('reply-form-body-'+id).value = '' document.getElementById('message-reply-'+id).innerHTML = '' - ToggleReplyBox('reply-message-'+id) + toggleReplyBox('reply-message-'+id) document.getElementById('file-upload').value = null; } else { showToast(false, getMessageFromJsonData(false, data)); @@ -193,7 +193,7 @@ function comment_edit(id){ xhr[0].send(xhr[1]); } -function post_comment(fullname, wall_user_id, hide){ +function postComment(fullname, hide){ const btn = document.getElementById('save-reply-to-'+fullname) btn.disabled = true btn.classList.add('disabled'); @@ -202,7 +202,6 @@ function post_comment(fullname, wall_user_id, hide){ form.append('formkey', formkey()); form.append('parent_fullname', fullname); - form.append('submission', document.getElementById('reply-form-submission-'+fullname).value); form.append('body', document.getElementById('reply-form-body-'+fullname).value); try { @@ -212,8 +211,7 @@ function post_comment(fullname, wall_user_id, hide){ catch(e) {} const xhr = new XMLHttpRequest(); - if (wall_user_id == 'None') url = "/comment" - else url = '/wall_comment' + url = '/comments/'; xhr.open("post", url); xhr.setRequestHeader('xhr', 'xhr'); xhr.onload=function(){ diff --git a/files/helpers/actions.py b/files/helpers/actions.py index 8464baebd..c9b7988ed 100644 --- a/files/helpers/actions.py +++ b/files/helpers/actions.py @@ -21,6 +21,7 @@ from files.helpers.sanitize import * from files.helpers.settings import get_setting from files.helpers.slots import check_slots_command +post_target_type = Union[Submission, User] def _archiveorg(url): headers = {'User-Agent': 'Mozilla/4.0 (compatible; MSIE 5.5; Windows NT)'} @@ -43,7 +44,7 @@ def archive_url(url): url = url.replace('https://instagram.com/', 'https://imginn.com/') gevent.spawn(_archiveorg, url) -def execute_snappy(post, v): +def execute_snappy(post:Submission, v:User): snappy = get_account(SNAPPY_ID) if post.sub == 'dankchristianmemes' or post.sub == 'truth': @@ -199,10 +200,13 @@ def execute_snappy(post, v): post.comment_count += 1 post.replies = [c] -def execute_zozbot(c, level, parent_submission, v): +def execute_zozbot(c:Comment, level:int, post_target:post_target_type, v): + if SITE_NAME != 'rDrama': return + posting_to_submission = isinstance(post_target, Submission) if random.random() >= 0.001: return c2 = Comment(author_id=ZOZBOT_ID, - parent_submission=parent_submission, + parent_submission=post_target.id if posting_to_submission else None, + wall_user_id=post_target.id if not posting_to_submission else None, parent_comment_id=c.id, level=level+1, is_bot=True, @@ -219,7 +223,8 @@ def execute_zozbot(c, level, parent_submission, v): g.db.add(n) c3 = Comment(author_id=ZOZBOT_ID, - parent_submission=parent_submission, + parent_submission=post_target.id if posting_to_submission else None, + wall_user_id=post_target.id if not posting_to_submission else None, parent_comment_id=c2.id, level=level+2, is_bot=True, @@ -235,7 +240,8 @@ def execute_zozbot(c, level, parent_submission, v): c4 = Comment(author_id=ZOZBOT_ID, - parent_submission=parent_submission, + parent_submission=post_target.id if posting_to_submission else None, + wall_user_id=post_target.id if not posting_to_submission else None, parent_comment_id=c3.id, level=level+3, is_bot=True, @@ -253,7 +259,9 @@ def execute_zozbot(c, level, parent_submission, v): zozbot.pay_account('coins', 1) g.db.add(zozbot) -def execute_longpostbot(c, level, body, body_html, parent_submission, v): +def execute_longpostbot(c:Comment, level:int, body, body_html, post_target:post_target_type, v:User): + if SITE_NAME != 'rDrama': return + posting_to_submission = isinstance(post_target, Submission) if not len(c.body.split()) >= 200: return if "" in body_html: return body = random.choice(LONGPOST_REPLIES) @@ -268,7 +276,8 @@ def execute_longpostbot(c, level, body, body_html, parent_submission, v): c.downvotes = 1 c2 = Comment(author_id=LONGPOSTBOT_ID, - parent_submission=parent_submission, + parent_submission=post_target.id if posting_to_submission else None, + wall_user_id=post_target.id if not posting_to_submission else None, parent_comment_id=c.id, level=level+1, is_bot=True, @@ -288,9 +297,12 @@ def execute_longpostbot(c, level, body, body_html, parent_submission, v): n = Notification(comment_id=c2.id, user_id=v.id) g.db.add(n) -def execute_basedbot(c, level, body, parent_post, v): +def execute_basedbot(c:Comment, level:int, body, post_target:post_target_type, v:User): + if SITE != "pcmemes.net": return + if not c.body.lower().startswith("based"): return + posting_to_submission = isinstance(post_target, Submission) pill = based_regex.match(body) - if level == 1: basedguy = get_account(parent_post.author_id) + if level == 1: basedguy = get_account(post_target.author_id) else: basedguy = get_account(c.parent_comment.author_id) basedguy.basedcount += 1 if pill: @@ -303,7 +315,8 @@ def execute_basedbot(c, level, body, parent_post, v): body_based_html = sanitize(body2) c_based = Comment(author_id=BASEDBOT_ID, - parent_submission=parent_post.id, + parent_submission=post_target.id if posting_to_submission else None, + wall_user_id=post_target.id if not posting_to_submission else None, distinguish_level=6, parent_comment_id=c.id, level=level+1, @@ -514,3 +527,13 @@ def process_poll_options(target:Union[Submission, Comment], exclusive=exclusive, ) db.add(option) + +def execute_wordle(post_target:post_target_type, c:Comment, body:str, rts:bool): + if not FEATURES['WORDLE']: return + if not "!wordle" in body: return + answer = random.choice(WORDLE_LIST) + c.wordle_result = f'_active_{answer}' + + if not c.wordle_result and not rts: + post_target.comment_count += 1 + g.db.add(post_target) diff --git a/files/routes/comments.py b/files/routes/comments.py index c465a93bb..e86e73421 100644 --- a/files/routes/comments.py +++ b/files/routes/comments.py @@ -79,11 +79,12 @@ def post_pid_comment_cid(cid, pid=None, anything=None, v=None, sub=None): else: template = "submission.html" return render_template(template, v=v, p=post, sort=sort, comment_info=comment_info, render_replies=True, sub=post.subr) +@app.post("/comments/") @app.post("/comment") @limiter.limit("1/second;20/minute;200/hour;1000/day") @auth_required @ratelimit_user("1/second;20/minute;200/hour;1000/day") -def comment(v): +def comment(v:User): if v.is_suspended: abort(403, "You can't perform this action while banned.") parent_fullname = request.values.get("parent_fullname").strip() @@ -92,33 +93,43 @@ def comment(v): parent_comment_id = None rts = False - if parent_fullname.startswith("p_"): + post_target = None + parent = None + + if parent_fullname.startswith("u_"): + parent = get_account(id, v=v) + post_target = parent + elif parent_fullname.startswith("p_"): parent = get_post(id, v=v) - parent_post = parent + post_target = parent if POLL_THREAD and parent.id == POLL_THREAD and v.admin_level < PERMS['POST_TO_POLL_THREAD']: abort(403) elif parent_fullname.startswith("c_"): parent = get_comment(id, v=v) - parent_post = get_post(parent.parent_submission, v=v) + post_target = get_post(parent.parent_submission, v=v, graceful=True) or get_account(parent.wall_user_id, v=v, include_blocks=True, include_shadowbanned=False) parent_comment_id = parent.id if parent.author_id == v.id: rts = True - if not v.can_post_in_ghost_threads and parent_post.ghost: abort(403, f"You need {TRUESCORE_GHOST_MINIMUM} truescore to post in ghost threads") - else: abort(400) + if not v.can_post_in_ghost_threads and isinstance(post_target, Submission) and post_target.ghost: + abort(403, f"You need {TRUESCORE_GHOST_MINIMUM} truescore to post in ghost threads") + else: abort(404) - level = 1 if isinstance(parent, Submission) else parent.level + 1 - sub = parent_post.sub - if sub and v.exiled_from(sub): abort(403, f"You're exiled from /h/{sub}") - - if sub in ('furry','vampire','racist','femboy') and not v.client and not v.house.lower().startswith(sub): - abort(403, f"You need to be a member of House {sub.capitalize()} to comment in /h/{sub}") + level = 1 if isinstance(parent, (Submission, User)) else int(parent.level) + 1 + parent_user = parent if isinstance(parent, User) else parent.author + posting_to_submission = isinstance(post_target, Submission) if not User.can_see(v, parent): abort(404) - if parent.deleted_utc != 0: abort(404) + if not isinstance(parent, User) and parent.deleted_utc != 0: abort(404) + + if posting_to_submission: + sub = post_target.sub + if sub and v.exiled_from(sub): abort(403, f"You're exiled from /h/{sub}") + if sub in ('furry','vampire','racist','femboy') and not v.client and not v.house.lower().startswith(sub): + abort(403, f"You need to be a member of House {sub.capitalize()} to comment in /h/{sub}") if level > COMMENT_MAX_DEPTH: abort(400, f"Max comment level is {COMMENT_MAX_DEPTH}") body = sanitize_raw_body(request.values.get("body", ""), False) - if parent_post.id not in ADMIGGER_THREADS: + if not posting_to_submission or post_target.id not in ADMIGGER_THREADS: if v.longpost and (len(body) < 280 or ' [](' in body or body.startswith('[](')): abort(403, "You have to type more than 280 characters!") elif v.bird and len(body) > 140: @@ -126,9 +137,9 @@ def comment(v): if not body and not request.files.get('file'): abort(400, "You need to actually write something!") - if v.admin_level < PERMS['POST_COMMENT_MODERATION'] and parent.author.any_block_exists(v): + if not v.admin_level >= PERMS['POST_COMMENT_MODERATION'] and parent_user.any_block_exists(v): abort(403, "You can't reply to users who have blocked you or users that you have blocked.") - + body, _, options, choices = sanitize_poll_options(v, body, False) if request.files.get("file") and not g.is_tor: @@ -139,7 +150,7 @@ def comment(v): file.save(oldname) image = process_image(oldname, v) if image == "": abort(400, "Image upload failed") - if v.admin_level >= PERMS['SITE_SETTINGS_SIDEBARS_BANNERS_BADGES'] and level == 1: + if posting_to_submission and v.admin_level >= PERMS['SITE_SETTINGS_SIDEBARS_BANNERS_BADGES']: def process_sidebar_or_banner(type, resize=0): li = sorted(os.listdir(f'files/assets/images/{SITE_NAME}/{type}'), key=lambda e: int(e.split('.webp')[0]))[-1] @@ -148,12 +159,12 @@ def comment(v): copyfile(oldname, filename) process_image(filename, v, resize=resize) - if parent_post.id == SIDEBAR_THREAD: + if post_target.id == SIDEBAR_THREAD: process_sidebar_or_banner('sidebar', 400) - elif parent_post.id == BANNER_THREAD: + elif post_target.id == BANNER_THREAD: banner_width = 1200 if not SITE_NAME == 'PCM' else 0 process_sidebar_or_banner('banners', banner_width) - elif parent_post.id == BADGE_THREAD: + elif post_target.id == BADGE_THREAD: try: badge_def = loads(body) name = badge_def["name"] @@ -180,48 +191,51 @@ def comment(v): 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: + if v.admin_level >= PERMS['SITE_SETTINGS_SNAPPY_QUOTES'] and posting_to_submission and post_target.id == SNAPPY_THREAD and level == 1: with open(f"snappy_{SITE_NAME}.txt", "a", encoding="utf-8") as f: f.write('\n{[para]}\n' + body) body_for_sanitize = body - if v.owoify: - body_for_sanitize = owoify(body_for_sanitize) - if v.marsify: - body_for_sanitize = marsify(body_for_sanitize) + if v.owoify: body_for_sanitize = owoify(body_for_sanitize) + if v.marsify: body_for_sanitize = marsify(body_for_sanitize) - torture = (v.agendaposter and not v.marseyawarded and parent_post.sub != 'chudrama' and parent_post.id not in ADMIGGER_THREADS) + torture = (v.agendaposter and not v.marseyawarded and post_target.sub != 'chudrama' and post_target.id not in ADMIGGER_THREADS) body_html = sanitize(body_for_sanitize, limit_pings=5, count_marseys=not v.marsify, torture=torture) - if parent_post.id not in ADMIGGER_THREADS and '!wordle' not in body.lower() and AGENDAPOSTER_PHRASE not in body.lower(): + if post_target.id not in ADMIGGER_THREADS and '!wordle' not in body.lower() and AGENDAPOSTER_PHRASE not in body.lower(): existing = g.db.query(Comment.id).filter( Comment.author_id == v.id, Comment.deleted_utc == 0, Comment.parent_comment_id == parent_comment_id, - Comment.parent_submission == parent_post.id, + Comment.parent_submission == post_target.id if posting_to_submission else None, + Comment.wall_user_id == post_target.id if not posting_to_submission else None, Comment.body_html == body_html ).first() if existing: abort(409, f"You already made that comment: /comment/{existing.id}") + execute_antispam_comment_check(body, v) + execute_antispam_duplicate_comment_check(v, body_html) + + if v.marseyawarded and posting_to_submission and post_target.id not in ADMIGGER_THREADS and marseyaward_body_regex.search(body_html): + abort(403, "You can only type marseys!") + + if len(body_html) > COMMENT_BODY_HTML_LENGTH_LIMIT: abort(400) + is_bot = (v.client is not None and v.id not in PRIVILEGED_USER_BOTS or (SITE == 'pcmemes.net' and v.id == SNAPPY_ID)) - execute_antispam_comment_check(body, v) - execute_antispam_duplicate_comment_check(v, body_html) - - if len(body_html) > COMMENT_BODY_HTML_LENGTH_LIMIT: abort(400) - c = Comment(author_id=v.id, - parent_submission=parent_post.id, + parent_submission=post_target.id if posting_to_submission else None, + wall_user_id=post_target.id if not posting_to_submission else None, parent_comment_id=parent_comment_id, level=level, - over_18=parent_post.over_18, + over_18=post_target.over_18 if posting_to_submission else False, is_bot=is_bot, app_id=v.client.application.id if v.client else None, body_html=body_html, body=body, - ghost=parent_post.ghost + ghost=post_target.ghost if posting_to_submission else False, ) c.upvotes = 1 @@ -237,10 +251,9 @@ def comment(v): process_poll_options(c, CommentOption, options, 0, "Poll", g.db) process_poll_options(c, CommentOption, choices, 1, "Poll", g.db) - if SITE == 'pcmemes.net' and c.body.lower().startswith("based"): - execute_basedbot(c, level, body, parent_post, v) + execute_basedbot(c, level, body, post_target, v) - if parent_post.id not in ADMIGGER_THREADS and v.agendaposter and not v.marseyawarded and AGENDAPOSTER_PHRASE not in c.body.lower() and parent_post.sub != 'chudrama': + if post_target.id not in ADMIGGER_THREADS and v.agendaposter and not v.marseyawarded and AGENDAPOSTER_PHRASE not in c.body.lower() and post_target.sub != 'chudrama': c.is_banned = True c.ban_reason = "AutoJanny" g.db.add(c) @@ -249,7 +262,8 @@ def comment(v): body_jannied_html = AGENDAPOSTER_MSG_HTML.format(id=v.id, username=v.username, type='comment', AGENDAPOSTER_PHRASE=AGENDAPOSTER_PHRASE) c_jannied = Comment(author_id=AUTOJANNY_ID, - parent_submission=parent_post.id, + parent_submission=post_target.id if posting_to_submission else None, + wall_user_id=post_target.id if not posting_to_submission else None, distinguish_level=6, parent_comment_id=c.id, level=level+1, @@ -266,46 +280,41 @@ def comment(v): n = Notification(comment_id=c_jannied.id, user_id=v.id) g.db.add(n) - if SITE_NAME == 'rDrama': - execute_longpostbot(c, level, body, body_html, parent_post.id, v) - execute_zozbot(c, level, parent_post.id, v) + execute_longpostbot(c, level, body, body_html, post_target, v) + execute_zozbot(c, level, post_target, v) if not v.shadowbanned: notify_users = NOTIFY_USERS(body, v) - if c.level == 1: - subscribers = g.db.query(Subscription.user_id).filter(Subscription.submission_id == parent_post.id, Subscription.user_id != v.id).all() + if c.level == 1 and posting_to_submission: + subscribers = g.db.query(Subscription.user_id).filter(Subscription.submission_id == post_target.id, Subscription.user_id != v.id).all() for x in subscribers: notify_users.add(x[0]) - if parent.author.id != v.id: - notify_users.add(parent.author.id) + if parent_user.id != v.id: + notify_users.add(parent_user.id) for x in notify_users-bots: n = Notification(comment_id=c.id, user_id=x) g.db.add(n) - if VAPID_PUBLIC_KEY != DEFAULT_CONFIG_VALUE and parent.author.id != v.id and not v.shadowbanned: + if VAPID_PUBLIC_KEY != DEFAULT_CONFIG_VALUE and parent_user.id != v.id and not v.shadowbanned: title = f'New reply by @{c.author_name}' + if not posting_to_submission: title = f"New comment on your wall by @{c.author_name}" - if len(c.body) > 500: notifbody = c.body[:500] + '...' + if len(c.body) > PUSH_NOTIF_LIMIT: notifbody = c.body[:PUSH_NOTIF_LIMIT] + '...' else: notifbody = c.body url = f'{SITE_FULL}/comment/{c.id}?context=8&read=true#context' - push_notif(parent.author.id, title, notifbody, url) - - + push_notif(parent_user.id, title, notifbody, url) vote = CommentVote(user_id=v.id, comment_id=c.id, vote_type=1, ) - g.db.add(vote) - - cache.delete_memoized(comment_idlist) v.comment_count = g.db.query(Comment).filter( @@ -316,20 +325,9 @@ def comment(v): g.db.add(v) c.voted = 1 - - if v.marseyawarded and parent_post.id not in ADMIGGER_THREADS and marseyaward_body_regex.search(body_html): - abort(403, "You can only type marseys!") check_for_treasure(body, c) - - if FEATURES['WORDLE'] and "!wordle" in body: - answer = random.choice(WORDLE_LIST) - c.wordle_result = f'_active_{answer}' - - if not c.wordle_result and not rts: - parent_post.comment_count += 1 - g.db.add(parent_post) - + execute_wordle(post_target or parent_user, c, body, rts) check_slots_command(v, v, c) if c.level > 5: @@ -344,216 +342,6 @@ def comment(v): if v.client: return c.json(db=g.db) return {"comment": render_template("comments.html", v=v, comments=[c])} - -@app.post("/wall_comment") -@limiter.limit("1/second;20/minute;200/hour;1000/day") -@auth_required -@ratelimit_user("1/second;20/minute;200/hour;1000/day") -def wall_comment(v): - if v.is_suspended: abort(403, "You can't perform this action while banned.") - - parent_fullname = request.values.get("parent_fullname").strip() - if len(parent_fullname) < 3: abort(400) - id = parent_fullname[2:] - parent_comment_id = None - - if parent_fullname.startswith("u_"): - parent = get_account(id, v=v) - parent_user = parent - parent_author = parent - elif parent_fullname.startswith("c_"): - parent = get_comment(id, v=v) - if parent.deleted_utc != 0: abort(404) - parent_user = parent.wall_user - parent_comment_id = parent.id - parent_author = parent.author - else: abort(400) - - level = 1 if isinstance(parent, User) else parent.level + 1 - - # if not User.can_see(v, parent): abort(404) - - if level > COMMENT_MAX_DEPTH: abort(400, f"Max comment level is {COMMENT_MAX_DEPTH}") - - body = sanitize_raw_body(request.values.get("body", ""), False) - - if v.longpost and (len(body) < 280 or ' [](' in body or body.startswith('[](')): - abort(403, "You have to type more than 280 characters!") - elif v.bird and len(body) > 140: - abort(403, "You have to type less than 140 characters!") - - if not body and not request.files.get('file'): - abort(400, "You need to actually write something!") - - if v.admin_level < PERMS['POST_COMMENT_MODERATION'] and parent_author.any_block_exists(v): - abort(403, "You can't reply to users who have blocked you or users that you have blocked.") - - body, _, options, choices = sanitize_poll_options(v, body, False) - - if request.files.get("file") and not g.is_tor: - files = request.files.getlist('file')[:4] - for file in files: - if file.content_type.startswith('image/'): - oldname = f'/images/{time.time()}'.replace('.','') + '.webp' - file.save(oldname) - image = process_image(oldname, v) - if image == "": abort(400, "Image upload failed") - body += f"\n\n![]({image})" - elif file.content_type.startswith('video/'): - body += f"\n\n{SITE_FULL}{process_video(file, v)}" - elif file.content_type.startswith('audio/'): - body += f"\n\n{SITE_FULL}{process_audio(file, v)}" - else: - abort(415) - - body = body.strip()[:COMMENT_BODY_LENGTH_LIMIT] - - body_for_sanitize = body - if v.owoify: - body_for_sanitize = owoify(body_for_sanitize) - if v.marsify: - body_for_sanitize = marsify(body_for_sanitize) - - torture = (v.agendaposter and not v.marseyawarded) - body_html = sanitize(body_for_sanitize, limit_pings=5, count_marseys=not v.marsify, torture=torture) - - if '!wordle' not in body.lower() and AGENDAPOSTER_PHRASE not in body.lower(): - existing = g.db.query(Comment.id).filter( - Comment.author_id == v.id, - Comment.deleted_utc == 0, - Comment.parent_comment_id == parent_comment_id, - Comment.parent_submission == None, - Comment.wall_user_id == parent_user.id, - Comment.body_html == body_html - ).first() - if existing: abort(409, f"You already made that comment: /comment/{existing.id}") - - is_bot = (v.client is not None - and v.id not in PRIVILEGED_USER_BOTS - or (SITE == 'pcmemes.net' and v.id == SNAPPY_ID)) - - execute_antispam_comment_check(body, v) - execute_antispam_duplicate_comment_check(v, body_html) - - if len(body_html) > COMMENT_BODY_HTML_LENGTH_LIMIT: abort(400) - - c = Comment(author_id=v.id, - wall_user_id=parent_user.id, - parent_comment_id=parent_comment_id, - level=level, - is_bot=is_bot, - app_id=v.client.application.id if v.client else None, - body_html=body_html, - body=body, - ) - - c.upvotes = 1 - g.db.add(c) - g.db.flush() - - execute_blackjack(v, c, c.body, "comment") - execute_under_siege(v, c, c.body, "comment") - - if c.level == 1: c.top_comment_id = c.id - else: c.top_comment_id = parent.top_comment_id - - process_poll_options(c, CommentOption, options, 0, "Poll", g.db) - process_poll_options(c, CommentOption, choices, 1, "Poll", g.db) - - if v.agendaposter and not v.marseyawarded and AGENDAPOSTER_PHRASE not in c.body.lower(): - c.is_banned = True - c.ban_reason = "AutoJanny" - g.db.add(c) - - body = AGENDAPOSTER_MSG.format(username=v.username, type='comment', AGENDAPOSTER_PHRASE=AGENDAPOSTER_PHRASE) - body_jannied_html = AGENDAPOSTER_MSG_HTML.format(id=v.id, username=v.username, type='comment', AGENDAPOSTER_PHRASE=AGENDAPOSTER_PHRASE) - - c_jannied = Comment(author_id=AUTOJANNY_ID, - parent_submission=None, - wall_user_id=parent_user.id, - distinguish_level=6, - parent_comment_id=c.id, - level=level+1, - is_bot=True, - body=body, - body_html=body_jannied_html, - top_comment_id=c.top_comment_id, - ) - - g.db.add(c_jannied) - g.db.flush() - - n = Notification(comment_id=c_jannied.id, user_id=v.id) - g.db.add(n) - - if not v.shadowbanned: - notify_users = NOTIFY_USERS(body, v) - - if parent_author.id != v.id: - notify_users.add(parent_author.id) - - for x in notify_users-bots: - n = Notification(comment_id=c.id, user_id=x) - g.db.add(n) - - if VAPID_PUBLIC_KEY != DEFAULT_CONFIG_VALUE and parent_author.id != v.id and not v.shadowbanned: - if parent_author.id == c.wall_user_id: - title = f"New comment on your profile wall by @{c.author_name}" - else: - title = f"New reply by @{c.author_name}" - - if len(c.body) > 500: notifbody = c.body[:500] + '...' - else: notifbody = c.body - - url = f'{SITE_FULL}/@{c.wall_user.username}/wall/comment/{c.id}?context=8&read=true#context' - - push_notif(parent_author.id, title, notifbody, url) - - - - vote = CommentVote(user_id=v.id, - comment_id=c.id, - vote_type=1, - ) - - g.db.add(vote) - - - v.comment_count = g.db.query(Comment).filter( - Comment.author_id == v.id, - or_(Comment.parent_submission != None, Comment.wall_user_id != None), - Comment.deleted_utc == 0 - ).count() - g.db.add(v) - - c.voted = 1 - - if v.marseyawarded and marseyaward_body_regex.search(body_html): - abort(403, "You can only type marseys!") - - check_for_treasure(body, c) - - if FEATURES['WORDLE'] and "!wordle" in body: - answer = random.choice(WORDLE_LIST) - c.wordle_result = f'_active_{answer}' - - check_slots_command(v, v, c) - - if c.level > 5: - n = g.db.query(Notification).filter_by( - comment_id=c.parent_comment.parent_comment.parent_comment.parent_comment_id, - user_id=c.parent_comment.author_id, - ).one_or_none() - if n: g.db.delete(n) - - g.db.flush() - - cache.delete_memoized(comment_idlist) - - if v.client: return c.json(db=g.db) - return {"comment": render_template("comments.html", v=v, comments=[c])} - - @app.post("/edit_comment/") @limiter.limit("1/second;10/minute;100/hour;200/day") @is_not_permabanned diff --git a/files/routes/users.py b/files/routes/users.py index 777699d2e..f85aa47fc 100644 --- a/files/routes/users.py +++ b/files/routes/users.py @@ -538,7 +538,7 @@ def messagereply(v:User): execute_blackjack(v, c, c.body_html, 'message') execute_under_siege(v, c, c.body_html, 'message') - if user_id and user_id not in (v.id, 2, bots): + if user_id and user_id not in (v.id, MODMAIL_ID, bots): notif = g.db.query(Notification).filter_by(comment_id=c.id, user_id=user_id).one_or_none() if not notif: notif = Notification(comment_id=c.id, user_id=user_id) @@ -878,7 +878,7 @@ def u_username(v:Optional[User]=None, username:str): if (v and v.client) or request.path.endswith(".json"): return {"data": [x.json(g.db) for x in listing]} - return render_template("userpage/userpage.html", + return render_template("userpage/submissions.html", unban=u.unban_string, u=u, v=v, @@ -892,7 +892,7 @@ def u_username(v:Optional[User]=None, username:str): if (v and v.client) or request.path.endswith(".json"): return {"data": [x.json(g.db) for x in listing]} - return render_template("userpage/userpage.html", + return render_template("userpage/submissions.html", u=u, v=v, listing=listing, @@ -1126,7 +1126,7 @@ def saved_posts(v:User, username): try: page = max(1, int(request.values.get("page", 1))) except: abort(400, "Invalid page input!") - return get_saves_and_subscribes(v, "userpage/userpage.html", SaveRelationship, page, False) + return get_saves_and_subscribes(v, "userpage/submissions.html", SaveRelationship, page, False) @app.get("/@/saved/comments") @auth_required @@ -1142,7 +1142,7 @@ def subscribed_posts(v:User, username): try: page = max(1, int(request.values.get("page", 1))) except: abort(400, "Invalid page input!") - return get_saves_and_subscribes(v, "userpage/userpage.html", Subscription, page, False) + return get_saves_and_subscribes(v, "userpage/submissions.html", Subscription, page, False) @app.post("/fp/") @auth_required diff --git a/files/templates/comments.html b/files/templates/comments.html index aca8341db..53c6fdcdd 100644 --- a/files/templates/comments.html +++ b/files/templates/comments.html @@ -275,6 +275,7 @@ {% if c.parent_submission or c.wall_user_id %} {% if v and v.id==c.author_id %} + {% endif %}
- - -
    @@ -316,7 +314,7 @@ {% if v and not c.deleted_utc %} - + {% endif %}
  • @@ -365,15 +363,6 @@
- - - - - - - - -
  • {% if v and (request.path.startswith('/@') and not wall) and v.admin_level < PERMS['VIEW_VOTE_BUTTONS_ON_USER_PAGE'] %} @@ -414,7 +403,7 @@ {% if v %} {% if not c.deleted_utc %} - + {% endif %} @@ -517,39 +506,7 @@ {% if v and v.id != c.author_id and c.body %}
    {{c.body.strip()}}
    {% endif %} - - -
    - -
    + {{macros.comment_reply_box(c.fullname, "reply-to-" + c.fullname, "d-none", "collapsed child", 'reply-to-' + c.fullname, true, '/comments/')}} {% if request.path.startswith('/transfers') %} @@ -578,9 +535,10 @@ {% endif %} - + -
    + {# TODO: swap to comment_reply_box macro #} +
    {% endif %} - {% if p.embed_url and "http" not in p.embed_url and "<" not in p.embed_url %} - - - -
    -
-
    -
  • {{p.comment_count}} - {% if v and v.admin_level >= PERMS['POST_COMMENT_MODERATION_TOOLS_VISIBLE'] %}
{% if not p.deleted_utc %} - {% if v %} -
- - - - - - -
- -
- -   - -   - -
- - -
- -
- {% else %} -
- -
- -
-
-
Jump in the discussion.
-

No email address required.

- -
-
- {% endif %} + {{macros.comment_reply_box(p.fullname, 'comment-reply-' + p.fullname, '', 'mb-3', '', true, '/comments/')}} {% endif %} {% if comment_info %} diff --git a/files/templates/userpage/banner.html b/files/templates/userpage/banner.html new file mode 100644 index 000000000..14cbc9f6e --- /dev/null +++ b/files/templates/userpage/banner.html @@ -0,0 +1,505 @@ +{% import 'userpage/admintools.html' as userpage_admintools with context %} +{% set hats_total = u.hats_owned_proportion_display[1] if u else 0 %} +{% set hats_owned_percent = u.hats_owned_proportion_display[0] if u else '' %} +{% block desktopUserBanner %} +
+
+
+
+
+
+
+ +
+ {{userpage_admintools.userBanBlock('desktop')}} +
+

{{u.user_name}}

+ + {% if u.username != u.original_username %} + + + + {% endif %} + + {% if FEATURES['PATRON_ICONS'] and u.patron %} + {{u.patron_tooltip}} + {% endif %} + + {% if FEATURES['HOUSES'] and u.house %} + House {{u.house}} + {% endif %} + + {% if u.verified %} + + {% endif %} + + {% if u.admin_level >= PERMS['ADMIN_MOP_VISIBLE'] %} + + + + {% endif %} + {% if v and v.id != u.id and v.has_follower(u) %} + Follows you + {% endif %} +
+ + {% if FEATURES['PRONOUNS'] %} +

{{u.pronouns}}

+ {% endif %} + + {% if u.customtitle %} +

{{u.customtitle | safe}}

+ {% endif %} + + {% if v and (v.id == u.id or v.admin_level >= PERMS['USER_VOTERS_VISIBLE']) -%} + + {%- endif %} + +
+ {{u.coins}} + coins + + {% if FEATURES['MARSEYBUX'] %} + {{u.marseybux}} + marseybux + {% endif %} + + {% if PERMS['USER_FOLLOWS_VISIBLE'] == 0 or (v and v.admin_level >= PERMS['USER_FOLLOWS_VISIBLE']) -%} + {{u.stored_subscriber_count}} follower{{'s' if u.stored_subscriber_count != 1 else ''}} + + follows {{u.follow_count}} user{{'s' if u.follow_count != 1 else ''}} + {%- endif %} + + joined {{u.created_date}} + + {% if v and v.admin_level >= PERMS['VIEW_LAST_ACTIVE'] -%} + last active {{u.last_active_date}} + {%- endif %} +
+ {% if u.basedcount %}

Based Count: {{u.basedcount}}

{% endif %} + + {% if FEATURES['USERS_PROFILE_BODYTEXT'] -%} + {% if u.bio_html %} +
{{u.bio_html | safe}}
+ {% else %} +

No bio...

+ {% endif %} + + {% if u.friends_html %} +

Friends:

+
{{u.friends_html | safe}}
+ {% endif %} + + {% if u.enemies_html %} +

Enemies:

+
{{u.enemies_html | safe}}
+ {% endif %} + {%- endif %} + + {% if u.received_awards and FEATURES['AWARDS'] %} +
+

Awards received

+ {% for a in u.received_awards %} + + + x{{a['count']}} + + {% endfor %} +
+ {% endif %} + + {% if u.moderated_subs %} +
+

Moderator of

+ {% for a in u.moderated_subs %} + + /h/{{a}} + + {% endfor %} +
+ {% endif %} + +
+
+ {% if v and v.id != u.id %} +
+
+ + + + + + {% if FEATURES['USERS_SUICIDE'] -%} + + {%- endif %} + + {% if FEATURES['MARSEYBUX'] -%} + + {%- endif %} + + +
+
+
+ + + +   + +
+ +
+ +
+ + +
{{u.username}} will receive 0 coins
+ +
+ +
+ + +
{{u.username}} will receive 0 marseybux
+ +
+ + {{userpage_admintools.userAdminTools('desktop')}} + {% endif %} + +
+ {% if v and v.id == u.id %} + Edit Profile + +
+ + + +
+ + {% if v.profile_background -%} +
+ +
+ {%- endif %} + {% endif %} + + {% if FEATURES['USERS_PROFILE_SONG'] and u.song and v and (v.id == u.id or v.mute and not u.unmutable) %} + + {% endif %} +
+ +
+

User ID: {{u.id}}

+

Coins spent: {{u.coins_spent}}

+

True score: {{u.truescore}}

+

Winnings: {{u.winnings}}

+

= hats_total %}class="profile-owned-all-hats"{% endif %}>{{u.num_of_owned_hats}} / {{hats_total}} hats owned ({{hats_owned_percent}})

+ {% if u.is_private %} +

User has private mode enabled

+ {% endif %} + {% if v and (v.admin_level >= PERMS['VIEW_ALTS'] or v.alt) %} + {% if v.admin_level >= PERMS['USER_LINK'] %} + Alts: + {% else %} + Alts: + {% endif %} +
    + {% for account in u.alts_unique if not account._alt_deleted and (v.can_see_shadowbanned or not account.shadowbanned) %} +
  • @{{account.username}}{% if account._is_manual %} [m]{% endif %}
  • + {% endfor %} +
+ {% endif %} +
+
+
+ + {% if FEATURES['BADGES'] -%} +
+ {% for b in u.badges %} + {% if b.url %} + + {{b.name}} + + {% else %} + {{b.name}} + {% endif %} + {% endfor %} +
+ {%- endif %} +
+
+
+
+
+
+
+{% endblock %} + +{% block mobileUserBanner %} +
+
+
+ + @{{u.username}}'s banner + +
+
+
+
+ +
+ {{userpage_admintools.userBanBlock('mobile')}} +
{{u.user_name}}
+ + {% if u.username != u.original_username %} + + + + {% endif %} + + {% if FEATURES['PATRON_ICONS'] and u.patron %} + {{u.patron_tooltip}} + {% endif %} + + {% if FEATURES['HOUSES'] and u.house %} + House {{u.house}} + {% endif %} + + {% if u.verified %} +   + {% endif %} + + {% if u.admin_level >= PERMS['ADMIN_MOP_VISIBLE'] %} + + + + {% endif %} + {% if v and v.id != u.id and v.has_follower(u) %} + Follows you + {% endif %} + + {% if FEATURES['PRONOUNS'] %} +

{{u.pronouns}}

+ {% endif %} + + {% if u.customtitle %} +

{{u.customtitle | safe}}

+ {% endif %} + + {% if v and (v.id == u.id or v.admin_level >= PERMS['USER_VOTERS_VISIBLE']) -%} + + {%- endif %} + +
+ {{u.coins}} + coins + + {% if FEATURES['MARSEYBUX'] %} + {{u.marseybux}} + marseybux + {% endif %} + + {% if PERMS['USER_FOLLOWS_VISIBLE'] == 0 or (v and v.admin_level >= PERMS['USER_FOLLOWS_VISIBLE']) -%} + {{u.stored_subscriber_count}} follower{{'s' if u.stored_subscriber_count != 1 else ''}} + + follows {{u.follow_count}} user{{'s' if u.follow_count != 1 else ''}} + {%- endif %} + + {% if u.basedcount %} +
Based count: {{u.basedcount}} + {% endif %} + +
joined {{u.created_date}} + + {% if v and v.admin_level >= PERMS['VIEW_LAST_ACTIVE'] -%} +
last active {{u.last_active_date}} + {%- endif %} +
+ + {% if FEATURES['USERS_PROFILE_BODYTEXT'] -%} + {% if u.bio_html %} +
{{u.bio_html | safe}}
+ {% endif %} + + {% if u.friends_html %} +

Friends:

+
{{u.friends_html | safe}}
+ {% endif %} + + {% if u.enemies_html %} +

Enemies:

+
{{u.enemies_html | safe}}
+ {% endif %} + {%- endif %} + + {% if u.received_awards and FEATURES['AWARDS'] %} +
+

Awards received

+ {% for a in u.received_awards %} + + + x{{a['count']}} + + {% endfor %} +
+ {% endif %} + + {% if u.moderated_subs %} +
+

Moderator of

+ {% for a in u.moderated_subs %} + + /h/{{a}} + + {% endfor %} +
+ {% endif %} + +
+ {% for b in u.badges %} + {% if b.url %} + + {{b.name}} + + {% else %} + {{b.name}} + {% endif %} + {% endfor %} +
+ +
+ {% if v and v.id == u.id %} + Edit Profile + {% endif %} + + {% if FEATURES['USERS_PROFILE_SONG'] and u.song and v and (v.id == u.id or v.mute and not u.unmutable) %} + + {% endif %} + + {% if v and v.id == u.id and (v.profile_background or v.theme == 'transparent') %} +
+
+ + + +
+ + {% if v.profile_background -%} +
+ +
+ {%- endif %} +
+ {% endif %} + + {% if v and v.id != u.id %} + + + + + + {% if FEATURES['USERS_SUICIDE'] -%} + + {%- endif %} + + {% if FEATURES['MARSEYBUX'] -%} + + {%- endif %} + + + {% endif %} +
+ + {% if v and v.id != u.id %} +
+ + + +   + +
+ +
+ +
+ + +
{{u.username}} will receive 0 coins
+ +
+ +
+ + +
{{u.username}} will receive 0 marseybux
+ +
+ {{userpage_admintools.userAdminTools('mobile')}} + {% endif %} + +
+

User ID: {{u.id}}

+

Coins spent: {{u.coins_spent}}

+

True score: {{u.truescore}}

+

Winnings: {{u.winnings}}

+

= hats_total %}class="profile-owned-all-hats"{% endif %}>{{u.num_of_owned_hats}} / {{hats_total}} hats owned ({{hats_owned_percent}})

+ {% if u.is_private %} +

User has private mode enabled

+ {% endif %} + {% if v and (v.admin_level >= PERMS['VIEW_ALTS'] or v.alt) %} + {% if v.admin_level >= PERMS['USER_LINK'] %} + Alts: + {% else %} + Alts: + {% endif %} +
    + {% for account in u.alts_unique if not account._alt_deleted and (v.can_see_shadowbanned or not account.shadowbanned) %} +
  • @{{account.username}}{% if account._is_manual %} [m]{% endif %}
  • + {% endfor %} +
+ {% endif %} +
+
+
+
+
+{% endblock %} diff --git a/files/templates/userpage/comments.html b/files/templates/userpage/comments.html index 71e8f1b17..91f9fcb8d 100644 --- a/files/templates/userpage/comments.html +++ b/files/templates/userpage/comments.html @@ -1,86 +1,7 @@ {% extends "userpage/userpage.html" %} - -{% block content %} - -
+{% block userpage_content %} + - -{% if "/saved/" not in request.path and "/subscribed/" not in request.path %} -
- -
- - - -
-
-{% endif %} - -
- -
- {% if listing %}
{% with comments=listing %} @@ -107,20 +28,4 @@ {% endif %}
- -{% if u.song %} - {% if v and v.id == u.id %} -
{{v.username}}
- {% else %} -
{{u.username}}
- {% endif %} -{% endif %} - -{% if v %} -
{% if v.patron or u.patron %}0{% else %}0.03{% endif %}
-
{{u.username}}
- -{% endif %} - - {% endblock %} diff --git a/files/templates/userpage/header.html b/files/templates/userpage/header.html new file mode 100644 index 000000000..4f5724f94 --- /dev/null +++ b/files/templates/userpage/header.html @@ -0,0 +1,74 @@ +{% set path = request.path.replace("/@" + u.username, '') %} + +{% if "/saved/" not in request.path and "/subscribed/" not in request.path and not path == '' %} +
+ +
+ + + +
+
+{% endif %} diff --git a/files/templates/userpage/private.html b/files/templates/userpage/private.html index c74f8afd6..7bdb3b47d 100644 --- a/files/templates/userpage/private.html +++ b/files/templates/userpage/private.html @@ -1,8 +1,6 @@ {% extends "userpage/userpage.html" %} - - -{% block content %} -
+{% block userpage_content %} +
@@ -14,29 +12,4 @@
- -{% if u.song %} - {% if v and v.id == u.id %} -
{{v.username}}
- {% else %} -
{{u.username}}
- {% endif %} -{% endif %} - -{% endblock %} - -{% block pagenav %} -{% if u.song %} -
{{u.id}}
-{% endif %} - -{% if v %} -
{% if v.patron or u.patron %}0{% else %}0.03{% endif %}
-
{{u.username}}
- {%- include "modals/emoji.html" -%} - -{% endif %} - - - {% endblock %} diff --git a/files/templates/userpage/submissions.html b/files/templates/userpage/submissions.html new file mode 100644 index 000000000..7ee4eeeec --- /dev/null +++ b/files/templates/userpage/submissions.html @@ -0,0 +1,10 @@ +{%- extends 'userpage/userpage.html' -%} +{% block userpage_content %} +
+
+
+ {% include "submission_listing.html" %} +
+
+
+{% endblock %} diff --git a/files/templates/userpage/userpage.html b/files/templates/userpage/userpage.html index 915a69d66..3ffc56837 100644 --- a/files/templates/userpage/userpage.html +++ b/files/templates/userpage/userpage.html @@ -14,606 +14,10 @@ {% endif %} {% endblock %} - -{% import 'userpage/admintools.html' as userpage_admintools with context %} -{% set hats_total = u.hats_owned_proportion_display[1] if u else 0 %} -{% set hats_owned_percent = u.hats_owned_proportion_display[0] if u else '' %} - -{% block desktopUserBanner %} - -
-
-
-
-
-
-
- -
- {{userpage_admintools.userBanBlock('desktop')}} -
-

{{u.user_name}}

- - {% if u.username != u.original_username %} - - - - {% endif %} - - {% if FEATURES['PATRON_ICONS'] and u.patron %} - {{u.patron_tooltip}} - {% endif %} - - {% if FEATURES['HOUSES'] and u.house %} - House {{u.house}} - {% endif %} - - {% if u.verified %} - - {% endif %} - - {% if u.admin_level >= PERMS['ADMIN_MOP_VISIBLE'] %} - - - - {% endif %} - {% if v and v.id != u.id and v.has_follower(u) %} - Follows you - {% endif %} -
- - {% if FEATURES['PRONOUNS'] %} -

{{u.pronouns}}

- {% endif %} - - {% if u.customtitle %} -

{{u.customtitle | safe}}

- {% endif %} - - {% if v and (v.id == u.id or v.admin_level >= PERMS['USER_VOTERS_VISIBLE']) -%} - - {%- endif %} - -
- {{u.coins}} - coins - - {% if FEATURES['MARSEYBUX'] %} - {{u.marseybux}} - marseybux - {% endif %} - - {% if PERMS['USER_FOLLOWS_VISIBLE'] == 0 or (v and v.admin_level >= PERMS['USER_FOLLOWS_VISIBLE']) -%} - {{u.stored_subscriber_count}} follower{{'s' if u.stored_subscriber_count != 1 else ''}} - - follows {{u.follow_count}} user{{'s' if u.follow_count != 1 else ''}} - {%- endif %} - - joined {{u.created_date}} - - {% if v and v.admin_level >= PERMS['VIEW_LAST_ACTIVE'] -%} - last active {{u.last_active_date}} - {%- endif %} -
- {% if u.basedcount %}

Based Count: {{u.basedcount}}

{% endif %} - - {% if FEATURES['USERS_PROFILE_BODYTEXT'] -%} - {% if u.bio_html %} -
{{u.bio_html | safe}}
- {% else %} -

No bio...

- {% endif %} - - {% if u.friends_html %} -

Friends:

-
{{u.friends_html | safe}}
- {% endif %} - - {% if u.enemies_html %} -

Enemies:

-
{{u.enemies_html | safe}}
- {% endif %} - {%- endif %} - - {% if u.received_awards and FEATURES['AWARDS'] %} -
-

Awards received

- {% for a in u.received_awards %} - - - x{{a['count']}} - - {% endfor %} -
- {% endif %} - - {% if u.moderated_subs %} -
-

Moderator of

- {% for a in u.moderated_subs %} - - /h/{{a}} - - {% endfor %} -
- {% endif %} - -
-
- {% if v and v.id != u.id %} -
-
- - - - - - {% if FEATURES['USERS_SUICIDE'] -%} - - {%- endif %} - - {% if FEATURES['MARSEYBUX'] -%} - - {%- endif %} - - -
-
-
- - - -   - -
- -
- -
- - -
{{u.username}} will receive 0 coins
- -
- -
- - -
{{u.username}} will receive 0 marseybux
- -
- - {{userpage_admintools.userAdminTools('desktop')}} - {% endif %} - -
- {% if v and v.id == u.id %} - Edit Profile - -
- - - -
- - {% if v.profile_background -%} -
- -
- {%- endif %} - {% endif %} - - {% if FEATURES['USERS_PROFILE_SONG'] and u.song and v and (v.id == u.id or v.mute and not u.unmutable) %} - - {% endif %} -
- -
-

User ID: {{u.id}}

-

Coins spent: {{u.coins_spent}}

-

True score: {{u.truescore}}

-

Winnings: {{u.winnings}}

-

= hats_total %}class="profile-owned-all-hats"{% endif %}>{{u.num_of_owned_hats}} / {{hats_total}} hats owned ({{hats_owned_percent}})

- {% if u.is_private %} -

User has private mode enabled

- {% endif %} - {% if v and (v.admin_level >= PERMS['VIEW_ALTS'] or v.alt) %} - {% if v.admin_level >= PERMS['USER_LINK'] %} - Alts: - {% else %} - Alts: - {% endif %} -
    - {% for account in u.alts_unique if not account._alt_deleted and (v.can_see_shadowbanned or not account.shadowbanned) %} -
  • @{{account.username}}{% if account._is_manual %} [m]{% endif %}
  • - {% endfor %} -
- {% endif %} -
-
-
- - {% if FEATURES['BADGES'] -%} -
- {% for b in u.badges %} - {% if b.url %} - - {{b.name}} - - {% else %} - {{b.name}} - {% endif %} - {% endfor %} -
- {%- endif %} -
-
-
-
-
-
-
-{% endblock %} - -{% block mobileUserBanner %} -
-
-
- - @{{u.username}}'s banner - -
-
-
-
- -
- {{userpage_admintools.userBanBlock('mobile')}} -
{{u.user_name}}
- - {% if u.username != u.original_username %} - - - - {% endif %} - - {% if FEATURES['PATRON_ICONS'] and u.patron %} - {{u.patron_tooltip}} - {% endif %} - - {% if FEATURES['HOUSES'] and u.house %} - House {{u.house}} - {% endif %} - - {% if u.verified %} -   - {% endif %} - - {% if u.admin_level >= PERMS['ADMIN_MOP_VISIBLE'] %} - - - - {% endif %} - {% if v and v.id != u.id and v.has_follower(u) %} - Follows you - {% endif %} - - {% if FEATURES['PRONOUNS'] %} -

{{u.pronouns}}

- {% endif %} - - {% if u.customtitle %} -

{{u.customtitle | safe}}

- {% endif %} - - {% if v and (v.id == u.id or v.admin_level >= PERMS['USER_VOTERS_VISIBLE']) -%} - - {%- endif %} - -
- {{u.coins}} - coins - - {% if FEATURES['MARSEYBUX'] %} - {{u.marseybux}} - marseybux - {% endif %} - - {% if PERMS['USER_FOLLOWS_VISIBLE'] == 0 or (v and v.admin_level >= PERMS['USER_FOLLOWS_VISIBLE']) -%} - {{u.stored_subscriber_count}} follower{{'s' if u.stored_subscriber_count != 1 else ''}} - - follows {{u.follow_count}} user{{'s' if u.follow_count != 1 else ''}} - {%- endif %} - - {% if u.basedcount %} -
Based count: {{u.basedcount}} - {% endif %} - -
joined {{u.created_date}} - - {% if v and v.admin_level >= PERMS['VIEW_LAST_ACTIVE'] -%} -
last active {{u.last_active_date}} - {%- endif %} -
- - {% if FEATURES['USERS_PROFILE_BODYTEXT'] -%} - {% if u.bio_html %} -
{{u.bio_html | safe}}
- {% endif %} - - {% if u.friends_html %} -

Friends:

-
{{u.friends_html | safe}}
- {% endif %} - - {% if u.enemies_html %} -

Enemies:

-
{{u.enemies_html | safe}}
- {% endif %} - {%- endif %} - - {% if u.received_awards and FEATURES['AWARDS'] %} -
-

Awards received

- {% for a in u.received_awards %} - - - x{{a['count']}} - - {% endfor %} -
- {% endif %} - - {% if u.moderated_subs %} -
-

Moderator of

- {% for a in u.moderated_subs %} - - /h/{{a}} - - {% endfor %} -
- {% endif %} - -
- {% for b in u.badges %} - {% if b.url %} - - {{b.name}} - - {% else %} - {{b.name}} - {% endif %} - {% endfor %} -
- -
- {% if v and v.id == u.id %} - Edit Profile - {% endif %} - - {% if FEATURES['USERS_PROFILE_SONG'] and u.song and v and (v.id == u.id or v.mute and not u.unmutable) %} - - {% endif %} - - {% if v and v.id == u.id %} -
-
- - - -
- - {% if v.profile_background -%} -
- -
- {%- endif %} -
- {% endif %} - - {% if v and v.id != u.id %} - - - - - - {% if FEATURES['USERS_SUICIDE'] -%} - - {%- endif %} - - {% if FEATURES['MARSEYBUX'] -%} - - {%- endif %} - - - {% endif %} -
- - {% if v and v.id != u.id %} -
- - - -   - -
- -
- -
- - -
{{u.username}} will receive 0 coins
- -
- -
- - -
{{u.username}} will receive 0 marseybux
- -
- {{userpage_admintools.userAdminTools('mobile')}} - {% endif %} - -
-

User ID: {{u.id}}

-

Coins spent: {{u.coins_spent}}

-

True score: {{u.truescore}}

-

Winnings: {{u.winnings}}

-

= hats_total %}class="profile-owned-all-hats"{% endif %}>{{u.num_of_owned_hats}} / {{hats_total}} hats owned ({{hats_owned_percent}})

- {% if u.is_private %} -

User has private mode enabled

- {% endif %} - {% if v and (v.admin_level >= PERMS['VIEW_ALTS'] or v.alt) %} - {% if v.admin_level >= PERMS['USER_LINK'] %} - Alts: - {% else %} - Alts: - {% endif %} -
    - {% for account in u.alts_unique if not account._alt_deleted and (v.can_see_shadowbanned or not account.shadowbanned) %} -
  • @{{account.username}}{% if account._is_manual %} [m]{% endif %}
  • - {% endfor %} -
- {% endif %} -
-
-
-
-
-{% endblock %} - {% block content %} - - - -{% if "/saved/" not in request.path and '/subscribed/' not in request.path %} -
- -
- - - -
-
-{% endif %} - -
- -
- -
- {% include "submission_listing.html" %} -
- -
- -
- +{%- include 'userpage/banner.html' -%} +{%- include 'userpage/header.html' -%} +{% block userpage_content required %}{% endblock %} {% if FEATURES['USERS_PROFILE_SONG'] and u.song %} {% if v and v.id == u.id %}
{{v.username}}
@@ -627,9 +31,7 @@
{{u.username}}
{% endif %} - - {% endblock %} {% block pagenav %} @@ -662,7 +64,5 @@ {% if v and v.id != u.id and not request.path.endswith('/comments') and not request.path.endswith(u.username) %} {% include "modals/emoji.html" %} {% endif %} - {% endblock %} - {% block GIFpicker %}{% endblock %} diff --git a/files/templates/userpage/voted_posts.html b/files/templates/userpage/voted_posts.html index 169a87871..ea46e3d7c 100644 --- a/files/templates/userpage/voted_posts.html +++ b/files/templates/userpage/voted_posts.html @@ -17,11 +17,8 @@ -
-
- {% block listing %}
{% include "submission_listing.html" %} diff --git a/files/templates/userpage/wall.html b/files/templates/userpage/wall.html index 894a16ca6..3295a2a1c 100644 --- a/files/templates/userpage/wall.html +++ b/files/templates/userpage/wall.html @@ -1,118 +1,24 @@ {% extends "userpage/userpage.html" %} - -{% block content %} - -
-
- +{% block userpage_content %} +
+ {{macros.comment_reply_box(u.fullname, 'replying-to-' + u.fullname, '', 'mb-3', '', true, '/comments/')}} +
+
+
+ {% with comments=listing %} + {% include "comments.html" %} + {% endwith %} +
+ {% if not listing %} +
+ + + + +
There's no comments on {% if u.id == v.id %}your{% else %}@{{u.username}}'s{% endif %} wall yet!
+
+ {% endif %} +
- -{% if v %} -
-
- - - - - -
- -
- -   - -   - -
- -
-
- -
-{% else %} -
- -
- -
-
-
Jump in the discussion.
-

No email address required.

- -
-
-{% endif %} - -{% if comment_info %} - -{% endif %} - -
- -
-
- {% with comments=listing %} - {% include "comments.html" %} - {% endwith %} -
- {% if not listing %} -
- - - - -
There's no comments on your wall yet!
-
- {% endif %} -
-
- -{% if u.song %} - {% if v and v.id == u.id %} -
{{v.username}}
- {% else %} -
{{u.username}}
- {% endif %} -{% endif %} - -{% if v %} -
{% if v.patron or u.patron %}0{% else %}0.03{% endif %}
-
{{u.username}}
- -{% endif %} - - - {% endblock %} diff --git a/files/templates/util/macros.html b/files/templates/util/macros.html index 71977d860..7a86f6c70 100644 --- a/files/templates/util/macros.html +++ b/files/templates/util/macros.html @@ -109,3 +109,52 @@ {% endif %} {{p.views}} thread views {% endmacro %} + +{% macro comment_reply_box(target_fullname, html_id, wrapper_css_classes="", subwrapper_css_classes="", hide="", allow_file_upload=true, action="/comments/") %} +
+ {% if v %} +
+
+ + + + +
+ +
+ +   + +   + {% if allow_file_upload %} + + {% endif %} +
+ +
+
+ +
+ {% else %} +
+ +
+ +
+
+
Jump in the discussion.
+

No email address required.

+ +
+
+ {% endif %} +
+{% endmacro %}