Merge remote-tracking branch 'upstream/frost' into 601_convert_created_utc_to_datetimez_for_flags
This commit is contained in:
commit
04b310fba0
26 changed files with 474 additions and 686 deletions
|
@ -5134,7 +5134,7 @@ th, td {
|
||||||
}
|
}
|
||||||
|
|
||||||
#account-menu-header, #account-menu {
|
#account-menu-header, #account-menu {
|
||||||
min-width: 10em;
|
min-width: 13em;
|
||||||
}
|
}
|
||||||
|
|
||||||
.navigation-secondary-link {
|
.navigation-secondary-link {
|
||||||
|
|
|
@ -57,3 +57,21 @@ function expandMarkdown(t,id) {
|
||||||
if (val.innerHTML == 'View source') val.innerHTML = 'Hide source'
|
if (val.innerHTML == 'View source') val.innerHTML = 'Hide source'
|
||||||
else val.innerHTML = 'View source'
|
else val.innerHTML = 'View source'
|
||||||
};
|
};
|
||||||
|
|
||||||
|
function commentsAddUnreadIndicator(commentIds) {
|
||||||
|
commentIds.forEach(element => {
|
||||||
|
const commentOnly = document.getElementById(`comment-${element}-only`);
|
||||||
|
if (!commentOnly) {
|
||||||
|
console.warn(`Couldn't find comment (comment ID ${element}) in page while attempting to add an unread indicator.`);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (commentOnly.classList.contains("unread")) return;
|
||||||
|
commentOnly.classList.add("unread");
|
||||||
|
const commentUserInfo = document.getElementById(`comment-${element}`)?.querySelector(".comment-user-info");
|
||||||
|
if (!commentUserInfo) {
|
||||||
|
console.warn(`Couldn't find comment user info (comment ID ${element}) in page while attempting to add an unread indicator.`);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
commentUserInfo.innerHTML += "<span class=\"new-indicator\">~new~</span>";
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
|
@ -1,78 +1,23 @@
|
||||||
function removeCommentBackend(post_id) {
|
function moderate(isPost, id, removing, removeButtonDesktopId, removeButtonMobileId, approveButtonDesktopId, approveButtonMobileId) {
|
||||||
url="/remove_comment/"+post_id
|
const filterState = removing ? "removed" : "normal";
|
||||||
|
if (isPost) {
|
||||||
post(url)
|
filter_new_status(id, filterState);
|
||||||
|
} else {
|
||||||
|
filter_new_comment_status(id, filterState);
|
||||||
}
|
}
|
||||||
|
const removeButtonDesktop = document.getElementById(removeButtonDesktopId);
|
||||||
function approveCommentBackend(post_id) {
|
const removeButtonMobile = document.getElementById(removeButtonMobileId);
|
||||||
url="/unremove_comment/"+post_id
|
const approveButtonDesktop = document.getElementById(approveButtonDesktopId);
|
||||||
|
const approveButtonMobile = document.getElementById(approveButtonMobileId);
|
||||||
post(url)
|
if (removing) {
|
||||||
}
|
removeButtonDesktop.classList.add("d-none");
|
||||||
|
removeButtonMobile.classList.add("d-none");
|
||||||
function removeCommentDesktop(post_id,button1,button2) {
|
approveButtonDesktop.classList.remove("d-none");
|
||||||
removeCommentBackend(post_id)
|
approveButtonMobile.classList.remove("d-none");
|
||||||
|
} else {
|
||||||
try {
|
removeButtonDesktop.classList.remove("d-none");
|
||||||
document.getElementById("comment-"+post_id+"-only").classList.add("banned");
|
removeButtonMobile.classList.remove("d-none");
|
||||||
} catch(e) {
|
approveButtonDesktop.classList.add("d-none");
|
||||||
document.getElementById("context").classList.add("banned");
|
approveButtonMobile.classList.add("d-none");
|
||||||
}
|
|
||||||
|
|
||||||
var button=document.getElementById("remove-"+post_id);
|
|
||||||
button.onclick=function(){approveCommentDesktop(post_id)};
|
|
||||||
button.innerHTML='<i class="fas fa-clipboard-check"></i>Approve'
|
|
||||||
|
|
||||||
if (typeof button1 !== 'undefined') {
|
|
||||||
document.getElementById(button1).classList.toggle("d-md-inline-block");
|
|
||||||
document.getElementById(button2).classList.toggle("d-md-inline-block");
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
function approveCommentDesktop(post_id,button1,button2) {
|
|
||||||
approveCommentBackend(post_id)
|
|
||||||
|
|
||||||
try {
|
|
||||||
document.getElementById("comment-"+post_id+"-only").classList.remove("banned");
|
|
||||||
} catch(e) {
|
|
||||||
document.getElementById("context").classList.remove("banned");
|
|
||||||
}
|
|
||||||
|
|
||||||
var button=document.getElementById("remove-"+post_id);
|
|
||||||
button.onclick=function(){removeCommentDesktop(post_id)};
|
|
||||||
button.innerHTML='<i class="fas fa-trash-alt"></i>Remove'
|
|
||||||
|
|
||||||
if (typeof button1 !== 'undefined') {
|
|
||||||
document.getElementById(button1).classList.toggle("d-md-inline-block");
|
|
||||||
document.getElementById(button2).classList.toggle("d-md-inline-block");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
function removeCommentMobile(post_id,button1,button2) {
|
|
||||||
removeCommentBackend(post_id)
|
|
||||||
|
|
||||||
document.getElementById("comment-"+post_id+"-only").classList.add("banned");
|
|
||||||
var button=document.getElementById("remove-"+post_id);
|
|
||||||
button.onclick=function(){approveCommentMobile(post_id)};
|
|
||||||
button.innerHTML='<i class="fas fa-clipboard-check"></i>Approve'
|
|
||||||
|
|
||||||
if (typeof button1 !== 'undefined') {
|
|
||||||
document.getElementById(button1).classList.toggle("d-none");
|
|
||||||
document.getElementById(button2).classList.toggle("d-none");
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
function approveCommentMobile(post_id,button1,button2) {
|
|
||||||
approveCommentBackend(post_id)
|
|
||||||
|
|
||||||
document.getElementById("comment-"+post_id+"-only").classList.remove("banned");
|
|
||||||
var button=document.getElementById("remove-"+post_id);
|
|
||||||
button.onclick=function(){removeCommentMobile(post_id)};
|
|
||||||
button.innerHTML='<i class="fas fa-trash-alt"></i>Remove'
|
|
||||||
|
|
||||||
if (typeof button1 !== 'undefined') {
|
|
||||||
document.getElementById(button1).classList.toggle("d-none");
|
|
||||||
document.getElementById(button2).classList.toggle("d-none");
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -85,6 +85,26 @@ class ModAction(CreatedBase):
|
||||||
return f"/log/{self.id}"
|
return f"/log/{self.id}"
|
||||||
|
|
||||||
ACTIONTYPES = {
|
ACTIONTYPES = {
|
||||||
|
'approve_post': {
|
||||||
|
"str": 'approved post {self.target_link}',
|
||||||
|
"icon": 'fa-feather-alt',
|
||||||
|
"color": 'bg-success'
|
||||||
|
},
|
||||||
|
'approve_comment': {
|
||||||
|
"str": 'approved {self.target_link}',
|
||||||
|
"icon": 'fa-comment',
|
||||||
|
"color": 'bg-success'
|
||||||
|
},
|
||||||
|
'remove_post': {
|
||||||
|
"str": 'removed post {self.target_link}',
|
||||||
|
"icon": 'fa-feather-alt',
|
||||||
|
"color": 'bg-danger'
|
||||||
|
},
|
||||||
|
'remove_comment': {
|
||||||
|
"str": 'removed {self.target_link}',
|
||||||
|
"icon": 'fa-comment',
|
||||||
|
"color": 'bg-danger'
|
||||||
|
},
|
||||||
'approve_app': {
|
'approve_app': {
|
||||||
"str": 'approved an application by {self.target_link}',
|
"str": 'approved an application by {self.target_link}',
|
||||||
"icon": 'fa-robot',
|
"icon": 'fa-robot',
|
||||||
|
@ -100,21 +120,11 @@ ACTIONTYPES = {
|
||||||
"icon": 'fa-badge',
|
"icon": 'fa-badge',
|
||||||
"color": 'bg-danger'
|
"color": 'bg-danger'
|
||||||
},
|
},
|
||||||
'remove_comment': {
|
|
||||||
"str": 'removed {self.target_link}',
|
|
||||||
"icon": 'fa-comment',
|
|
||||||
"color": 'bg-danger'
|
|
||||||
},
|
|
||||||
'ban_domain': {
|
'ban_domain': {
|
||||||
"str": 'banned a domain',
|
"str": 'banned a domain',
|
||||||
"icon": 'fa-globe',
|
"icon": 'fa-globe',
|
||||||
"color": 'bg-danger'
|
"color": 'bg-danger'
|
||||||
},
|
},
|
||||||
'remove_post': {
|
|
||||||
"str": 'removed post {self.target_link}',
|
|
||||||
"icon": 'fa-feather-alt',
|
|
||||||
"color": 'bg-danger'
|
|
||||||
},
|
|
||||||
'ban_user': {
|
'ban_user': {
|
||||||
"str": 'banned user {self.target_link}',
|
"str": 'banned user {self.target_link}',
|
||||||
"icon": 'fa-user-slash',
|
"icon": 'fa-user-slash',
|
||||||
|
@ -300,21 +310,11 @@ ACTIONTYPES = {
|
||||||
"icon": 'fa-eye-slash',
|
"icon": 'fa-eye-slash',
|
||||||
"color": 'bg-danger'
|
"color": 'bg-danger'
|
||||||
},
|
},
|
||||||
'unremove_comment': {
|
|
||||||
"str": 'reinstated {self.target_link}',
|
|
||||||
"icon": 'fa-comment',
|
|
||||||
"color": 'bg-success'
|
|
||||||
},
|
|
||||||
'unban_domain': {
|
'unban_domain': {
|
||||||
"str": 'unbanned a domain',
|
"str": 'unbanned a domain',
|
||||||
"icon": 'fa-globe',
|
"icon": 'fa-globe',
|
||||||
"color": 'bg-success'
|
"color": 'bg-success'
|
||||||
},
|
},
|
||||||
'unremove_post': {
|
|
||||||
"str": 'reinstated post {self.target_link}',
|
|
||||||
"icon": 'fa-feather-alt',
|
|
||||||
"color": 'bg-success'
|
|
||||||
},
|
|
||||||
'unban_user': {
|
'unban_user': {
|
||||||
"str": 'unbanned user {self.target_link}',
|
"str": 'unbanned user {self.target_link}',
|
||||||
"icon": 'fa-user',
|
"icon": 'fa-user',
|
||||||
|
|
|
@ -64,13 +64,14 @@ class VisibilityState:
|
||||||
op_name_safe=target.author_name
|
op_name_safe=target.author_name
|
||||||
)
|
)
|
||||||
|
|
||||||
def moderated_body(self, v: User | None) -> str | None:
|
def moderated_body(self, v: User | None, is_blocking: bool=False) -> str | None:
|
||||||
if v and (v.admin_level >= PERMS['POST_COMMENT_MODERATION'] \
|
if v and (v.admin_level >= PERMS['POST_COMMENT_MODERATION'] \
|
||||||
or v.id == self.op_id):
|
or v.id == self.op_id):
|
||||||
return None
|
return None
|
||||||
if self.deleted: return 'Deleted'
|
if self.deleted: return 'Deleted'
|
||||||
if self.appear_removed(v): return 'Removed'
|
if self.appear_removed(v): return 'Removed'
|
||||||
if self.filtered: return 'Filtered'
|
if self.filtered: return 'Filtered'
|
||||||
|
if is_blocking: return f'You are blocking @{self.op_name_safe}'
|
||||||
return None
|
return None
|
||||||
|
|
||||||
def visibility_and_message(self, v: User | None, is_blocking: bool) -> tuple[bool, str]:
|
def visibility_and_message(self, v: User | None, is_blocking: bool) -> tuple[bool, str]:
|
||||||
|
|
|
@ -87,7 +87,10 @@ def canonicalize_url2(url:str, *, httpsify:bool=False) -> urllib.parse.ParseResu
|
||||||
|
|
||||||
|
|
||||||
def body_displayed(target:Submittable, v:Optional[User], is_html:bool) -> str:
|
def body_displayed(target:Submittable, v:Optional[User], is_html:bool) -> str:
|
||||||
moderated:Optional[str] = target.visibility_state.moderated_body(v)
|
moderated:Optional[str] = target.visibility_state.moderated_body(
|
||||||
|
v=v,
|
||||||
|
is_blocking=getattr(target, 'is_blocking', False)
|
||||||
|
)
|
||||||
if moderated: return moderated
|
if moderated: return moderated
|
||||||
|
|
||||||
body = target.body_html if is_html else target.body
|
body = target.body_html if is_html else target.body
|
||||||
|
|
|
@ -272,14 +272,14 @@ def filtered_comments(v):
|
||||||
# (also rename Unremove to Approve, sigh)
|
# (also rename Unremove to Approve, sigh)
|
||||||
@app.post("/admin/update_filter_status")
|
@app.post("/admin/update_filter_status")
|
||||||
@limiter.exempt
|
@limiter.exempt
|
||||||
@admin_level_required(2)
|
@admin_level_required(PERMS['POST_COMMENT_MODERATION'])
|
||||||
def update_filter_status(v):
|
def update_filter_status(v):
|
||||||
update_body = request.get_json()
|
update_body = request.get_json()
|
||||||
new_status = update_body.get('new_status')
|
new_status = update_body.get('new_status')
|
||||||
post_id = update_body.get('post_id')
|
post_id = update_body.get('post_id')
|
||||||
comment_id = update_body.get('comment_id')
|
comment_id = update_body.get('comment_id')
|
||||||
if new_status not in ['normal', 'removed', 'ignored']:
|
if new_status not in ['normal', 'removed', 'ignored']:
|
||||||
return { 'result': f'Status of {new_status} is not permitted' }
|
return {'result': f'Status of {new_status} is not permitted'}, 403
|
||||||
|
|
||||||
if new_status == 'normal':
|
if new_status == 'normal':
|
||||||
state_mod_new = StateMod.VISIBLE
|
state_mod_new = StateMod.VISIBLE
|
||||||
|
@ -292,43 +292,45 @@ def update_filter_status(v):
|
||||||
state_report_new = StateReport.IGNORED
|
state_report_new = StateReport.IGNORED
|
||||||
|
|
||||||
if post_id:
|
if post_id:
|
||||||
target = g.db.get(Submission, post_id)
|
target: Submission = get_post(post_id, graceful=True)
|
||||||
old_status = target.state_mod
|
modlog_target_type: str = 'post'
|
||||||
|
|
||||||
# this could totally be one query but it would be kinda ugly
|
|
||||||
if state_mod_new is not None:
|
|
||||||
g.db.query(Submission).where(Submission.id == post_id) \
|
|
||||||
.update({Submission.state_mod: state_mod_new, Submission.state_mod_set_by: v.username})
|
|
||||||
g.db.query(Submission).where(Submission.id == post_id) \
|
|
||||||
.update({Submission.state_report: state_report_new})
|
|
||||||
elif comment_id:
|
elif comment_id:
|
||||||
target = g.db.get(Comment, comment_id)
|
target: Comment = get_comment(comment_id, graceful=True)
|
||||||
|
modlog_target_type: str = 'comment'
|
||||||
|
else:
|
||||||
|
return {"result": "No valid item ID provided"}, 404
|
||||||
|
|
||||||
|
if not target:
|
||||||
|
return {"result": "Item ID does not exist"}, 404
|
||||||
|
|
||||||
old_status = target.state_mod
|
old_status = target.state_mod
|
||||||
|
|
||||||
if state_mod_new is not None:
|
if state_mod_new is not None:
|
||||||
g.db.query(Comment).where(Comment.id == comment_id) \
|
target.state_mod = state_mod_new
|
||||||
.update({Comment.state_mod: state_mod_new, Comment.state_mod_set_by: v.username})
|
target.state_mod_set_by = v.username
|
||||||
g.db.query(Comment).where(Comment.id == comment_id) \
|
target.state_report = state_report_new
|
||||||
.update({Comment.state_report: state_report_new})
|
|
||||||
else:
|
|
||||||
return { 'result': f'No valid item ID provided' }
|
|
||||||
|
|
||||||
if target is not None:
|
making_visible: bool = old_status != StateMod.VISIBLE and state_mod_new == StateMod.VISIBLE
|
||||||
# If comment now visible, update state to reflect publication.
|
making_invisible: bool = old_status == StateMod.VISIBLE and state_mod_new != StateMod.VISIBLE and state_mod_new is not None
|
||||||
if (isinstance(target, Comment)
|
|
||||||
and old_status != StateMod.VISIBLE
|
|
||||||
and state_mod_new == StateMod.VISIBLE):
|
|
||||||
comment_on_publish(target) # XXX: can cause discrepancies if removal state ≠ filter state
|
|
||||||
|
|
||||||
if (isinstance(target, Comment)
|
if making_visible:
|
||||||
and old_status == StateMod.VISIBLE
|
modlog_action: str = "approve"
|
||||||
and state_mod_new != StateMod.VISIBLE and state_mod_new is not None):
|
if isinstance(target, Comment): comment_on_publish(target)
|
||||||
comment_on_unpublish(target) # XXX: can cause discrepancies if removal state ≠ filter state
|
elif making_invisible:
|
||||||
|
modlog_action: str = "remove"
|
||||||
|
if isinstance(target, Comment): comment_on_unpublish(target)
|
||||||
|
|
||||||
|
if making_visible or making_invisible:
|
||||||
|
g.db.add(ModAction(
|
||||||
|
kind=f"{modlog_action}_{modlog_target_type}",
|
||||||
|
user_id=v.id,
|
||||||
|
target_submission_id=target.id if isinstance(target, Submission) else None,
|
||||||
|
target_comment_id=target.id if isinstance(target, Comment) else None
|
||||||
|
))
|
||||||
|
|
||||||
g.db.commit()
|
g.db.commit()
|
||||||
|
invalidate_cache(frontlist=True)
|
||||||
return { 'result': 'Update successful' }
|
return { 'result': 'Update successful' }
|
||||||
else:
|
|
||||||
return { 'result': 'Item ID does not exist' }
|
|
||||||
|
|
||||||
@app.get("/admin/image_posts")
|
@app.get("/admin/image_posts")
|
||||||
@limiter.exempt
|
@limiter.exempt
|
||||||
|
@ -809,7 +811,7 @@ def admin_removed_comments(v):
|
||||||
try: page = int(request.values.get("page", 1))
|
try: page = int(request.values.get("page", 1))
|
||||||
except: page = 1
|
except: page = 1
|
||||||
|
|
||||||
ids = g.db.query(Comment.id).join(User, User.id == Comment.author_id).filter(or_(Comment.state_mode == StateMod.REMOVED, User.shadowbanned != None)).order_by(Comment.id.desc()).offset(25 * (page - 1)).limit(26).all()
|
ids = g.db.query(Comment.id).join(User, User.id == Comment.author_id).filter(or_(Comment.state_mod == StateMod.REMOVED, User.shadowbanned != None)).order_by(Comment.id.desc()).offset(25 * (page - 1)).limit(26).all()
|
||||||
|
|
||||||
ids=[x[0] for x in ids]
|
ids=[x[0] for x in ids]
|
||||||
|
|
||||||
|
@ -1100,74 +1102,6 @@ def unban_user(user_id, v):
|
||||||
else: return {"message": f"@{user.username} was unbanned!"}
|
else: return {"message": f"@{user.username} was unbanned!"}
|
||||||
|
|
||||||
|
|
||||||
@app.post("/remove_post/<post_id>")
|
|
||||||
@limiter.exempt
|
|
||||||
@admin_level_required(2)
|
|
||||||
def remove_post(post_id, v):
|
|
||||||
post = g.db.query(Submission).filter_by(id=post_id).one_or_none()
|
|
||||||
|
|
||||||
if not post:
|
|
||||||
abort(400)
|
|
||||||
|
|
||||||
post.state_mod = StateMod.REMOVED
|
|
||||||
post.state_mod_set_by = v.username
|
|
||||||
post.stickied = None
|
|
||||||
post.is_pinned = False
|
|
||||||
g.db.add(post)
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
ma=ModAction(
|
|
||||||
kind="remove_post",
|
|
||||||
user_id=v.id,
|
|
||||||
target_submission_id=post.id,
|
|
||||||
)
|
|
||||||
g.db.add(ma)
|
|
||||||
|
|
||||||
invalidate_cache(frontlist=True)
|
|
||||||
|
|
||||||
v.coins += 1
|
|
||||||
g.db.add(v)
|
|
||||||
|
|
||||||
requests.post(f'https://api.cloudflare.com/client/v4/zones/{CF_ZONE}/purge_cache', headers=CF_HEADERS, json={'files': [f"{SITE_FULL}/logged_out/"]}, timeout=5)
|
|
||||||
|
|
||||||
g.db.commit()
|
|
||||||
|
|
||||||
return {"message": "Post removed!"}
|
|
||||||
|
|
||||||
|
|
||||||
@app.post("/unremove_post/<post_id>")
|
|
||||||
@limiter.exempt
|
|
||||||
@admin_level_required(2)
|
|
||||||
def unremove_post(post_id, v):
|
|
||||||
post = g.db.query(Submission).filter_by(id=post_id).one_or_none()
|
|
||||||
|
|
||||||
if not post:
|
|
||||||
abort(400)
|
|
||||||
|
|
||||||
if post.state_mod != StateMod.VISIBLE:
|
|
||||||
ma=ModAction(
|
|
||||||
kind="unremove_post",
|
|
||||||
user_id=v.id,
|
|
||||||
target_submission_id=post.id,
|
|
||||||
)
|
|
||||||
g.db.add(ma)
|
|
||||||
|
|
||||||
post.state_mod = StateMod.VISIBLE
|
|
||||||
post.state_mod_set_by = v.username
|
|
||||||
|
|
||||||
g.db.add(post)
|
|
||||||
|
|
||||||
invalidate_cache(frontlist=True)
|
|
||||||
|
|
||||||
v.coins -= 1
|
|
||||||
g.db.add(v)
|
|
||||||
|
|
||||||
g.db.commit()
|
|
||||||
|
|
||||||
return {"message": "Post approved!"}
|
|
||||||
|
|
||||||
|
|
||||||
@app.post("/distinguish/<post_id>")
|
@app.post("/distinguish/<post_id>")
|
||||||
@limiter.exempt
|
@limiter.exempt
|
||||||
@admin_level_required(1)
|
@admin_level_required(1)
|
||||||
|
@ -1307,59 +1241,10 @@ def unsticky_comment(cid, v):
|
||||||
return {"message": "Comment unpinned!"}
|
return {"message": "Comment unpinned!"}
|
||||||
|
|
||||||
|
|
||||||
@app.post("/remove_comment/<c_id>")
|
|
||||||
@limiter.exempt
|
|
||||||
@admin_level_required(2)
|
|
||||||
def api_remove_comment(c_id, v):
|
|
||||||
comment = g.db.query(Comment).filter_by(id=c_id).one_or_none()
|
|
||||||
if not comment:
|
|
||||||
abort(404)
|
|
||||||
|
|
||||||
comment.state_mod = StateMod.REMOVED
|
|
||||||
comment.state_mod_set_by = v.username
|
|
||||||
comment_on_unpublish(comment) # XXX: can cause discrepancies if removal state ≠ filter state
|
|
||||||
ma=ModAction(
|
|
||||||
kind="remove_comment",
|
|
||||||
user_id=v.id,
|
|
||||||
target_comment_id=comment.id,
|
|
||||||
)
|
|
||||||
g.db.add(ma)
|
|
||||||
g.db.commit()
|
|
||||||
return {"message": "Comment removed!"}
|
|
||||||
|
|
||||||
|
|
||||||
@app.post("/unremove_comment/<c_id>")
|
|
||||||
@limiter.exempt
|
|
||||||
@admin_level_required(2)
|
|
||||||
def api_unremove_comment(c_id, v):
|
|
||||||
comment = g.db.query(Comment).filter_by(id=c_id).one_or_none()
|
|
||||||
if not comment: abort(404)
|
|
||||||
|
|
||||||
if comment.state_mod == StateMod.REMOVED:
|
|
||||||
ma=ModAction(
|
|
||||||
kind="unremove_comment",
|
|
||||||
user_id=v.id,
|
|
||||||
target_comment_id=comment.id,
|
|
||||||
)
|
|
||||||
g.db.add(ma)
|
|
||||||
|
|
||||||
comment.state_mod = StateMod.VISIBLE
|
|
||||||
comment.state_mod_set_by = v.username
|
|
||||||
comment_on_publish(comment) # XXX: can cause discrepancies if removal state ≠ filter state
|
|
||||||
|
|
||||||
g.db.add(comment)
|
|
||||||
|
|
||||||
g.db.commit()
|
|
||||||
|
|
||||||
return {"message": "Comment approved!"}
|
|
||||||
|
|
||||||
|
|
||||||
@app.post("/distinguish_comment/<c_id>")
|
@app.post("/distinguish_comment/<c_id>")
|
||||||
@limiter.exempt
|
@limiter.exempt
|
||||||
@admin_level_required(1)
|
@admin_level_required(1)
|
||||||
def admin_distinguish_comment(c_id, v):
|
def admin_distinguish_comment(c_id, v):
|
||||||
|
|
||||||
|
|
||||||
comment = get_comment(c_id, v=v)
|
comment = get_comment(c_id, v=v)
|
||||||
|
|
||||||
if comment.author_id != v.id: abort(403)
|
if comment.author_id != v.id: abort(403)
|
||||||
|
|
|
@ -646,13 +646,12 @@ def visitors(v):
|
||||||
return render_template("viewers.html", v=v, viewers=viewers)
|
return render_template("viewers.html", v=v, viewers=viewers)
|
||||||
|
|
||||||
|
|
||||||
@app.get("/@<username>")
|
@app.get("/@<username>/posts")
|
||||||
@auth_desired
|
@auth_desired
|
||||||
def u_username(username, v=None):
|
def u_username(username, v=None):
|
||||||
u = get_user(username, v=v, include_blocks=True)
|
u = get_user(username, v=v, include_blocks=True)
|
||||||
|
|
||||||
if username != u.username:
|
if username != u.username: return redirect(f'/@{u.username}/posts')
|
||||||
return redirect(SITE_FULL + request.full_path.replace(username, u.username)[:-1])
|
|
||||||
|
|
||||||
if u.reserved:
|
if u.reserved:
|
||||||
if request.headers.get("Authorization") or request.headers.get("xhr"): abort(403, f"That username is reserved for: {u.reserved}")
|
if request.headers.get("Authorization") or request.headers.get("xhr"): abort(403, f"That username is reserved for: {u.reserved}")
|
||||||
|
@ -698,7 +697,7 @@ def u_username(username, v=None):
|
||||||
|
|
||||||
if u.unban_utc:
|
if u.unban_utc:
|
||||||
if request.headers.get("Authorization"): {"data": [x.json for x in listing]}
|
if request.headers.get("Authorization"): {"data": [x.json for x in listing]}
|
||||||
return render_template("userpage.html",
|
return render_template("userpage_submissions.html",
|
||||||
unban=u.unban_string,
|
unban=u.unban_string,
|
||||||
u=u,
|
u=u,
|
||||||
v=v,
|
v=v,
|
||||||
|
@ -712,7 +711,7 @@ def u_username(username, v=None):
|
||||||
|
|
||||||
|
|
||||||
if request.headers.get("Authorization"): return {"data": [x.json for x in listing]}
|
if request.headers.get("Authorization"): return {"data": [x.json for x in listing]}
|
||||||
return render_template("userpage.html",
|
return render_template("userpage_submissions.html",
|
||||||
u=u,
|
u=u,
|
||||||
v=v,
|
v=v,
|
||||||
listing=listing,
|
listing=listing,
|
||||||
|
@ -723,12 +722,13 @@ def u_username(username, v=None):
|
||||||
is_following=(v and u.has_follower(v)))
|
is_following=(v and u.has_follower(v)))
|
||||||
|
|
||||||
|
|
||||||
@app.get("/@<username>/comments")
|
@app.get("/@<username>/")
|
||||||
@auth_desired
|
@auth_desired
|
||||||
def u_username_comments(username, v=None):
|
def u_username_comments(username, v=None):
|
||||||
user = get_user(username, v=v, include_blocks=True)
|
user = get_user(username, v=v, include_blocks=True)
|
||||||
|
|
||||||
if username != user.username: return redirect(f'/@{user.username}/comments')
|
if username != user.username:
|
||||||
|
return redirect(SITE_FULL + request.full_path.replace(username, user.username)[:-1])
|
||||||
u = user
|
u = user
|
||||||
|
|
||||||
if u.reserved:
|
if u.reserved:
|
||||||
|
@ -935,7 +935,8 @@ def saved_posts(v, username):
|
||||||
listing = get_posts(ids, v=v, eager=True)
|
listing = get_posts(ids, v=v, eager=True)
|
||||||
|
|
||||||
if request.headers.get("Authorization"): return {"data": [x.json for x in listing]}
|
if request.headers.get("Authorization"): return {"data": [x.json for x in listing]}
|
||||||
return render_template("userpage.html",
|
return render_template(
|
||||||
|
"userpage_submissions.html",
|
||||||
u=v,
|
u=v,
|
||||||
v=v,
|
v=v,
|
||||||
listing=listing,
|
listing=listing,
|
||||||
|
@ -959,13 +960,15 @@ def saved_comments(v, username):
|
||||||
|
|
||||||
|
|
||||||
if request.headers.get("Authorization"): return {"data": [x.json for x in listing]}
|
if request.headers.get("Authorization"): return {"data": [x.json for x in listing]}
|
||||||
return render_template("userpage_comments.html",
|
return render_template(
|
||||||
|
"userpage_comments.html",
|
||||||
u=v,
|
u=v,
|
||||||
v=v,
|
v=v,
|
||||||
listing=listing,
|
listing=listing,
|
||||||
page=page,
|
page=page,
|
||||||
next_exists=next_exists,
|
next_exists=next_exists,
|
||||||
standalone=True)
|
standalone=True
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
@app.post("/fp/<fp>")
|
@app.post("/fp/<fp>")
|
||||||
|
|
|
@ -65,7 +65,8 @@ def api_vote_post(post_id, new, v):
|
||||||
new = int(new)
|
new = int(new)
|
||||||
|
|
||||||
# get the post
|
# get the post
|
||||||
post = get_post(post_id)
|
post = get_post(post_id, v=v)
|
||||||
|
if getattr(post, 'is_blocking', False): abort(403, "Can't vote on things from users you've blocked")
|
||||||
|
|
||||||
# get the old vote, if we have one
|
# get the old vote, if we have one
|
||||||
vote = g.db.query(Vote).filter_by(user_id=v.id, submission_id=post.id).one_or_none()
|
vote = g.db.query(Vote).filter_by(user_id=v.id, submission_id=post.id).one_or_none()
|
||||||
|
@ -132,7 +133,8 @@ def api_vote_comment(comment_id, new, v):
|
||||||
new = int(new)
|
new = int(new)
|
||||||
|
|
||||||
# get the comment
|
# get the comment
|
||||||
comment = get_comment(comment_id)
|
comment = get_comment(comment_id, v=v)
|
||||||
|
if getattr(comment, 'is_blocking', False): abort(403, "Can't vote on things from users you've blocked")
|
||||||
|
|
||||||
# get the old vote, if we have one
|
# get the old vote, if we have one
|
||||||
vote = g.db.query(CommentVote).filter_by(user_id=v.id, comment_id=comment.id).one_or_none()
|
vote = g.db.query(CommentVote).filter_by(user_id=v.id, comment_id=comment.id).one_or_none()
|
||||||
|
|
|
@ -17,13 +17,13 @@
|
||||||
<h3>Content</h3>
|
<h3>Content</h3>
|
||||||
<ul>
|
<ul>
|
||||||
<li><a href="/admin/image_posts">Image Posts</a></li>
|
<li><a href="/admin/image_posts">Image Posts</a></li>
|
||||||
<li><a href="/admin/reported/posts">Reported Posts/Comments</a></li>
|
<li><a href="/admin/reported/comments">Reported Comments/Posts</a></li>
|
||||||
<li><a href="/admin/removed/posts">Removed Posts/Comments</a></li>
|
<li><a href="/admin/removed/comments">Removed Comments/Posts</a></li>
|
||||||
</ul>
|
</ul>
|
||||||
|
|
||||||
<h3>Filtering</h3>
|
<h3>Filtering</h3>
|
||||||
<ul>
|
<ul>
|
||||||
<li><a href="/admin/filtered/posts">Filtered Posts/Comments</a></li>
|
<li><a href="/admin/filtered/comments">Filtered Comments/Posts</a></li>
|
||||||
</ul>
|
</ul>
|
||||||
|
|
||||||
<h3>Users</h3>
|
<h3>Users</h3>
|
||||||
|
|
|
@ -23,13 +23,13 @@
|
||||||
|
|
||||||
<ul class="nav post-nav py-2">
|
<ul class="nav post-nav py-2">
|
||||||
<li class="nav-item">
|
<li class="nav-item">
|
||||||
<a class="nav-link {% if request.path=="/admin/filtered/posts" %} active{% endif %}" href="/admin/filtered/posts">
|
<a class="nav-link {% if request.path=="/admin/filtered/comments" %} active{% endif %}" href="/admin/filtered/comments">
|
||||||
<div>Posts</div>
|
<div>Comments</div>
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
<li class="nav-item">
|
<li class="nav-item">
|
||||||
<a class="nav-link {% if request.path=="/admin/filtered/comments" %} active{% endif %}" href="/admin/filtered/comments">
|
<a class="nav-link {% if request.path=="/admin/filtered/posts" %} active{% endif %}" href="/admin/filtered/posts">
|
||||||
<div>Comments</div>
|
<div>Posts</div>
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
|
|
|
@ -20,13 +20,13 @@
|
||||||
|
|
||||||
<ul class="nav post-nav py-2">
|
<ul class="nav post-nav py-2">
|
||||||
<li class="nav-item">
|
<li class="nav-item">
|
||||||
<a class="nav-link {% if request.path=="/admin/removed/posts" %} active{% endif %}" href="/admin/removed/posts">
|
<a class="nav-link {% if request.path=="/admin/removed/comments" %} active{% endif %}" href="/admin/removed/comments">
|
||||||
<div>Posts</div>
|
<div>Comments</div>
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
<li class="nav-item">
|
<li class="nav-item">
|
||||||
<a class="nav-link {% if request.path=="/admin/removed/comments" %} active{% endif %}" href="/admin/removed/comments">
|
<a class="nav-link {% if request.path=="/admin/removed/posts" %} active{% endif %}" href="/admin/removed/posts">
|
||||||
<div>Comments</div>
|
<div>Posts</div>
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
|
|
|
@ -20,13 +20,13 @@
|
||||||
|
|
||||||
<ul class="nav post-nav py-2">
|
<ul class="nav post-nav py-2">
|
||||||
<li class="nav-item">
|
<li class="nav-item">
|
||||||
<a class="nav-link {% if request.path=="/admin/reported/posts" %} active{% endif %}" href="/admin/reported/posts">
|
<a class="nav-link {% if request.path=="/admin/reported/comments" %} active{% endif %}" href="/admin/reported/comments">
|
||||||
<div>Posts</div>
|
<div>Comments</div>
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
<li class="nav-item">
|
<li class="nav-item">
|
||||||
<a class="nav-link {% if request.path=="/admin/reported/comments" %} active{% endif %}" href="/admin/reported/comments">
|
<a class="nav-link {% if request.path=="/admin/reported/posts" %} active{% endif %}" href="/admin/reported/posts">
|
||||||
<div>Comments</div>
|
<div>Posts</div>
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
|
|
|
@ -201,23 +201,23 @@
|
||||||
<script src="{{ 'js/comments+submission_listing.js' | asset }}"></script>
|
<script src="{{ 'js/comments+submission_listing.js' | asset }}"></script>
|
||||||
<script src="{{ 'js/comments.js' | asset }}"></script>
|
<script src="{{ 'js/comments.js' | asset }}"></script>
|
||||||
|
|
||||||
|
{# See https://github.com/themotte/rDrama/pull/642#issuecomment-1646649781 for info on this section of the code #}
|
||||||
<script>
|
<script>
|
||||||
{% if p and (not v or v.highlightcomments) %}
|
{% if p and (not v or v.highlightcomments) %}
|
||||||
comments = JSON.parse(localStorage.getItem("comment-counts")) || {}
|
comments = JSON.parse(localStorage.getItem("comment-counts")) || {}
|
||||||
lastCount = comments['{{p.id}}']
|
lastCount = comments['{{p.id}}']
|
||||||
if (lastCount)
|
var commentsToCheck = [
|
||||||
{
|
{% for c in p.comments -%}
|
||||||
{% for c in p.comments %}
|
{%- if not (v and v.id==c.author_id) and not c.voted %}
|
||||||
{% if not (v and v.id==c.author_id) and not c.voted %}
|
[{{c.id}}, {{c.created_utc * 1000}}],
|
||||||
if ({{c.created_utc*1000}} > lastCount.t)
|
{%- endif -%}
|
||||||
try {
|
|
||||||
document.getElementById("comment-{{c.id}}-only").classList.add('unread')
|
|
||||||
document.getElementById("comment-{{c.id}}").querySelector(".comment-user-info").innerHTML += "<span>~new~</span>";
|
|
||||||
}
|
|
||||||
catch(e) {}
|
|
||||||
{% endif %}
|
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
}
|
];
|
||||||
|
|
||||||
|
commentsToCheck = commentsToCheck.filter(comment => comment[1] > lastCount.t)
|
||||||
|
.map(comment => comment[0]);
|
||||||
|
|
||||||
|
if (lastCount) commentsAddUnreadIndicator(commentsToCheck);
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
{% if p and not (request.values and ('context' in request.values)) %}
|
{% if p and not (request.values and ('context' in request.values)) %}
|
||||||
|
@ -250,19 +250,19 @@
|
||||||
{% if p %}
|
{% if p %}
|
||||||
comments = JSON.parse(localStorage.getItem("old-comment-counts")) || {}
|
comments = JSON.parse(localStorage.getItem("old-comment-counts")) || {}
|
||||||
lastCount = comments['{{p.id}}']
|
lastCount = comments['{{p.id}}']
|
||||||
if (lastCount)
|
|
||||||
{
|
var commentsToCheck = [
|
||||||
{% for c in p.comments %}
|
{% for c in p.comments -%}
|
||||||
{% if not (v and v.id==c.author_id) and not c.voted %}
|
{%- if not (v and v.id==c.author_id) and not c.voted %}
|
||||||
if ({{c.created_utc*1000}} > lastCount.t)
|
[{{c.id}}, {{c.created_utc * 1000}}],
|
||||||
try {
|
{%- endif -%}
|
||||||
document.getElementById("comment-{{c.id}}-only").classList.add('unread')
|
|
||||||
document.getElementById("comment-{{c.id}}").querySelector(".comment-user-info").innerHTML += "<span>~new~</span>";
|
|
||||||
}
|
|
||||||
catch(e) {}
|
|
||||||
{% endif %}
|
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
}
|
];
|
||||||
|
|
||||||
|
commentsToCheck = commentsToCheck.filter(comment => comment[1] > lastCount.t)
|
||||||
|
.map(comment => comment[0]);
|
||||||
|
|
||||||
|
if (lastCount) commentsAddUnreadIndicator(commentsToCheck);
|
||||||
{% endif %}
|
{% endif %}
|
||||||
}
|
}
|
||||||
btn.disabled = false;
|
btn.disabled = false;
|
||||||
|
|
|
@ -19,10 +19,12 @@
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
{% if v and v.admin_level >= 2 and c.state_mod == StateMod.FILTERED %}
|
{%- if v and v.admin_level >= PERMS['POST_COMMENT_MODERATION'] -%}
|
||||||
<button class="btn" role="button" id="filter-approve" onclick="filter_new_comment_status({{ c.id }}, 'normal')"><span>Approve</span></button>
|
{%- set show_approve = c.state_mod != StateMod.VISIBLE or "/reported/" in request.path -%}
|
||||||
<button class="btn" role="button" id="filter-remove" onclick="filter_new_comment_status({{ c.id }}, 'removed')"><span>Remove</span></button>
|
{%- set show_remove = c.state_mod != StateMod.REMOVED -%}
|
||||||
{% endif %}
|
<button id="remove-{{c.id}}" class="btn caction py-0 nobackground px-1 text-muted{% if not show_remove %} d-none{% endif %}" role="button" onclick="moderate(false, {{c.id}}, true, 'remove-{{c.id}}', 'remove2-{{c.id}}', 'approve-{{c.id}}', 'approve2-{{c.id}}');"><i class="fas fa-ban"></i>Remove</a>
|
||||||
|
<button id="approve-{{c.id}}" class="btn caction py-0 nobackground px-1 text-muted{% if not show_approve %} d-none{% endif %}" role="button" onclick="moderate(false, {{c.id}}, false, 'remove-{{c.id}}', 'remove2-{{c.id}}', 'approve-{{c.id}}', 'approve2-{{c.id}}');"><i class="fas fa-check"></i>Approve</a>
|
||||||
|
{%- endif -%}
|
||||||
|
|
||||||
{% if v %}
|
{% if v %}
|
||||||
<button style="margin-top:0.2rem" class="btn caction py-0 nobackground px-1 text-muted" data-bs-toggle="dropdown" aria-expanded="false"><i class="fas fa-ellipsis-h fa-fw"></i></button>
|
<button style="margin-top:0.2rem" class="btn caction py-0 nobackground px-1 text-muted" data-bs-toggle="dropdown" aria-expanded="false"><i class="fas fa-ellipsis-h fa-fw"></i></button>
|
||||||
|
@ -45,16 +47,6 @@
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
{% if v.admin_level >= 2 %}
|
|
||||||
{% if "/reported/" in request.path %}
|
|
||||||
<button class="dropdown-item list-inline-item text-success" onclick="approveCommentDesktop('{{c.id}}')"><i class="fas fa-check text-success fa-fw"></i>Approve</button>
|
|
||||||
<button class="dropdown-item list-inline-item text-danger" onclick="removeCommentDesktop('{{c.id}}')"><i class="fas fa-ban text-danger fa-fw"></i>Remove</button>
|
|
||||||
{% else %}
|
|
||||||
<button id="approve-{{c.id}}" class="dropdown-item list-inline-item d-none {% if c.state_mod != StateMod.VISIBLE %}d-md-block{% endif %} text-success" onclick="approveCommentDesktop('{{c.id}}','approve-{{c.id}}','remove-{{c.id}}')"><i class="fas fa-check text-success fa-fw"></i>Approve</button>
|
|
||||||
<button id="remove-{{c.id}}" class="dropdown-item list-inline-item d-none {% if c.state_mod != StateMod.REMOVED %}d-md-block{% endif %} text-danger" onclick="removeCommentDesktop('{{c.id}}','approve-{{c.id}}','remove-{{c.id}}')"><i class="fas fa-ban text-danger fa-fw"></i>Remove</button>
|
|
||||||
{% endif %}
|
|
||||||
{% endif %}
|
|
||||||
|
|
||||||
{% if c.parent_submission and (c.author_id==v.id or v.admin_level >= 2) %}
|
{% if c.parent_submission and (c.author_id==v.id or v.admin_level >= 2) %}
|
||||||
<button id="unmark-{{c.id}}" class="dropdown-item list-inline-item d-none {% if c.over_18 %}d-md-block{% endif %} text-danger" onclick="post_toast3(this,'/toggle_comment_nsfw/{{c.id}}','mark-{{c.id}}','unmark-{{c.id}}')"><i class="fas fa-eye-evil text-danger fa-fw"></i>Unmark +18</button>
|
<button id="unmark-{{c.id}}" class="dropdown-item list-inline-item d-none {% if c.over_18 %}d-md-block{% endif %} text-danger" onclick="post_toast3(this,'/toggle_comment_nsfw/{{c.id}}','mark-{{c.id}}','unmark-{{c.id}}')"><i class="fas fa-eye-evil text-danger fa-fw"></i>Unmark +18</button>
|
||||||
<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="post_toast3(this,'/toggle_comment_nsfw/{{c.id}}','mark-{{c.id}}','unmark-{{c.id}}')"><i class="fas fa-eye-evil text-danger fa-fw"></i>Mark +18</button>
|
<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="post_toast3(this,'/toggle_comment_nsfw/{{c.id}}','mark-{{c.id}}','unmark-{{c.id}}')"><i class="fas fa-eye-evil text-danger fa-fw"></i>Mark +18</button>
|
||||||
|
|
|
@ -27,13 +27,12 @@
|
||||||
<a id="unban2-{{c.id}}" class="{% if not c.author.is_banned %}d-none{% endif %} list-group-item text-success" role="button" onclick="post_toast2(this,'/unban_user/{{c.author_id}}','ban2-{{c.id}}','unban2-{{c.id}}')" data-bs-dismiss="modal"><i class="fas fa-user-minus fa-fw text-success mr-2"></i>Unban user</a>
|
<a id="unban2-{{c.id}}" class="{% if not c.author.is_banned %}d-none{% endif %} list-group-item text-success" role="button" onclick="post_toast2(this,'/unban_user/{{c.author_id}}','ban2-{{c.id}}','unban2-{{c.id}}')" data-bs-dismiss="modal"><i class="fas fa-user-minus fa-fw text-success mr-2"></i>Unban user</a>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
{% if "/reported/" in request.path %}
|
{%- if v and v.admin_level >= PERMS['POST_COMMENT_MODERATION'] -%}
|
||||||
<a class="list-group-item text-danger" role="button" onclick="removeCommentMobile('{{c.id}}')" data-bs-dismiss="modal"><i class="fas fa-ban text-danger mr-2"></i>Remove</a>
|
{%- set show_approve = c.state_mod != StateMod.VISIBLE or "/reported/" in request.path -%}
|
||||||
<a class="list-group-item text-success" role="button" onclick="approveCommentMobile('{{c.id}}')" data-bs-dismiss="modal"><i class="fas fa-check text-success mr-2"></i>Approve</a>
|
{%- set show_remove = c.state_mod == StateMod.VISIBLE -%}
|
||||||
{% else %}
|
<a id="remove2-{{c.id}}" class="dropdown-item list-inline-item text-danger{% if not show_remove %} d-none{% endif %}" role="button" onclick="moderate(false, {{c.id}}, true, 'remove-{{c.id}}', 'remove2-{{c.id}}', 'approve-{{c.id}}', 'approve2-{{c.id}}');"><i class="fas fa-ban"></i>Remove</a>
|
||||||
<a id="remove2-{{c.id}}" class="{% if c.state_mod != StateMod.VISIBLE %}d-none{% endif %} list-group-item text-danger" role="button" onclick="removeCommentMobile('{{c.id}}','approve2-{{c.id}}','remove2-{{c.id}}')" data-bs-dismiss="modal"><i class="fas fa-ban text-danger mr-2"></i>Remove</a>
|
<a id="approve2-{{c.id}}" class="dropdown-item list-inline-item text-success{% if not show_approve %} d-none{% endif %}" role="button" onclick="moderate(false, {{c.id}}, false, 'remove-{{c.id}}', 'remove2-{{c.id}}', 'approve-{{c.id}}', 'approve2-{{c.id}}');"></i>Approve</a>
|
||||||
<a id="approve2-{{c.id}}" class="{% if c.state_mod != StateMod.REMOVED %}d-none{% endif %} list-group-item text-success" role="button" onclick="approveCommentMobile('{{c.id}}','approve2-{{c.id}}','remove2-{{c.id}}')" data-bs-dismiss="modal"><i class="fas fa-check text-success mr-2"></i>Approve</a>
|
{%- endif -%}
|
||||||
{% endif %}
|
|
||||||
|
|
||||||
{% if c.oauth_app %}
|
{% if 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>
|
<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>
|
||||||
|
|
|
@ -58,15 +58,14 @@
|
||||||
<a id="unclub-{{p.id}}" class="dropdown-item {% if not p.club %}d-none{% endif %} list-inline-item text-info" role="button" onclick="post_toast2(this,'/toggle_club/{{p.id}}','club-{{p.id}}','unclub-{{p.id}}')"><i class="fas fa-eye"></i>Unmark club</a>
|
<a id="unclub-{{p.id}}" class="dropdown-item {% if not p.club %}d-none{% endif %} list-inline-item text-info" role="button" onclick="post_toast2(this,'/toggle_club/{{p.id}}','club-{{p.id}}','unclub-{{p.id}}')"><i class="fas fa-eye"></i>Unmark club</a>
|
||||||
{% endif %} #}
|
{% endif %} #}
|
||||||
|
|
||||||
{% if v.admin_level > 1 %}
|
{%- if v and v.admin_level >= PERMS['POST_COMMENT_MODERATION'] -%}
|
||||||
{% if "/reported/" in request.path %}
|
{%- set show_approve = p.state_mod != StateMod.VISIBLE or "/reported/" in request.path -%}
|
||||||
{% if v.id != p.author.id %}<a class="dropdown-item list-inline-item text-danger" role="button" onclick="post_toast(this,'/remove_post/{{p.id}}')"><i class="fas fa-ban"></i>Remove</a>{% endif %}
|
{%- set show_remove = p.state_mod == StateMod.VISIBLE -%}
|
||||||
<a class="dropdown-item list-inline-item text-success" role="button" onclick="post_toast(this,'/unremove_post/{{p.id}}')"><i class="fas fa-check"></i>Approve</a>
|
<a id="remove-{{p.id}}" class="dropdown-item list-inline-item text-danger{% if not show_remove %} d-none{% endif %}" role="button" onclick="moderate(true, {{p.id}}, true, 'remove-{{p.id}}', 'remove2-{{p.id}}', 'approve-{{p.id}}', 'approve2-{{p.id}}');"><i class="fas fa-ban"></i>Remove</a>
|
||||||
{% else %}
|
<a id="approve-{{p.id}}" class="dropdown-item list-inline-item text-success{% if not show_approve %} d-none{% endif %}" role="button" onclick="moderate(true, {{p.id}}, false, 'remove-{{p.id}}', 'remove2-{{p.id}}', 'approve-{{p.id}}', 'approve2-{{p.id}}');"><i class="fas fa-check"></i>Approve</a>
|
||||||
{% if v.id != p.author.id %}<a id="remove-{{p.id}}" class="dropdown-item {% if p.state_mod == StateMod.REMOVED %}d-none{% endif %} list-inline-item text-danger" role="button" onclick="post_toast2(this,'/remove_post/{{p.id}}','remove-{{p.id}}','approve-{{p.id}}')"><i class="fas fa-ban"></i>Remove</a>{% endif %}
|
{%- endif -%}
|
||||||
<a id="approve-{{p.id}}" class="dropdown-item {% if p.state_mod == StateMod.VISIBLE %}d-none{% endif %} list-inline-item text-success" role="button" onclick="post_toast2(this,'/unremove_post/{{p.id}}','remove-{{p.id}}','approve-{{p.id}}')"><i class="fas fa-check"></i>Approve</a>
|
|
||||||
{% endif %}
|
|
||||||
|
|
||||||
|
{% if v.admin_level >= 2 %}
|
||||||
{% if p.oauth_app %}
|
{% if p.oauth_app %}
|
||||||
<a class="dropdown-item list-inline-item" href="{{p.oauth_app.permalink}}"><i class="fas fa-code"></i>API App</a>
|
<a class="dropdown-item list-inline-item" href="{{p.oauth_app.permalink}}"><i class="fas fa-code"></i>API App</a>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
|
@ -20,21 +20,14 @@
|
||||||
<button id="undistinguish2-{{p.id}}" class="{% if not p.distinguish_level %}d-none{% endif %} nobackground btn btn-link btn-block btn-lg text-left text-primary" role="button" onclick="post_toast2(this,'/distinguish/{{p.id}}','distinguish2-{{p.id}}','undistinguish2-{{p.id}}')" data-bs-dismiss="modal"><i class="fas fa-crown text-center text-primary mr-3"></i>Undistinguish</button> #}
|
<button id="undistinguish2-{{p.id}}" class="{% if not p.distinguish_level %}d-none{% endif %} nobackground btn btn-link btn-block btn-lg text-left text-primary" role="button" onclick="post_toast2(this,'/distinguish/{{p.id}}','distinguish2-{{p.id}}','undistinguish2-{{p.id}}')" data-bs-dismiss="modal"><i class="fas fa-crown text-center text-primary mr-3"></i>Undistinguish</button> #}
|
||||||
|
|
||||||
<button id="pin2-{{p.id}}" class="{% if p.stickied %}d-none{% endif %} nobackground btn btn-link btn-block btn-lg text-left text-primary" role="button" onclick="post_toast2(this,'/sticky/{{p.id}}','pin2-{{p.id}}','unpin2-{{p.id}}')" data-bs-dismiss="modal"><i class="fas fa-thumbtack fa-rotate--45 text-center text-primary mr-3"></i>Pin</button>
|
<button id="pin2-{{p.id}}" class="{% if p.stickied %}d-none{% endif %} nobackground btn btn-link btn-block btn-lg text-left text-primary" role="button" onclick="post_toast2(this,'/sticky/{{p.id}}','pin2-{{p.id}}','unpin2-{{p.id}}')" data-bs-dismiss="modal"><i class="fas fa-thumbtack fa-rotate--45 text-center text-primary mr-3"></i>Pin</button>
|
||||||
|
|
||||||
<button id="unpin2-{{p.id}}" class="{% if not p.stickied %}d-none{% endif %} nobackground btn btn-link btn-block btn-lg text-left text-primary" role="button" onclick="post_toast2(this,'/unsticky/{{p.id}}','pin2-{{p.id}}','unpin2-{{p.id}}')" data-bs-dismiss="modal"><i class="fas fa-thumbtack fa-rotate--45 text-center text-primary mr-3"></i>Unpin</button>
|
<button id="unpin2-{{p.id}}" class="{% if not p.stickied %}d-none{% endif %} nobackground btn btn-link btn-block btn-lg text-left text-primary" role="button" onclick="post_toast2(this,'/unsticky/{{p.id}}','pin2-{{p.id}}','unpin2-{{p.id}}')" data-bs-dismiss="modal"><i class="fas fa-thumbtack fa-rotate--45 text-center text-primary mr-3"></i>Unpin</button>
|
||||||
|
|
||||||
{% if "/reported/" in request.path %}
|
{%- if v and v.admin_level >= PERMS['POST_COMMENT_MODERATION'] -%}
|
||||||
<button class="nobackground btn btn-link btn-block btn-lg text-danger text-left" role="button" onclick="post_toast(this,'/remove_post/{{p.id}}')" data-bs-dismiss="modal"><i class="far fa-ban text-center mr-3"></i>Remove</button>
|
{%- set show_approve = p.state_mod != StateMod.VISIBLE or "/reported/" in request.path -%}
|
||||||
<button class="nobackground btn btn-link btn-block btn-lg text-success text-left" role="button" onclick="post_toast(this,'/unremove_post/{{p.id}}')" data-bs-dismiss="modal"><i class="far fa-check text-center mr-3"></i>Approve</button>
|
{%- set show_remove = p.state_mod == StateMod.VISIBLE -%}
|
||||||
{% else %}
|
<a id="remove2-{{p.id}}" class="dropdown-item list-inline-item text-danger{% if not show_remove %} d-none{% endif %}" role="button" onclick="moderate(true, {{p.id}}, true, 'remove-{{p.id}}', 'remove2-{{p.id}}', 'approve-{{p.id}}', 'approve2-{{p.id}}');"><i class="fas fa-ban"></i>Remove</a>
|
||||||
<button id="remove2-{{p.id}}" class="{% if p.state_mod == StateMod.REMOVED %}d-none{% endif %} nobackground btn btn-link btn-block btn-lg text-danger text-left" role="button" onclick="post_toast2(this,'/remove_post/{{p.id}}','remove2-{{p.id}}','approve2-{{p.id}}')" data-bs-dismiss="modal"><i class="far fa-ban text-center mr-3"></i>Remove</button>
|
<a id="approve2-{{p.id}}" class="dropdown-item list-inline-item text-success{% if not show_approve %} d-none{% endif %}" role="button" onclick="moderate(true, {{p.id}}, false, 'remove-{{p.id}}', 'remove2-{{p.id}}', 'approve-{{p.id}}', 'approve2-{{p.id}}');"><i class="fas fa-check"></i>Approve</a>
|
||||||
<button id="approve2-{{p.id}}" class="{% if p.state_mod == StateMod.VISIBLE %}d-none{% endif %} nobackground btn btn-link btn-block btn-lg text-success text-left" role="button" onclick="post_toast2(this,'/unremove_post/{{p.id}}','remove2-{{p.id}}','approve2-{{p.id}}')" data-bs-dismiss="modal"><i class="far fa-check text-center mr-3"></i>Approve</button>
|
{%- endif -%}
|
||||||
{% endif %}
|
|
||||||
|
|
||||||
{% if v and v.admin_level >= 2 and p.state_mod == StateMod.FILTERED %}
|
|
||||||
<button id="mobile-filter-approve-{{p.id}}" class="nobackground btn btn-link btn-block btn-lg text-success text-left" role="button" onclick="filter_new_status({{p.id}}, 'normal')"><i class="far fa-check text-center mr-3"></i>Filter Approve</a>
|
|
||||||
<button id="mobile-filter-remove-{{p.id}}" class="nobackground btn btn-link btn-block btn-lg text-danger text-left" role="button" onclick="filter_new_status({{p.id}}, 'removed')"><i class="far fa-ban text-center mr-3"></i>Filter Remove</a>
|
|
||||||
{% endif %}
|
|
||||||
|
|
||||||
{% if p.oauth_app %}
|
{% if p.oauth_app %}
|
||||||
<a href="{{p.oauth_app.permalink}}"><button class="nobackground btn btn-link btn-block btn-lg text-muted text-left"><i class="far fa-code text-center text-info mr-3"></i>API App</button></a>
|
<a href="{{p.oauth_app.permalink}}"><button class="nobackground btn btn-link btn-block btn-lg text-muted text-left"><i class="far fa-code text-center text-info mr-3"></i>API App</button></a>
|
||||||
|
@ -47,7 +40,6 @@
|
||||||
<button id="ban2-{{p.id}}" data-bs-dismiss="modal" data-bs-toggle="modal" data-bs-target="#banModal" onclick="banModal('/post/{{p.id}}', '{{p.author.id}}', '{{p.author_name}}')" class="{% if p.author.is_suspended %}d-none{% endif %} nobackground btn btn-link btn-block btn-lg text-danger text-left" role="button"><i class="fas fa-user-minus mr-3"></i>Ban user</button>
|
<button id="ban2-{{p.id}}" data-bs-dismiss="modal" data-bs-toggle="modal" data-bs-target="#banModal" onclick="banModal('/post/{{p.id}}', '{{p.author.id}}', '{{p.author_name}}')" class="{% if p.author.is_suspended %}d-none{% endif %} nobackground btn btn-link btn-block btn-lg text-danger text-left" role="button"><i class="fas fa-user-minus mr-3"></i>Ban user</button>
|
||||||
<button id="unban2-{{p.id}}" class="{% if not p.author.is_suspended %}d-none{% endif %} nobackground btn btn-link btn-block btn-lg text-success text-left" role="button" onclick="post_toast2(this,'/unban_user/{{p.author_id}}','ban2-{{p.id}}','unban2-{{p.id}}')" data-bs-dismiss="modal"><i class="fas fa-user-minus mr-3"></i>Unban user</button>
|
<button id="unban2-{{p.id}}" class="{% if not p.author.is_suspended %}d-none{% endif %} nobackground btn btn-link btn-block btn-lg text-success text-left" role="button" onclick="post_toast2(this,'/unban_user/{{p.author_id}}','ban2-{{p.id}}','unban2-{{p.id}}')" data-bs-dismiss="modal"><i class="fas fa-user-minus mr-3"></i>Unban user</button>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -11,7 +11,7 @@
|
||||||
</a>
|
</a>
|
||||||
|
|
||||||
<div class="flex-grow-1 d-fl d-none d-md-block {% if not v %}pad{% endif %}">
|
<div class="flex-grow-1 d-fl d-none d-md-block {% if not v %}pad{% endif %}">
|
||||||
<form id="searchform" class="form-inline search flex-nowrap mx-0 mx-lg-auto" {% if err %}style="margin-right:40rem!important"{% endif %} action="{% if request.path.startswith('/search') %}{{request.path}}{% else %}/search/posts/{% endif %}" method="get">
|
<form id="searchform" class="form-inline search flex-nowrap mx-0 mx-lg-auto" {% if err %}style="margin-right:40rem!important"{% endif %} action="{% if request.path.startswith('/search') %}{{request.path}}{% else %}/search/comments/{% endif %}" method="get">
|
||||||
<input autocomplete="off" class="form-control w-100" placeholder="Search" aria-label="Search" name="q" value="{{request.values.get('q', '')}}">
|
<input autocomplete="off" class="form-control w-100" placeholder="Search" aria-label="Search" name="q" value="{{request.values.get('q', '')}}">
|
||||||
<span class="input-group-append">
|
<span class="input-group-append">
|
||||||
<span class="input-group-text border-0 bg-transparent" style="margin-left: -2.5rem; cursor: pointer;" onclick="document.getElementById('searchform').submit()">
|
<span class="input-group-text border-0 bg-transparent" style="margin-left: -2.5rem; cursor: pointer;" onclick="document.getElementById('searchform').submit()">
|
||||||
|
|
|
@ -61,10 +61,10 @@
|
||||||
<div class="flex-row box-shadow-bottom d-flex justify-content-center justify-content-md-between align-items-center">
|
<div class="flex-row box-shadow-bottom d-flex justify-content-center justify-content-md-between align-items-center">
|
||||||
<ul class="nav settings-nav">
|
<ul class="nav settings-nav">
|
||||||
<li class="nav-item">
|
<li class="nav-item">
|
||||||
<a class="nav-link{% if '/posts/' in request.path %} active{% endif %}" href="/search/posts/?sort={{sort}}&q={{query | urlencode}}&t={{t}}">Posts</a>
|
<a class="nav-link{% if '/comments/' in request.path %} active{% endif %}" href="/search/comments/?sort={{sort}}&q={{query | urlencode}}&t={{t}}">Comments</a>
|
||||||
</li>
|
</li>
|
||||||
<li class="nav-item">
|
<li class="nav-item">
|
||||||
<a class="nav-link{% if '/comments/' in request.path %} active{% endif %}" href="/search/comments/?sort={{sort}}&q={{query | urlencode}}&t={{t}}">Comments</a>
|
<a class="nav-link{% if '/posts/' in request.path %} active{% endif %}" href="/search/posts/?sort={{sort}}&q={{query | urlencode}}&t={{t}}">Posts</a>
|
||||||
</li>
|
</li>
|
||||||
<li class="nav-item">
|
<li class="nav-item">
|
||||||
<a class="nav-link{% if '/users/' in request.path %} active{% endif %}" href="/search/users/?sort={{sort}}&q={{query | urlencode}}&t={{t}}">Users</a>
|
<a class="nav-link{% if '/users/' in request.path %} active{% endif %}" href="/search/users/?sort={{sort}}&q={{query | urlencode}}&t={{t}}">Users</a>
|
||||||
|
|
|
@ -20,7 +20,6 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
||||||
<div class="d-lg-flex border-bottom">
|
<div class="d-lg-flex border-bottom">
|
||||||
<div class="title w-lg-25">
|
<div class="title w-lg-25">
|
||||||
<label for="highlightcomments">Highlight New Comments</label>
|
<label for="highlightcomments">Highlight New Comments</label>
|
||||||
|
@ -35,7 +34,6 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
||||||
<div class="d-lg-flex border-bottom">
|
<div class="d-lg-flex border-bottom">
|
||||||
<div class="title w-lg-25">
|
<div class="title w-lg-25">
|
||||||
<label for="theme">Website Theme</label>
|
<label for="theme">Website Theme</label>
|
||||||
|
@ -77,8 +75,8 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<h2 class="h5">Profile Banner</h2>
|
|
||||||
|
|
||||||
|
<h2 class="h5">Profile Banner</h2>
|
||||||
<div class="settings-section rounded">
|
<div class="settings-section rounded">
|
||||||
<div class="d-flex">
|
<div class="d-flex">
|
||||||
<div class="title w-lg-75 text-md-center">
|
<div class="title w-lg-75 text-md-center">
|
||||||
|
@ -112,10 +110,13 @@
|
||||||
<input autocomplete="off" type="text" readonly="" class="form-control copy-link" id="referral_code" value="{{SITE_FULL}}/signup?ref={{v.username}}" data-clipboard-text="{{SITE_FULL}}/signup?ref={{v.username}}">
|
<input autocomplete="off" type="text" readonly="" class="form-control copy-link" id="referral_code" value="{{SITE_FULL}}/signup?ref={{v.username}}" data-clipboard-text="{{SITE_FULL}}/signup?ref={{v.username}}">
|
||||||
<span class="input-group-append" data-bs-toggle="tooltip" data-bs-placement="top" title="You have referred {{v.referral_count}} user{{'s' if v.referral_count != 1 else ''}} so far. {% if v.referral_count==0 %}¯\_(ツ)_/¯{% elif v.referral_count>10%}Wow!{% endif %}">
|
<span class="input-group-append" data-bs-toggle="tooltip" data-bs-placement="top" title="You have referred {{v.referral_count}} user{{'s' if v.referral_count != 1 else ''}} so far. {% if v.referral_count==0 %}¯\_(ツ)_/¯{% elif v.referral_count>10%}Wow!{% endif %}">
|
||||||
<span class="input-group-text text-primary border-0">
|
<span class="input-group-text text-primary border-0">
|
||||||
<i class="far fa-user mr-1" aria-hidden="true"></i>{{v.referral_count}}</span>
|
<i class="far fa-user mr-1" aria-hidden="true"></i>{{v.referral_count}}
|
||||||
|
</span>
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="text-small-extra text-muted mt-3">Share this link with a friend. {% if v.referral_count==0 %} When they sign up, you'll get the bronze recruitment badge.{% elif v.referral_count<10 %} When you refer 10 friends, you'll receive the silver recruitment badge.{% elif v.referral_count<100 %} When you refer 100 friends, you'll receive the gold recruitment badge.{% endif %}</div>
|
<div class="text-small-extra text-muted mt-3">
|
||||||
|
Share this link with a friend. {% if v.referral_count==0 %} When they sign up, you'll get the bronze recruitment badge.{% elif v.referral_count<10 %} When you refer 10 friends, you'll receive the silver recruitment badge.{% elif v.referral_count<100 %} When you refer 100 friends, you'll receive the gold recruitment badge.{% endif %}
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -138,7 +139,6 @@
|
||||||
<label class="text-black w-lg-25">Username</label>
|
<label class="text-black w-lg-25">Username</label>
|
||||||
<div class="w-lg-100">
|
<div class="w-lg-100">
|
||||||
<p>Your original username will always stay reserved for you: <code>{{v.original_username}}</code></p>
|
<p>Your original username will always stay reserved for you: <code>{{v.original_username}}</code></p>
|
||||||
|
|
||||||
<form action="/settings/name_change" method="post">
|
<form action="/settings/name_change" method="post">
|
||||||
{{forms.formkey(v)}}
|
{{forms.formkey(v)}}
|
||||||
<input autocomplete="off" type="text" name="name" class="form-control" value="{{v.username}}">
|
<input autocomplete="off" type="text" name="name" class="form-control" value="{{v.username}}">
|
||||||
|
@ -193,7 +193,6 @@
|
||||||
<label class="btn btn-secondary text-capitalize mr-2 mt-2 mb-0">Update<input autocomplete="off" type="text" for="color-code" onclick="form.submit()" hidden=""></label>
|
<label class="btn btn-secondary text-capitalize mr-2 mt-2 mb-0">Update<input autocomplete="off" type="text" for="color-code" onclick="form.submit()" hidden=""></label>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{% if v.verified %}
|
{% if v.verified %}
|
||||||
|
@ -202,7 +201,6 @@
|
||||||
<div class="d-flex">
|
<div class="d-flex">
|
||||||
<form action="/settings/verifiedcolor" id="verifiedcolor-form" method="post" class="color-picker" style="line-height: 0">
|
<form action="/settings/verifiedcolor" id="verifiedcolor-form" method="post" class="color-picker" style="line-height: 0">
|
||||||
{{forms.formkey(v)}}
|
{{forms.formkey(v)}}
|
||||||
|
|
||||||
{% for verifiedcolor in COLORS %}
|
{% for verifiedcolor in COLORS %}
|
||||||
<input autocomplete="off" type="radio" name="verifiedcolor" id="verifiedcolor-{{verifiedcolor}}" value="{{verifiedcolor}}" {% if v.verifiedcolor == verifiedcolor %}checked{% endif %} onclick="document.getElementById('verifiedcolor-form').submit()">
|
<input autocomplete="off" type="radio" name="verifiedcolor" id="verifiedcolor-{{verifiedcolor}}" value="{{verifiedcolor}}" {% if v.verifiedcolor == verifiedcolor %}checked{% endif %} onclick="document.getElementById('verifiedcolor-form').submit()">
|
||||||
<label class="color-radio" for="verifiedcolor-{{verifiedcolor}}">
|
<label class="color-radio" for="verifiedcolor-{{verifiedcolor}}">
|
||||||
|
@ -215,9 +213,7 @@
|
||||||
</span>
|
</span>
|
||||||
</label>
|
</label>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
|
|
||||||
</form>
|
</form>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<p class="text-small mb-2">Or type a color code:</p>
|
<p class="text-small mb-2">Or type a color code:</p>
|
||||||
|
@ -228,7 +224,6 @@
|
||||||
<label class="btn btn-secondary text-capitalize mr-2 mt-2 mb-0">Update<input autocomplete="off" type="text" for="color-code" onclick="form.submit()" hidden=""></label>
|
<label class="btn btn-secondary text-capitalize mr-2 mt-2 mb-0">Update<input autocomplete="off" type="text" for="color-code" onclick="form.submit()" hidden=""></label>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
|
@ -279,7 +274,6 @@
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="d-lg-flex border-bottom">
|
<div class="d-lg-flex border-bottom">
|
||||||
<div class="title w-lg-25">
|
<div class="title w-lg-25">
|
||||||
<label for="privateswitch">Private Mode</label>
|
<label for="privateswitch">Private Mode</label>
|
||||||
|
@ -308,8 +302,5 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<script src="{{ 'js/settings_profile.js' | asset }}"></script>
|
<script src="{{ 'js/settings_profile.js' | asset }}"></script>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
|
@ -489,19 +489,19 @@
|
||||||
|
|
||||||
comments = JSON.parse(localStorage.getItem("old-comment-counts")) || {}
|
comments = JSON.parse(localStorage.getItem("old-comment-counts")) || {}
|
||||||
lastCount = comments['{{p.id}}']
|
lastCount = comments['{{p.id}}']
|
||||||
if (lastCount)
|
|
||||||
{
|
var commentsToCheck = [
|
||||||
{% for c in p.comments %}
|
{% for c in p.comments -%}
|
||||||
{% if not (v and v.id==c.author_id) and not c.voted %}
|
{% if not (v and v.id==c.author_id) and not c.voted %}
|
||||||
if ({{c.created_utc*1000}} > lastCount.t)
|
[{{c.id}}, {{c.created_utc * 1000}}],
|
||||||
try {
|
{%- endif -%}
|
||||||
document.getElementById("comment-{{c.id}}-only").classList.add('unread')
|
|
||||||
document.getElementById("comment-{{c.id}}").querySelector(".comment-user-info").innerHTML += "<span>~new~</span>";
|
|
||||||
}
|
|
||||||
catch(e) {}
|
|
||||||
{% endif %}
|
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
}
|
];
|
||||||
|
|
||||||
|
commentsToCheck = commentsToCheck.filter(comment => comment[1] > lastCount.t)
|
||||||
|
.map(comment => comment[0]);
|
||||||
|
|
||||||
|
if (lastCount) commentsAddUnreadIndicator(commentsToCheck);
|
||||||
|
|
||||||
collapsedCommentStorageApply();
|
collapsedCommentStorageApply();
|
||||||
}
|
}
|
||||||
|
|
|
@ -520,23 +520,23 @@
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
|
{% block userpage_nav %}
|
||||||
<div id="profilecontent" class="row no-gutters">
|
<div id="profilecontent" class="row no-gutters">
|
||||||
<div class="col">
|
<div class="col">
|
||||||
<div class="flex-row box-shadow-bottom d-flex justify-content-center justify-content-md-between align-items-center">
|
<div class="flex-row box-shadow-bottom d-flex justify-content-center justify-content-md-between align-items-center">
|
||||||
<ul class="nav settings-nav">
|
<ul class="nav settings-nav">
|
||||||
<li class="nav-item">
|
<li class="nav-item">
|
||||||
<a class="nav-link {% if not 'saved' in request.path %}active{% endif %}" style="font-size: .9rem !important; padding: .75rem .4rem !important" href="/@{{u.username}}">Posts <span class="count">({{u.post_count}})</span></a>
|
<a class="nav-link {% if 'posts' not in request.path and not 'saved' in request.path %}active{% endif %}" style="font-size: .9rem !important; padding: .75rem .4rem !important" href="/@{{u.username}}">Comments <span class="count">({{u.comment_count}})</span></a>
|
||||||
</li>
|
</li>
|
||||||
<li class="nav-item">
|
<li class="nav-item">
|
||||||
<a class="nav-link" style="font-size: .9rem !important; padding: .75rem .4rem !important" href="/@{{u.username}}/comments">Comments <span class="count">({{u.comment_count}})</span></a>
|
<a class="nav-link {% if 'posts' in request.path and not 'saved' in request.path %}active{% endif %}" style="font-size: .9rem !important; padding: .75rem .4rem !important" href="/@{{u.username}}/posts">Posts <span class="count">({{u.post_count}})</span></a>
|
||||||
</li>
|
</li>
|
||||||
{% if u.id == v.id %}
|
{% if u.id == v.id %}
|
||||||
<li class="nav-item">
|
<li class="nav-item">
|
||||||
<a class="nav-link {% if 'saved' in request.path %}active{% endif %}" style="font-size: .9rem !important; padding: .75rem .4rem !important" href="/@{{u.username}}/saved/posts">Saved Posts <span class="count">({{u.saved_count}})</span></a>
|
<a class="nav-link {% if 'posts' not in request.path and 'saved' in request.path %}active{% endif %}" style="font-size: .9rem !important; padding: .75rem .4rem !important" href="/@{{u.username}}/saved/comments">Saved Comments <span class="count">({{u.saved_comment_count}})</span></a>
|
||||||
</li>
|
</li>
|
||||||
<li class="nav-item">
|
<li class="nav-item">
|
||||||
<a class="nav-link" style="font-size: .9rem !important; padding: .75rem .4rem !important" href="/@{{u.username}}/saved/comments">Saved Comments <span class="count">({{u.saved_comment_count}})</span></a>
|
<a class="nav-link {% if 'posts' in request.path and 'saved' in request.path %}active{% endif %}" style="font-size: .9rem !important; padding: .75rem .4rem !important" href="/@{{u.username}}/saved/posts">Saved Posts <span class="count">({{u.saved_count}})</span></a>
|
||||||
</li>
|
</li>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</ul>
|
</ul>
|
||||||
|
@ -575,18 +575,8 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
{% endblock %}
|
||||||
<div class="row no-gutters {% if listing %}mt-md-3{% elif not listing %}my-md-3{% endif %}" style="margin-top: 10px;">
|
{% block userpage_content required %}{% endblock %}
|
||||||
|
|
||||||
<div class="col">
|
|
||||||
|
|
||||||
<div class="posts">
|
|
||||||
{% include "submission_listing.html" %}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{% if v %}
|
{% if v %}
|
||||||
<div id='tax' class="d-none">{% if v.patron or u.patron or v.alts_patron or u.alts_patron %}0{% else %}0.03{% endif %}</div>
|
<div id='tax' class="d-none">{% if v.patron or u.patron or v.alts_patron or u.alts_patron %}0{% else %}0.03{% endif %}</div>
|
||||||
|
|
|
@ -1,67 +1,7 @@
|
||||||
{% extends "userpage.html" %}
|
{% extends "userpage.html" %}
|
||||||
{%- import 'component/sorting_time.html' as sorting_time -%}
|
{% block userpage_content %}
|
||||||
|
|
||||||
{% 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">
|
|
||||||
<li class="nav-item">
|
|
||||||
<a class="nav-link" style="font-size: .9rem !important; padding: .75rem .4rem !important" href="/@{{u.username}}">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 %}" style="font-size: .9rem !important; padding: .75rem .4rem !important" 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" style="font-size: .9rem !important; padding: .75rem .4rem !important" 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 %}" style="font-size: .9rem !important; padding: .75rem .4rem !important" href="/@{{u.username}}/saved/comments">Saved Comments <span class="count">({{u.saved_comment_count}})</span></a>
|
|
||||||
</li>
|
|
||||||
{% endif %}
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{% if not "saved" in request.full_path %}
|
|
||||||
<div class="d-flex justify-content-between align-items-center" style="padding-top:10px">
|
|
||||||
|
|
||||||
<div class="d-flex align-items-center">
|
|
||||||
<div class="text-small font-weight-bold mr-2"></div>
|
|
||||||
<div class="dropdown dropdown-actions">
|
|
||||||
<button class="btn btn-secondary dropdown-toggle" role="button" id="dropdownMenuButton" data-bs-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
|
|
||||||
{% if t=="hour" %}<i class="fas fa-clock mr-1"></i>
|
|
||||||
{% elif t=="day" %}<i class="fas fa-calendar-day mr-1"></i>
|
|
||||||
{% elif t=="week" %}<i class="fas fa-calendar-week mr-1"></i>
|
|
||||||
{% elif t=="month" %}<i class="fas fa-calendar-alt mr-1"></i>
|
|
||||||
{% elif t=="year" %}<i class="fas fa-calendar mr-1"></i>
|
|
||||||
{% elif t=="all" %}<i class="fas fa-infinity mr-1"></i>
|
|
||||||
{% endif %}
|
|
||||||
{{t | capitalize}}
|
|
||||||
</button>
|
|
||||||
<div class="dropdown-menu" aria-labelledby="dropdownMenuButton" x-placement="bottom-start" style="position: absolute; will-change: transform; top: 0px; left: 0px; transform: translate3d(0px, 31px, 0px);">
|
|
||||||
{% if t != "hour" %}<a class="dropdown-item" href="?sort={{sort}}&t=hour"><i class="fas fa-clock mr-2"></i>Hour</a>{% endif %}
|
|
||||||
{% if t != "day" %}<a class="dropdown-item" href="?sort={{sort}}&t=day"><i class="fas fa-calendar-day mr-2"></i>Day</a>{% endif %}
|
|
||||||
{% if t != "week" %}<a class="dropdown-item" href="?sort={{sort}}&t=week"><i class="fas fa-calendar-week mr-2"></i>Week</a>{% endif %}
|
|
||||||
{% if t != "month" %}<a class="dropdown-item" href="?sort={{sort}}&t=month"><i class="fas fa-calendar-alt mr-2"></i>Month</a>{% endif %}
|
|
||||||
{% if t != "year" %}<a class="dropdown-item" href="?sort={{sort}}&t=year"><i class="fas fa-calendar mr-2"></i>Year</a>{% endif %}
|
|
||||||
{% if t != "all" %}<a class="dropdown-item" href="?sort={{sort}}&t=all"><i class="fas fa-infinity mr-2"></i>All</a>{% endif %}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="text-small font-weight-bold ml-3 mr-2"></div>
|
|
||||||
{{sorting_time.sort_dropdown(sort, t, SORTS_COMMENTS)}}
|
|
||||||
</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="row no-gutters {% if listing %}mt-md-3{% elif not listing %}my-md-3{% endif %}" style="margin-top: 10px;">
|
||||||
|
|
||||||
<div class="col">
|
<div class="col">
|
||||||
|
|
||||||
{% if listing %}
|
{% if listing %}
|
||||||
<div class="posts p-3 p-md-0">
|
<div class="posts p-3 p-md-0">
|
||||||
{% with comments=listing %}
|
{% with comments=listing %}
|
||||||
|
@ -88,11 +28,4 @@
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{% if v %}
|
|
||||||
<div id='tax' class="d-none">{% if v.patron or u.patron %}0{% else %}0.03{% endif %}</div>
|
|
||||||
<script src="{{ 'js/userpage_v.js' | asset }}"></script>
|
|
||||||
<div id="username" class="d-none">{{u.username}}</div>
|
|
||||||
{% endif %}
|
|
||||||
|
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
10
files/templates/userpage_submissions.html
Normal file
10
files/templates/userpage_submissions.html
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
{% extends "userpage.html" %}
|
||||||
|
{% block userpage_content %}
|
||||||
|
<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="posts">
|
||||||
|
{% include "submission_listing.html" %}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% endblock %}
|
|
@ -0,0 +1,25 @@
|
||||||
|
"""Rename approve mod actions
|
||||||
|
|
||||||
|
Revision ID: a23fe2f1515c
|
||||||
|
Revises: 7ae4658467d7
|
||||||
|
Create Date: 2023-07-22 14:37:20.485816+00:00
|
||||||
|
|
||||||
|
"""
|
||||||
|
from alembic import op
|
||||||
|
|
||||||
|
|
||||||
|
# revision identifiers, used by Alembic.
|
||||||
|
revision = 'a23fe2f1515c'
|
||||||
|
down_revision = '7ae4658467d7'
|
||||||
|
branch_labels = None
|
||||||
|
depends_on = None
|
||||||
|
|
||||||
|
|
||||||
|
def upgrade():
|
||||||
|
op.execute("UPDATE modactions SET kind='approve_post' WHERE kind='unremove_post';")
|
||||||
|
op.execute("UPDATE modactions SET kind='approve_comment' WHERE kind='unremove_comment';")
|
||||||
|
|
||||||
|
|
||||||
|
def downgrade():
|
||||||
|
op.execute("UPDATE modactions SET kind='unremove_post' WHERE kind='approve_post';")
|
||||||
|
op.execute("UPDATE modactions SET kind='unremove_comment' WHERE kind='approve_comment';")
|
Loading…
Add table
Add a link
Reference in a new issue