forked from MarseyWorld/MarseyWorld
add profile wall
parent
814552cdfe
commit
cb4d941fd0
|
@ -191,7 +191,7 @@ function comment_edit(id){
|
|||
xhr[0].send(xhr[1]);
|
||||
}
|
||||
|
||||
function post_comment(fullname, hide){
|
||||
function post_comment(fullname, wall_user_id, hide){
|
||||
const btn = document.getElementById('save-reply-to-'+fullname)
|
||||
btn.disabled = true
|
||||
btn.classList.add('disabled');
|
||||
|
@ -210,7 +210,9 @@ function post_comment(fullname, hide){
|
|||
catch(e) {}
|
||||
|
||||
const xhr = new XMLHttpRequest();
|
||||
xhr.open("post", "/comment");
|
||||
if (wall_user_id == 'None') url = "/comment"
|
||||
else url = '/wall_comment'
|
||||
xhr.open("post", url);
|
||||
xhr.setRequestHeader('xhr', 'xhr');
|
||||
xhr.onload=function(){
|
||||
let data
|
||||
|
|
|
@ -33,6 +33,7 @@ class Comment(Base):
|
|||
id = Column(Integer, primary_key=True)
|
||||
author_id = Column(Integer, ForeignKey("users.id"))
|
||||
parent_submission = Column(Integer, ForeignKey("submissions.id"))
|
||||
wall_user_id = Column(Integer, ForeignKey("users.id"))
|
||||
created_utc = Column(Integer)
|
||||
edited_utc = Column(Integer, default=0)
|
||||
is_banned = Column(Boolean, default=False)
|
||||
|
@ -74,6 +75,7 @@ class Comment(Base):
|
|||
flags = relationship("CommentFlag", order_by="CommentFlag.created_utc")
|
||||
options = relationship("CommentOption", order_by="CommentOption.id")
|
||||
casino_game = relationship("Casino_Game")
|
||||
wall_user = relationship("User", primaryjoin="User.id==Comment.wall_user_id")
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
if "created_utc" not in kwargs:
|
||||
|
|
|
@ -496,7 +496,7 @@ class User(Base):
|
|||
@property
|
||||
@lazy
|
||||
def fullname(self):
|
||||
return f"t1_{self.id}"
|
||||
return f"u_{self.id}"
|
||||
|
||||
@property
|
||||
@lazy
|
||||
|
|
|
@ -215,7 +215,7 @@ def comment(v):
|
|||
parent_submission=parent_post.id,
|
||||
parent_comment_id=parent_comment_id,
|
||||
level=level,
|
||||
over_18=parent_post.over_18 or request.values.get("over_18")=="true",
|
||||
over_18=parent_post.over_18,
|
||||
is_bot=is_bot,
|
||||
app_id=v.client.application.id if v.client else None,
|
||||
body_html=body_html,
|
||||
|
@ -344,6 +344,241 @@ def comment(v):
|
|||
return {"comment": render_template("comments.html", v=v, comments=[c])}
|
||||
|
||||
|
||||
#- API
|
||||
@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_user
|
||||
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.")
|
||||
|
||||
options = []
|
||||
for i in list(poll_regex.finditer(body))[:POLL_MAX_OPTIONS]:
|
||||
options.append(i.group(1))
|
||||
body = body.replace(i.group(0), "")
|
||||
|
||||
choices = []
|
||||
for i in list(choice_regex.finditer(body))[:POLL_MAX_OPTIONS]:
|
||||
choices.append(i.group(1))
|
||||
body = body.replace(i.group(0), "")
|
||||
|
||||
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")
|
||||
if v.admin_level >= PERMS['SITE_SETTINGS_SIDEBARS_BANNERS_BADGES'] and level == 1:
|
||||
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]
|
||||
num = int(li.split('.webp')[0]) + 1
|
||||
filename = f'files/assets/images/{SITE_NAME}/{type}/{num}.webp'
|
||||
copyfile(oldname, filename)
|
||||
process_image(filename, v, resize=resize)
|
||||
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.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
|
||||
|
||||
for option in options:
|
||||
body_html = filter_emojis_only(option)
|
||||
if len(body_html) > 500: abort(400, "Poll option too long!")
|
||||
option = CommentOption(
|
||||
comment_id=c.id,
|
||||
body_html=body_html,
|
||||
exclusive=0
|
||||
)
|
||||
g.db.add(option)
|
||||
|
||||
for choice in choices:
|
||||
body_html = filter_emojis_only(choice)
|
||||
if len(body_html) > 500: abort(400, "Poll option too long!")
|
||||
choice = CommentOption(
|
||||
comment_id=c.id,
|
||||
body_html=body_html,
|
||||
exclusive=1
|
||||
)
|
||||
g.db.add(choice)
|
||||
|
||||
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:
|
||||
title = f'New comment on your wall by @{c.author_name}'
|
||||
|
||||
if len(c.body) > 500: notifbody = c.body[:500] + '...'
|
||||
else: notifbody = c.body
|
||||
|
||||
url = f'{SITE_FULL}/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,
|
||||
Comment.parent_submission != 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()
|
||||
|
||||
if v.client: return c.json(db=g.db)
|
||||
return {"comment": render_template("comments.html", v=v, comments=[c])}
|
||||
|
||||
|
||||
@app.post("/edit_comment/<cid>")
|
||||
@limiter.limit("1/second;10/minute;100/hour;200/day")
|
||||
|
|
|
@ -714,6 +714,50 @@ def userpagelisting(user:User, site=None, v=None, page:int=1, sort="new", t="all
|
|||
@app.get("/@<username>")
|
||||
@app.get("/@<username>.json")
|
||||
@auth_desired_with_logingate
|
||||
def u_username_wall(username, v=None):
|
||||
u = get_user(username, v=v, include_blocks=True, include_shadowbanned=False)
|
||||
if username != u.username:
|
||||
return redirect(f"/@{u.username}/comments")
|
||||
is_following = v and u.has_follower(v)
|
||||
|
||||
if not u.is_visible_to(v):
|
||||
if g.is_api_or_xhr or request.path.endswith(".json"):
|
||||
abort(403, f"@{u.username}'s userpage is private")
|
||||
return render_template("userpage/private.html", u=u, v=v, is_following=is_following), 403
|
||||
|
||||
if v and hasattr(u, 'is_blocking') and u.is_blocking:
|
||||
if g.is_api_or_xhr or request.path.endswith(".json"):
|
||||
abort(403, f"You are blocking @{u.username}.")
|
||||
return render_template("userpage/blocking.html", u=u, v=v), 403
|
||||
|
||||
try: page = max(int(request.values.get("page", "1")), 1)
|
||||
except: page = 1
|
||||
|
||||
comments, output = get_comments_v_properties(v, True, None, Comment.wall_user_id == u.id)
|
||||
comments = comments.filter(Comment.level == 1)
|
||||
|
||||
if not v or (v.id != u.id and v.admin_level < PERMS['POST_COMMENT_MODERATION']):
|
||||
comments = comments.filter(
|
||||
Comment.is_banned == False,
|
||||
Comment.ghost == False,
|
||||
Comment.deleted_utc == 0
|
||||
)
|
||||
|
||||
comments = comments.order_by(Comment.created_utc.desc()).offset(PAGE_SIZE * (page - 1)).limit(PAGE_SIZE+1)
|
||||
comments = [c[0] for c in comments.all()]
|
||||
|
||||
next_exists = (len(comments) > PAGE_SIZE)
|
||||
comments = comments[:PAGE_SIZE]
|
||||
|
||||
if (v and v.client) or request.path.endswith(".json"):
|
||||
return {"data": [c.json(g.db) for c in comments]}
|
||||
|
||||
return render_template("userpage/wall.html", u=u, v=v, listing=comments, page=page, next_exists=next_exists, is_following=is_following, standalone=True, render_replies=True)
|
||||
|
||||
|
||||
@app.get("/@<username>/posts")
|
||||
@app.get("/@<username>/posts.json")
|
||||
@auth_desired_with_logingate
|
||||
def u_username(username, v=None):
|
||||
u = get_user(username, v=v, include_blocks=True, include_shadowbanned=False)
|
||||
if username != u.username:
|
||||
|
@ -766,7 +810,7 @@ def u_username(username, v=None):
|
|||
if (v and v.client) or request.path.endswith(".json"):
|
||||
return {"data": [x.json(g.db) for x in listing]}
|
||||
|
||||
return render_template("userpage.html",
|
||||
return render_template("userpage/userpage.html",
|
||||
unban=u.unban_string,
|
||||
u=u,
|
||||
v=v,
|
||||
|
@ -780,7 +824,7 @@ def u_username(username, v=None):
|
|||
if (v and v.client) or request.path.endswith(".json"):
|
||||
return {"data": [x.json(g.db) for x in listing]}
|
||||
|
||||
return render_template("userpage.html",
|
||||
return render_template("userpage/userpage.html",
|
||||
u=u,
|
||||
v=v,
|
||||
listing=listing,
|
||||
|
@ -1005,7 +1049,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.html", SaveRelationship, page, False)
|
||||
return get_saves_and_subscribes(v, "userpage/userpage.html", SaveRelationship, page, False)
|
||||
|
||||
@app.get("/@<username>/saved/comments")
|
||||
@auth_required
|
||||
|
@ -1021,7 +1065,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.html", Subscription, page, False)
|
||||
return get_saves_and_subscribes(v, "userpage/userpage.html", Subscription, page, False)
|
||||
|
||||
@app.post("/fp/<fp>")
|
||||
@auth_required
|
||||
|
|
|
@ -71,7 +71,7 @@ def vote_post_comment(target_id, new, v, cls, vote_cls):
|
|||
target = get_post(target_id)
|
||||
elif cls == Comment:
|
||||
target = get_comment(target_id)
|
||||
if not target.parent_submission: abort(404)
|
||||
if not target.parent_submission and not target.wall_user_id: abort(404)
|
||||
else:
|
||||
abort(404)
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
{% extends "userpage.html" %}
|
||||
{% extends "userpage/userpage.html" %}
|
||||
{% block pagetype %}userpage{% endblock %}
|
||||
{% block desktopBanner %}{% endblock %}
|
||||
{% block desktopUserBanner %}{% endblock %}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
{% extends "userpage.html" %}
|
||||
{% extends "userpage/userpage.html" %}
|
||||
{% block pagetype %}userpage{% endblock %}
|
||||
{% block desktopBanner %}{% endblock %}
|
||||
{% block desktopUserBanner %}{% endblock %}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
{% extends "userpage.html" %}
|
||||
{% extends "userpage/userpage.html" %}
|
||||
{% block pagetype %}userpage{% endblock %}
|
||||
{% block desktopBanner %}{% endblock %}
|
||||
{% block desktopUserBanner %}{% endblock %}
|
||||
|
|
|
@ -92,7 +92,7 @@
|
|||
{% endif %}
|
||||
{% elif c.author_id==AUTOJANNY_ID %}
|
||||
<span class="font-weight-bold">Notification</span>
|
||||
{% else %}
|
||||
{% elif not c.wall_user_id %}
|
||||
{% if c.sentto == MODMAIL_ID %}
|
||||
<span class="font-weight-bold">Sent to admins</span>
|
||||
{% else %}
|
||||
|
@ -266,7 +266,7 @@
|
|||
<div id="comment-text-{{c.id}}" class="comment-text mb-0 {% if c.author.agendaposter and not (c.parent_submission and c.post.sub == 'chudrama') %}agendaposter{% endif %} {% if c.author.rainbow %}rainbow-text{% endif %}">
|
||||
{{c.realbody(v) | safe}}
|
||||
</div>
|
||||
{% if c.parent_submission %}
|
||||
{% if c.parent_submission or c.wall_user_id %}
|
||||
|
||||
{% if v and v.id==c.author_id %}
|
||||
<div id="comment-edit-{{c.id}}" class="d-none comment-write collapsed child">
|
||||
|
@ -422,7 +422,7 @@
|
|||
<button type="button" id="save-{{c.id}}" class="btn caction py-0 nobackground px-1 {% if c.id not in v.saved_comment_idlist %}d-md-inline-block{% endif %} text-muted d-none" onclick="postToastSwitch(this,'/save_comment/{{c.id}}','save-{{c.id}}','unsave-{{c.id}}','d-md-inline-block')"><i class="fas fa-save"></i>Save</button>
|
||||
{% endif %}
|
||||
|
||||
{% if c.parent_submission %}
|
||||
{% if c.parent_submission or c.wall_user_id %}
|
||||
{% if v and c.author_id == v.id %}
|
||||
<button type="button" class="btn caction py-0 nobackground px-1 text-muted" onclick="toggleEdit('{{c.id}}')"><i class="fas fa-edit fa-fw"></i>Edit</button>
|
||||
|
||||
|
@ -485,7 +485,7 @@
|
|||
{% endif %}
|
||||
{% endif %}
|
||||
|
||||
{% if c.parent_submission and (c.author_id==v.id or v.admin_level >= PERMS['POST_COMMENT_MODERATION'] or (c.post.sub and v.mods(c.post.sub))) %}
|
||||
{% if (c.parent_submission or c.wall_user_id) and (c.author_id==v.id or v.admin_level >= PERMS['POST_COMMENT_MODERATION'] or (c.post.sub and v.mods(c.post.sub))) %}
|
||||
<button type="button" id="unmark-{{c.id}}" class="dropdown-item list-inline-item d-none {% if c.over_18 %}d-md-block{% endif %} text-success" onclick="postToastSwitch(this,'/toggle_comment_nsfw/{{c.id}}','mark-{{c.id}}','unmark-{{c.id}}','d-md-block')"><i class="fas fa-eye-evil text-success fa-fw"></i>Unmark +18</button>
|
||||
<button type="button" id="mark-{{c.id}}" class="dropdown-item list-inline-item d-none {% if not c.over_18 %}d-md-block{% endif %} text-danger" onclick="postToastSwitch(this,'/toggle_comment_nsfw/{{c.id}}','mark-{{c.id}}','unmark-{{c.id}}','d-md-block')"><i class="fas fa-eye-evil text-danger fa-fw"></i>Mark +18</button>
|
||||
{% endif %}
|
||||
|
@ -537,7 +537,7 @@
|
|||
<input autocomplete="off" id="file-upload-reply-{{c.fullname}}" accept="image/*, video/*, audio/*" type="file" multiple="multiple" name="file" {% if g.is_tor %}disabled{% endif %} onchange="changename('filename-show-reply-{{c.fullname}}','file-upload-reply-{{c.fullname}}')" hidden>
|
||||
</label>
|
||||
</div>
|
||||
<button type="button" id="save-reply-to-{{c.fullname}}" class="btn btn-primary ml-2 fl-r commentmob" onclick="post_comment('{{c.fullname}}', 'reply-to-{{c.id}}');remove_dialog()">Comment</button>
|
||||
<button type="button" id="save-reply-to-{{c.fullname}}" class="btn btn-primary ml-2 fl-r commentmob" onclick="post_comment('{{c.fullname}}', '{{c.wall_user_id}}', 'reply-to-{{c.id}}');remove_dialog()">Comment</button>
|
||||
<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>
|
||||
|
@ -696,7 +696,7 @@
|
|||
</div>
|
||||
<div class="modal-body">
|
||||
<ul class="list-group comment-actions">
|
||||
{% if c.parent_submission %}
|
||||
{% if c.parent_submission or c.wall_user_id %}
|
||||
{% if v.admin_level >= PERMS['APPS_MODERATION'] and c.oauth_app %}
|
||||
<a href="{{c.oauth_app.permalink}}/comments" class="list-group-item text-info"><i class="fas fa-code text-info mr-2"></i>API App</a>
|
||||
{% endif %}
|
||||
|
|
|
@ -366,7 +366,7 @@
|
|||
<input autocomplete="off" id="file-upload-reply-{{p.fullname}}" accept="image/*, video/*, audio/*" type="file" multiple="multiple" name="file" {% if g.is_tor %}disabled{% endif %} onchange="changename('filename-show-reply-{{p.fullname}}','file-upload-reply-{{p.fullname}}')" hidden>
|
||||
</label>
|
||||
</div>
|
||||
<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>
|
||||
<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}}', 'None');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 %}data-target="t"target="_blank"{% endif %}>Formatting help</a></div>
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
{% extends "userpage.html" %}
|
||||
{% extends "userpage/userpage.html" %}
|
||||
|
||||
{% block content %}
|
||||
|
||||
|
@ -7,7 +7,10 @@
|
|||
<div class="flex-row box-shadow-bottom d-flex justify-content-center justify-content-md-between align-items-center">
|
||||
<ul class="nav settings-nav" id="profile-content--nav">
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="/@{{u.username}}">Posts <span class="count">({{u.post_count}})</span></a>
|
||||
<a class="nav-link" href="/@{{u.username}}">Wall</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="/@{{u.username}}/posts">Posts <span class="count">({{u.post_count}})</span></a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link {% if not 'saved' in request.path %}active{% endif %}" href="/@{{u.username}}/comments">Comments <span class="count">({{u.comment_count}})</span></a>
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
{% extends "userpage.html" %}
|
||||
{% extends "userpage/userpage.html" %}
|
||||
|
||||
|
||||
{% block content %}
|
||||
|
|
|
@ -474,7 +474,10 @@
|
|||
<div class="flex-row box-shadow-bottom d-flex justify-content-center justify-content-md-between align-items-center">
|
||||
<ul class="nav settings-nav" id="profile-content--nav">
|
||||
<li class="nav-item">
|
||||
<a class="nav-link {% if not 'saved' in request.path %}active{% endif %}" href="/@{{u.username}}">Posts <span class="count">({{u.post_count}})</span></a>
|
||||
<a class="nav-link" href="/@{{u.username}}">Wall</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link {% if not 'saved' in request.path %}active{% endif %}" href="/@{{u.username}}/posts">Posts <span class="count">({{u.post_count}})</span></a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="/@{{u.username}}/comments">Comments <span class="count">({{u.comment_count}})</span></a>
|
||||
|
@ -595,12 +598,12 @@
|
|||
</nav>
|
||||
{% endif %}
|
||||
|
||||
{% if not request.path.endswith('/comments') %}
|
||||
{% if not request.path.endswith('/comments') and not request.path.endswith(u.username) %}
|
||||
<script defer src="{{'js/vendor/marked.js' | asset}}"></script>
|
||||
<script defer src="{{'js/markdown.js' | asset}}"></script>
|
||||
{% endif %}
|
||||
|
||||
{% if v and v.id != u.id and '/comments' not in request.path %}
|
||||
{% 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 %}
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
{% extends "userpage.html" %}
|
||||
{% extends "userpage/userpage.html" %}
|
||||
{% block pagetype %}userpage{% endblock %}
|
||||
{% block desktopBanner %}{% endblock %}
|
||||
{% block desktopUserBanner %}{% endblock %}
|
||||
|
|
|
@ -0,0 +1,114 @@
|
|||
{% extends "userpage/userpage.html" %}
|
||||
|
||||
{% block content %}
|
||||
|
||||
<div class="row no-gutters">
|
||||
<div class="col">
|
||||
<div class="flex-row box-shadow-bottom d-flex justify-content-center justify-content-md-between align-items-center">
|
||||
<ul class="nav settings-nav" id="profile-content--nav">
|
||||
<li class="nav-item">
|
||||
<a class="nav-link active" href="/@{{u.username}}">Wall</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="/@{{u.username}}/posts">Posts <span class="count">({{u.post_count}})</span></a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="/@{{u.username}}/comments">Comments <span class="count">({{u.comment_count}})</span></a>
|
||||
</li>
|
||||
{% if u.id == v.id %}
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="/@{{u.username}}/saved/posts">Saved Posts <span class="count">({{u.saved_count}})</span></a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link {% if 'saved' in request.path %}active{% endif %}" href="/@{{u.username}}/saved/comments">Saved Comments <span class="count">({{u.saved_comment_count}})</span></a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="/@{{u.username}}/subscribed/posts">Subscribed <span class="count">({{u.subscribed_count}})</span></a>
|
||||
</li>
|
||||
{% endif %}
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{% if v %}
|
||||
<div id="comment-form-space-{{u.fullname}}" class="comment-write mb-3 mt-4">
|
||||
<form id="reply-to-{{u.fullname}}" action="/comment" method="post">
|
||||
<input type="hidden" name="formkey" value="{{v|formkey}}">
|
||||
<input type="hidden" name="parent_fullname" value="p_{{u.id}}">
|
||||
<input autocomplete="off" id="reply-form-submission-{{u.fullname}}" type="hidden" name="submission" value="{{u.id}}">
|
||||
<textarea required autocomplete="off" {% if v.longpost %}minlength="280"{% elif v.bird %}maxlength="140"{% endif %} minlength="1" maxlength="10000" data-preview="form-preview-{{u.fullname}}" oninput="markdown(this);charLimit('reply-form-body-{{u.fullname}}','charcount-{{u.fullname}}')" id="reply-form-body-{{u.fullname}}" data-fullname="{{u.fullname}}" class="comment-box form-control rounded" name="body" form="reply-to-{{u.fullname}}" aria-label="With textarea" placeholder="Add your comment..." rows="3"></textarea>
|
||||
|
||||
<div class="text-small font-weight-bold mt-1" id="charcount-{{u.fullname}}" style="right: 1rem; bottom: 0.5rem; z-index: 3;"></div>
|
||||
|
||||
<div class="comment-format">
|
||||
<label class="btn btn-secondary format d-inline-block m-0" for="gif-reply-btn-{{u.fullname}}">
|
||||
<span id="gif-reply-btn-{{u.fullname}}" class="font-weight-bolder text-uppercase" onclick="commentForm('reply-form-body-{{u.fullname}}');getGif()" aria-hidden="true" data-bs-toggle="modal" data-bs-target="#gifModal" data-bs-toggle="tooltip" data-bs-placement="bottom" title="Add GIF">GIF</span>
|
||||
</label>
|
||||
|
||||
<div onclick="loadEmojis('reply-form-body-{{u.fullname}}')" class="btn btn-secondary format d-inline-block m-0" id="emoji-reply-btn-{{u.fullname}}" aria-hidden="true" data-bs-toggle="modal" data-bs-target="#emojiModal" data-bs-toggle="tooltip" data-bs-placement="bottom" title="Add Emoji"><i class="fas fa-smile-beam"></i></div>
|
||||
|
||||
<label class="format btn btn-secondary m-0 ml-1 {% if v %}d-inline-block{% else %}d-none{% endif %}" for="file-upload-reply-{{u.fullname}}">
|
||||
<div id="filename-show-reply-{{u.fullname}}"><i class="fas fa-file"></i></div>
|
||||
<input autocomplete="off" id="file-upload-reply-{{u.fullname}}" accept="image/*, video/*, audio/*" type="file" multiple="multiple" name="file" {% if g.is_tor %}disabled{% endif %} onchange="changename('filename-show-reply-{{u.fullname}}','file-upload-reply-{{u.fullname}}')" hidden>
|
||||
</label>
|
||||
</div>
|
||||
<button type="button" id="save-reply-to-{{u.fullname}}" form="reply-to-{{u.fullname}}" class="btn btn-primary text-whitebtn ml-auto fl-r" onclick="post_comment('{{u.fullname}}', '{{u.id}}');remove_dialog()">Comment</button>
|
||||
</form>
|
||||
<div id="form-preview-{{u.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 %}data-target="t"target="_blank"{% endif %}>Formatting help</a></div>
|
||||
</div>
|
||||
{% else %}
|
||||
<div class="comment-write mb-3 mt-4">
|
||||
<textarea autocomplete="off" maxlength="10000" class="comment-box form-control rounded" name="body" aria-label="With textarea" placeholder="Add your comment..." rows="3" onclick="location.href='/login?redirect={{request.full_path | urlencode}}';"></textarea>
|
||||
</div>
|
||||
|
||||
<div class="card border-0 mt-4">
|
||||
<div class="card-body">
|
||||
<h5 class="card-title">Jump in the discussion.</h5>
|
||||
<p class="card-text">No email address required.</p>
|
||||
<div>
|
||||
<a href="/signup?redirect={{request.full_path | urlencode}}" class="btn btn-primary">Sign up</a>
|
||||
<a href="/login?redirect={{request.full_path | urlencode}}" class="btn btn-link text-muted">Sign in</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
<div class="row no-gutters {% if listing %}mt-md-3{% elif not listing %}my-md-3{% endif %}" style="margin-top: 10px;">
|
||||
|
||||
<div class="col">
|
||||
<div class="comment-section" id="replies-of-{{u.fullname}}">
|
||||
{% with comments=listing %}
|
||||
{% include "comments.html" %}
|
||||
{% endwith %}
|
||||
</div>
|
||||
{% if not listing %}
|
||||
<div class="text-center px-3 my-3">
|
||||
<span class="fa-stack fa-2x text-muted mb-4">
|
||||
<i class="fas fa-square text-gray-500 opacity-25 fa-stack-2x"></i>
|
||||
<i class="fas text-gray-500 fa-scroll-old fa-stack-1x text-lg"></i>
|
||||
</span>
|
||||
<h5>There's no comments on your wall yet!</h5>
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{% if u.song %}
|
||||
{% if v and v.id == u.id %}
|
||||
<div id="v_username" class="d-none">{{v.username}}</div>
|
||||
{% else %}
|
||||
<div id="u_username" class="d-none">{{u.username}}</div>
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
|
||||
{% if v %}
|
||||
<div id='tax' class="d-none">{% if v.patron or u.patron %}0{% else %}0.03{% endif %}</div>
|
||||
<div id="username" class="d-none">{{u.username}}</div>
|
||||
<script defer src="{{'js/userpage_v.js' | asset}}"></script>
|
||||
{% endif %}
|
||||
|
||||
<script defer src="{{'js/userpage.js' | asset}}"></script>
|
||||
|
||||
{% endblock %}
|
Loading…
Reference in New Issue