Rejigger the Mod/Report state system.
This commit is contained in:
parent
31ebdd0213
commit
7266c7887c
36 changed files with 490 additions and 222 deletions
|
@ -174,6 +174,9 @@ div.deleted {
|
||||||
div.deleted.banned {
|
div.deleted.banned {
|
||||||
background-color: var(--gray) !important;
|
background-color: var(--gray) !important;
|
||||||
}
|
}
|
||||||
|
div.deleted.removed {
|
||||||
|
background-color: var(--gray) !important;
|
||||||
|
}
|
||||||
.comment-anchor:target, .unread {
|
.comment-anchor:target, .unread {
|
||||||
background: #2280B310 !important;
|
background: #2280B310 !important;
|
||||||
}
|
}
|
||||||
|
|
|
@ -4336,6 +4336,9 @@ div.deleted {
|
||||||
div.deleted.banned {
|
div.deleted.banned {
|
||||||
background-color: #964000 !important;
|
background-color: #964000 !important;
|
||||||
}
|
}
|
||||||
|
div.deleted.removed {
|
||||||
|
background-color: #964000 !important;
|
||||||
|
}
|
||||||
.text-admin {
|
.text-admin {
|
||||||
color: var(--primary);
|
color: var(--primary);
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,6 +7,7 @@ from sqlalchemy import *
|
||||||
from sqlalchemy.orm import relationship
|
from sqlalchemy.orm import relationship
|
||||||
|
|
||||||
from files.classes.base import CreatedBase
|
from files.classes.base import CreatedBase
|
||||||
|
from files.classes.visstate import StateMod, StateReport
|
||||||
from files.helpers.config.const import *
|
from files.helpers.config.const import *
|
||||||
from files.helpers.config.environment import SCORE_HIDING_TIME_HOURS, SITE_FULL
|
from files.helpers.config.environment import SCORE_HIDING_TIME_HOURS, SITE_FULL
|
||||||
from files.helpers.content import (ModerationState, body_displayed,
|
from files.helpers.content import (ModerationState, body_displayed,
|
||||||
|
@ -27,11 +28,9 @@ class Comment(CreatedBase):
|
||||||
author_id = Column(Integer, ForeignKey("users.id"), nullable=False)
|
author_id = Column(Integer, ForeignKey("users.id"), nullable=False)
|
||||||
parent_submission = Column(Integer, ForeignKey("submissions.id"))
|
parent_submission = Column(Integer, ForeignKey("submissions.id"))
|
||||||
edited_utc = Column(Integer, default=0, nullable=False)
|
edited_utc = Column(Integer, default=0, nullable=False)
|
||||||
is_banned = Column(Boolean, default=False, nullable=False)
|
|
||||||
ghost = Column(Boolean, default=False, nullable=False)
|
ghost = Column(Boolean, default=False, nullable=False)
|
||||||
bannedfor = Column(Boolean)
|
bannedfor = Column(Boolean)
|
||||||
distinguish_level = Column(Integer, default=0, nullable=False)
|
distinguish_level = Column(Integer, default=0, nullable=False)
|
||||||
is_approved = Column(Integer, ForeignKey("users.id"))
|
|
||||||
level = Column(Integer, default=1, nullable=False)
|
level = Column(Integer, default=1, nullable=False)
|
||||||
parent_comment_id = Column(Integer, ForeignKey("comments.id"))
|
parent_comment_id = Column(Integer, ForeignKey("comments.id"))
|
||||||
top_comment_id = Column(Integer)
|
top_comment_id = Column(Integer)
|
||||||
|
@ -47,20 +46,17 @@ class Comment(CreatedBase):
|
||||||
descendant_count = Column(Integer, default=0, nullable=False)
|
descendant_count = Column(Integer, default=0, nullable=False)
|
||||||
body = Column(Text)
|
body = Column(Text)
|
||||||
body_html = Column(Text, nullable=False)
|
body_html = Column(Text, nullable=False)
|
||||||
ban_reason = Column(String)
|
|
||||||
filter_state = Column(String, nullable=False)
|
|
||||||
volunteer_janitor_badness = Column(Float, default=0.5, nullable=False)
|
volunteer_janitor_badness = Column(Float, default=0.5, nullable=False)
|
||||||
|
|
||||||
# Visibility states here
|
# Visibility states here
|
||||||
state_user_deleted_utc = Column(DateTime(timezone=True), nullable=True) # null if it hasn't been deleted by the user
|
state_user_deleted_utc = Column(DateTime(timezone=True), nullable=True) # null if it hasn't been deleted by the user
|
||||||
# TBD: state_mod
|
state_mod = Column(Enum(StateMod), default=StateMod.Filtered, nullable=False) # default to Filtered just to partially neuter possible exploits
|
||||||
# TBD: state_mod_set_by
|
state_mod_set_by = Column(String, nullable=True) # This should *really* be a User.id, but I don't want to mess with the required refactoring at the moment - it's extra hard because it could potentially be a lot of extra either data or queries
|
||||||
# TBD: state_report
|
state_report = Column(Enum(StateReport), default=StateReport.Unreported, nullable=False)
|
||||||
|
|
||||||
Index('comment_parent_index', parent_comment_id)
|
Index('comment_parent_index', parent_comment_id)
|
||||||
Index('comment_post_id_index', parent_submission)
|
Index('comment_post_id_index', parent_submission)
|
||||||
Index('comments_user_index', author_id)
|
Index('comments_user_index', author_id)
|
||||||
Index('fki_comment_approver_fkey', is_approved)
|
|
||||||
Index('fki_comment_sentto_fkey', sentto)
|
Index('fki_comment_sentto_fkey', sentto)
|
||||||
|
|
||||||
oauth_app = relationship("OauthApp", viewonly=True)
|
oauth_app = relationship("OauthApp", viewonly=True)
|
||||||
|
@ -79,11 +75,6 @@ class Comment(CreatedBase):
|
||||||
viewonly=True)
|
viewonly=True)
|
||||||
notes = relationship("UserNote", back_populates="comment")
|
notes = relationship("UserNote", back_populates="comment")
|
||||||
|
|
||||||
def __init__(self, *args, **kwargs):
|
|
||||||
if 'filter_state' not in kwargs:
|
|
||||||
kwargs['filter_state'] = 'normal'
|
|
||||||
super().__init__(*args, **kwargs)
|
|
||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
return f"<{self.__class__.__name__}(id={self.id})>"
|
return f"<{self.__class__.__name__}(id={self.id})>"
|
||||||
|
|
||||||
|
@ -171,13 +162,13 @@ class Comment(CreatedBase):
|
||||||
if not self.parent_submission:
|
if not self.parent_submission:
|
||||||
return sorted((x for x in self.child_comments
|
return sorted((x for x in self.child_comments
|
||||||
if x.author
|
if x.author
|
||||||
and (x.filter_state not in ('filtered', 'removed') or x.author_id == author_id)
|
and (x.state_mod == StateMod.Visible or x.author_id == author_id)
|
||||||
and not x.author.shadowbanned),
|
and not x.author.shadowbanned),
|
||||||
key=lambda x: x.created_utc)
|
key=lambda x: x.created_utc)
|
||||||
return sorted((x for x in self.child_comments
|
return sorted((x for x in self.child_comments
|
||||||
if x.author
|
if x.author
|
||||||
and not x.author.shadowbanned
|
and not x.author.shadowbanned
|
||||||
and (x.filter_state not in ('filtered', 'removed') or x.author_id == author_id)),
|
and (x.state_mod == StateMod.Visible or x.author_id == author_id)),
|
||||||
key=lambda x: x.created_utc, reverse=True)
|
key=lambda x: x.created_utc, reverse=True)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
|
@ -234,8 +225,6 @@ class Comment(CreatedBase):
|
||||||
'is_bot': self.is_bot,
|
'is_bot': self.is_bot,
|
||||||
'created_utc': self.created_utc,
|
'created_utc': self.created_utc,
|
||||||
'edited_utc': self.edited_utc or 0,
|
'edited_utc': self.edited_utc or 0,
|
||||||
'is_banned': bool(self.is_banned),
|
|
||||||
'state_user_deleted_utc': self.state_user_deleted_utc,
|
|
||||||
'is_nsfw': self.over_18,
|
'is_nsfw': self.over_18,
|
||||||
'permalink': f'/comment/{self.id}',
|
'permalink': f'/comment/{self.id}',
|
||||||
'is_pinned': self.is_pinned,
|
'is_pinned': self.is_pinned,
|
||||||
|
@ -248,21 +237,21 @@ class Comment(CreatedBase):
|
||||||
'flags': flags,
|
'flags': flags,
|
||||||
}
|
}
|
||||||
|
|
||||||
if self.ban_reason:
|
|
||||||
data["ban_reason"]=self.ban_reason
|
|
||||||
|
|
||||||
return data
|
return data
|
||||||
|
|
||||||
def award_count(self, kind):
|
def award_count(self, kind):
|
||||||
if not FEATURES['AWARDS']: return 0
|
if not FEATURES['AWARDS']: return 0
|
||||||
return len([x for x in self.awards if x.kind == kind])
|
return len([x for x in self.awards if x.kind == kind])
|
||||||
|
|
||||||
|
def is_visible(self):
|
||||||
|
return self.state_mod == StateMod.Visible
|
||||||
|
|
||||||
@property
|
@property
|
||||||
@lazy
|
@lazy
|
||||||
def json_core(self):
|
def json_core(self):
|
||||||
if self.is_banned:
|
if self.state_mod != StateMod.Visible:
|
||||||
data = {'is_banned': True,
|
data = {'state_mod_not_visible': True,
|
||||||
'ban_reason': self.ban_reason,
|
'state_mod_set_by': self.state_mod_set_by,
|
||||||
'id': self.id,
|
'id': self.id,
|
||||||
'post': self.post.id if self.post else 0,
|
'post': self.post.id if self.post else 0,
|
||||||
'level': self.level,
|
'level': self.level,
|
||||||
|
@ -287,7 +276,7 @@ class Comment(CreatedBase):
|
||||||
@lazy
|
@lazy
|
||||||
def json(self):
|
def json(self):
|
||||||
data = self.json_core
|
data = self.json_core
|
||||||
if self.state_user_deleted_utc or self.is_banned: return data
|
if self.state_user_deleted_utc or self.state_mod != StateMod.Visible: return data
|
||||||
data["author"] = '👻' if self.ghost else self.author.json_core
|
data["author"] = '👻' if self.ghost else self.author.json_core
|
||||||
data["post"] = self.post.json_core if self.post else ''
|
data["post"] = self.post.json_core if self.post else ''
|
||||||
return data
|
return data
|
||||||
|
@ -317,7 +306,7 @@ class Comment(CreatedBase):
|
||||||
if v and self.author_id == v.id: return False
|
if v and self.author_id == v.id: return False
|
||||||
if path == '/admin/removed/comments': return False
|
if path == '/admin/removed/comments': return False
|
||||||
if self.over_18 and not (v and v.over_18) and not (self.post and self.post.over_18): return True
|
if self.over_18 and not (v and v.over_18) and not (self.post and self.post.over_18): return True
|
||||||
if self.is_banned: return True
|
# we no longer collapse removed things; the mods want to see them, non-mods see a placeholder anyway
|
||||||
if v and v.filter_words and self.body and any(x in self.body for x in v.filter_words): return True
|
if v and v.filter_words and self.body and any(x in self.body for x in v.filter_words): return True
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
|
|
@ -8,6 +8,7 @@ from sqlalchemy.sql.sqltypes import Boolean, Integer, String, Text
|
||||||
from files.classes.cron.tasks import (RepeatableTask, ScheduledTaskType,
|
from files.classes.cron.tasks import (RepeatableTask, ScheduledTaskType,
|
||||||
TaskRunContext)
|
TaskRunContext)
|
||||||
from files.classes.submission import Submission
|
from files.classes.submission import Submission
|
||||||
|
from files.classes.visstate import StateMod
|
||||||
from files.helpers.config.const import SUBMISSION_TITLE_LENGTH_MAXIMUM
|
from files.helpers.config.const import SUBMISSION_TITLE_LENGTH_MAXIMUM
|
||||||
from files.helpers.content import ModerationState, body_displayed
|
from files.helpers.content import ModerationState, body_displayed
|
||||||
from files.helpers.lazy import lazy
|
from files.helpers.lazy import lazy
|
||||||
|
@ -68,7 +69,7 @@ class ScheduledSubmissionTask(RepeatableTask):
|
||||||
body_html=self.body_html,
|
body_html=self.body_html,
|
||||||
flair=self.flair,
|
flair=self.flair,
|
||||||
ghost=self.ghost,
|
ghost=self.ghost,
|
||||||
filter_state='normal',
|
state_mod=StateMod.Visible,
|
||||||
embed_url=self.embed_url,
|
embed_url=self.embed_url,
|
||||||
task_id=self.id,
|
task_id=self.id,
|
||||||
)
|
)
|
||||||
|
@ -127,8 +128,8 @@ class ScheduledSubmissionTask(RepeatableTask):
|
||||||
return 0
|
return 0
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def filter_state(self) -> str:
|
def state_mod(self) -> StateMod:
|
||||||
return 'normal'
|
return StateMod.Visible
|
||||||
|
|
||||||
def award_count(self, kind):
|
def award_count(self, kind):
|
||||||
return 0
|
return 0
|
||||||
|
|
|
@ -6,6 +6,7 @@ from sqlalchemy.orm import Session, declared_attr, deferred, relationship
|
||||||
|
|
||||||
from files.classes.base import CreatedBase
|
from files.classes.base import CreatedBase
|
||||||
from files.classes.flags import Flag
|
from files.classes.flags import Flag
|
||||||
|
from files.classes.visstate import StateMod, StateReport
|
||||||
from files.classes.votes import Vote
|
from files.classes.votes import Vote
|
||||||
from files.helpers.assetcache import assetcache_path
|
from files.helpers.assetcache import assetcache_path
|
||||||
from files.helpers.config.const import *
|
from files.helpers.config.const import *
|
||||||
|
@ -23,7 +24,6 @@ class Submission(CreatedBase):
|
||||||
author_id = Column(Integer, ForeignKey("users.id"), nullable=False)
|
author_id = Column(Integer, ForeignKey("users.id"), nullable=False)
|
||||||
edited_utc = Column(Integer, default=0, nullable=False)
|
edited_utc = Column(Integer, default=0, nullable=False)
|
||||||
thumburl = Column(String)
|
thumburl = Column(String)
|
||||||
is_banned = Column(Boolean, default=False, nullable=False)
|
|
||||||
bannedfor = Column(Boolean)
|
bannedfor = Column(Boolean)
|
||||||
ghost = Column(Boolean, default=False, nullable=False)
|
ghost = Column(Boolean, default=False, nullable=False)
|
||||||
views = Column(Integer, default=0, nullable=False)
|
views = Column(Integer, default=0, nullable=False)
|
||||||
|
@ -34,7 +34,6 @@ class Submission(CreatedBase):
|
||||||
private = Column(Boolean, default=False, nullable=False)
|
private = Column(Boolean, default=False, nullable=False)
|
||||||
club = Column(Boolean, default=False, nullable=False)
|
club = Column(Boolean, default=False, nullable=False)
|
||||||
comment_count = Column(Integer, default=0, nullable=False)
|
comment_count = Column(Integer, default=0, nullable=False)
|
||||||
is_approved = Column(Integer, ForeignKey("users.id"))
|
|
||||||
over_18 = Column(Boolean, default=False, nullable=False)
|
over_18 = Column(Boolean, default=False, nullable=False)
|
||||||
is_bot = Column(Boolean, default=False, nullable=False)
|
is_bot = Column(Boolean, default=False, nullable=False)
|
||||||
upvotes = Column(Integer, default=1, nullable=False)
|
upvotes = Column(Integer, default=1, nullable=False)
|
||||||
|
@ -47,26 +46,23 @@ class Submission(CreatedBase):
|
||||||
body = Column(Text)
|
body = Column(Text)
|
||||||
body_html = Column(Text)
|
body_html = Column(Text)
|
||||||
flair = Column(String)
|
flair = Column(String)
|
||||||
ban_reason = Column(String)
|
|
||||||
embed_url = Column(String)
|
embed_url = Column(String)
|
||||||
filter_state = Column(String, nullable=False)
|
|
||||||
task_id = Column(Integer, ForeignKey("tasks_repeatable_scheduled_submissions.id"))
|
task_id = Column(Integer, ForeignKey("tasks_repeatable_scheduled_submissions.id"))
|
||||||
|
|
||||||
# Visibility states here
|
# Visibility states here
|
||||||
state_user_deleted_utc = Column(DateTime(timezone=True), nullable=True) # null if it hasn't been deleted by the user
|
state_user_deleted_utc = Column(DateTime(timezone=True), nullable=True) # null if it hasn't been deleted by the user
|
||||||
# TBD: state_mod
|
state_mod = Column(Enum(StateMod), default=StateMod.Filtered, nullable=False) # default to Filtered just to partially neuter possible exploits
|
||||||
# TBD: state_mod_set_by
|
state_mod_set_by = Column(String, nullable=True) # This should *really* be a User.id, but I don't want to mess with the required refactoring at the moment - it's extra hard because it could potentially be a lot of extra either data or queries
|
||||||
# TBD: state_report
|
state_report = Column(Enum(StateReport), default=StateReport.Unreported, nullable=False)
|
||||||
|
|
||||||
Index('fki_submissions_approver_fkey', is_approved)
|
|
||||||
Index('post_app_id_idx', app_id)
|
Index('post_app_id_idx', app_id)
|
||||||
Index('subimssion_binary_group_idx', is_banned, state_user_deleted_utc, over_18)
|
Index('subimssion_binary_group_idx', state_mod, state_user_deleted_utc, over_18)
|
||||||
Index('submission_isbanned_idx', is_banned)
|
Index('submission_state_mod_idx', state_mod)
|
||||||
Index('submission_isdeleted_idx', state_user_deleted_utc)
|
Index('submission_isdeleted_idx', state_user_deleted_utc)
|
||||||
|
|
||||||
@declared_attr
|
@declared_attr
|
||||||
def submission_new_sort_idx(self):
|
def submission_new_sort_idx(self):
|
||||||
return Index('submission_new_sort_idx', self.is_banned, self.state_user_deleted_utc, self.created_utc.desc(), self.over_18)
|
return Index('submission_new_sort_idx', self.state_mod, self.state_user_deleted_utc, self.created_utc.desc(), self.over_18)
|
||||||
|
|
||||||
Index('submission_pinned_idx', is_pinned)
|
Index('submission_pinned_idx', is_pinned)
|
||||||
Index('submissions_author_index', author_id)
|
Index('submissions_author_index', author_id)
|
||||||
|
@ -83,7 +79,6 @@ class Submission(CreatedBase):
|
||||||
|
|
||||||
author = relationship("User", primaryjoin="Submission.author_id==User.id")
|
author = relationship("User", primaryjoin="Submission.author_id==User.id")
|
||||||
oauth_app = relationship("OauthApp", viewonly=True)
|
oauth_app = relationship("OauthApp", viewonly=True)
|
||||||
approved_by = relationship("User", uselist=False, primaryjoin="Submission.is_approved==User.id", viewonly=True)
|
|
||||||
awards = relationship("AwardRelationship", viewonly=True)
|
awards = relationship("AwardRelationship", viewonly=True)
|
||||||
reports = relationship("Flag", viewonly=True)
|
reports = relationship("Flag", viewonly=True)
|
||||||
comments = relationship("Comment", primaryjoin="Comment.parent_submission==Submission.id")
|
comments = relationship("Comment", primaryjoin="Comment.parent_submission==Submission.id")
|
||||||
|
@ -107,7 +102,7 @@ class Submission(CreatedBase):
|
||||||
author = self.author
|
author = self.author
|
||||||
author.post_count = db.query(Submission.id).filter_by(
|
author.post_count = db.query(Submission.id).filter_by(
|
||||||
author_id=self.author_id,
|
author_id=self.author_id,
|
||||||
is_banned=False,
|
state_mod=StateMod.Visible,
|
||||||
state_user_deleted_utc=None).count()
|
state_user_deleted_utc=None).count()
|
||||||
db.add(author)
|
db.add(author)
|
||||||
|
|
||||||
|
@ -235,8 +230,6 @@ class Submission(CreatedBase):
|
||||||
data = {'author_name': self.author_name if self.author else '',
|
data = {'author_name': self.author_name if self.author else '',
|
||||||
'permalink': self.permalink,
|
'permalink': self.permalink,
|
||||||
'shortlink': self.shortlink,
|
'shortlink': self.shortlink,
|
||||||
'is_banned': bool(self.is_banned),
|
|
||||||
'state_user_deleted_utc': self.state_user_deleted_utc,
|
|
||||||
'created_utc': self.created_utc,
|
'created_utc': self.created_utc,
|
||||||
'id': self.id,
|
'id': self.id,
|
||||||
'title': self.title,
|
'title': self.title,
|
||||||
|
@ -261,24 +254,21 @@ class Submission(CreatedBase):
|
||||||
'club': self.club,
|
'club': self.club,
|
||||||
}
|
}
|
||||||
|
|
||||||
if self.ban_reason:
|
|
||||||
data["ban_reason"]=self.ban_reason
|
|
||||||
|
|
||||||
return data
|
return data
|
||||||
|
|
||||||
@property
|
@property
|
||||||
@lazy
|
@lazy
|
||||||
def json_core(self):
|
def json_core(self):
|
||||||
if self.is_banned:
|
if self.state_mod != StateMod.Visible:
|
||||||
return {'is_banned': True,
|
return {'state_mod_not_visible': True,
|
||||||
'state_user_deleted_utc': self.state_user_deleted_utc,
|
'state_user_deleted_utc': self.state_user_deleted_utc,
|
||||||
'ban_reason': self.ban_reason,
|
'state_mod_set_by': self.state_mod_set_by,
|
||||||
'id': self.id,
|
'id': self.id,
|
||||||
'title': self.title,
|
'title': self.title,
|
||||||
'permalink': self.permalink,
|
'permalink': self.permalink,
|
||||||
}
|
}
|
||||||
elif self.state_user_deleted_utc:
|
elif self.state_user_deleted_utc:
|
||||||
return {'is_banned': bool(self.is_banned),
|
return {'state_mod_not_visible': False,
|
||||||
'state_user_deleted_utc': self.state_user_deleted_utc,
|
'state_user_deleted_utc': self.state_user_deleted_utc,
|
||||||
'id': self.id,
|
'id': self.id,
|
||||||
'title': self.title,
|
'title': self.title,
|
||||||
|
@ -292,7 +282,7 @@ class Submission(CreatedBase):
|
||||||
def json(self):
|
def json(self):
|
||||||
data=self.json_core
|
data=self.json_core
|
||||||
|
|
||||||
if self.state_user_deleted_utc or self.is_banned:
|
if self.state_user_deleted_utc or self.state_mod != StateMod.Visible:
|
||||||
return data
|
return data
|
||||||
|
|
||||||
data["author"]='👻' if self.ghost else self.author.json_core
|
data["author"]='👻' if self.ghost else self.author.json_core
|
||||||
|
|
|
@ -18,6 +18,7 @@ from files.classes.notifications import Notification
|
||||||
from files.classes.saves import CommentSaveRelationship, SaveRelationship
|
from files.classes.saves import CommentSaveRelationship, SaveRelationship
|
||||||
from files.classes.subscriptions import Subscription
|
from files.classes.subscriptions import Subscription
|
||||||
from files.classes.userblock import UserBlock
|
from files.classes.userblock import UserBlock
|
||||||
|
from files.classes.visstate import StateMod
|
||||||
from files.helpers.assetcache import assetcache_path
|
from files.helpers.assetcache import assetcache_path
|
||||||
from files.helpers.config.const import *
|
from files.helpers.config.const import *
|
||||||
from files.helpers.config.environment import (CARD_VIEW,
|
from files.helpers.config.environment import (CARD_VIEW,
|
||||||
|
@ -335,7 +336,7 @@ class User(CreatedBase):
|
||||||
@property
|
@property
|
||||||
@lazy
|
@lazy
|
||||||
def notifications_count(self):
|
def notifications_count(self):
|
||||||
notifs = g.db.query(Notification.user_id).join(Comment).filter(Notification.user_id == self.id, Notification.read == False, Comment.is_banned == False, Comment.state_user_deleted_utc == None)
|
notifs = g.db.query(Notification.user_id).join(Comment).filter(Notification.user_id == self.id, Notification.read == False, Comment.state_mod == StateMod.Visible, Comment.state_user_deleted_utc == None)
|
||||||
|
|
||||||
if not self.shadowbanned and self.admin_level < 3:
|
if not self.shadowbanned and self.admin_level < 3:
|
||||||
notifs = notifs.join(User, User.id == Comment.author_id).filter(User.shadowbanned == None)
|
notifs = notifs.join(User, User.id == Comment.author_id).filter(User.shadowbanned == None)
|
||||||
|
@ -350,7 +351,7 @@ class User(CreatedBase):
|
||||||
@property
|
@property
|
||||||
@lazy
|
@lazy
|
||||||
def reddit_notifications_count(self):
|
def reddit_notifications_count(self):
|
||||||
return g.db.query(Notification.user_id).join(Comment).filter(Notification.user_id == self.id, Notification.read == False, Comment.is_banned == False, Comment.state_user_deleted_utc == None, Comment.body_html.like('%<p>New site mention: <a href="https://old.reddit.com/r/%'), Comment.parent_submission == None, Comment.author_id == NOTIFICATIONS_ID).count()
|
return g.db.query(Notification.user_id).join(Comment).filter(Notification.user_id == self.id, Notification.read == False, Comment.state_mod == StateMod.Visible, Comment.state_user_deleted_utc == None, Comment.body_html.like('%<p>New site mention: <a href="https://old.reddit.com/r/%'), Comment.parent_submission == None, Comment.author_id == NOTIFICATIONS_ID).count()
|
||||||
|
|
||||||
@property
|
@property
|
||||||
@lazy
|
@lazy
|
||||||
|
@ -528,7 +529,7 @@ class User(CreatedBase):
|
||||||
@lazy
|
@lazy
|
||||||
def saved_idlist(self, page=1):
|
def saved_idlist(self, page=1):
|
||||||
saved = [x[0] for x in g.db.query(SaveRelationship.submission_id).filter_by(user_id=self.id).all()]
|
saved = [x[0] for x in g.db.query(SaveRelationship.submission_id).filter_by(user_id=self.id).all()]
|
||||||
posts = g.db.query(Submission.id).filter(Submission.id.in_(saved), Submission.is_banned == False, Submission.state_user_deleted_utc == None)
|
posts = g.db.query(Submission.id).filter(Submission.id.in_(saved), Submission.state_mod == StateMod.Visible, Submission.state_user_deleted_utc == None)
|
||||||
|
|
||||||
if self.admin_level < 2:
|
if self.admin_level < 2:
|
||||||
posts = posts.filter(Submission.author_id.notin_(self.userblocks))
|
posts = posts.filter(Submission.author_id.notin_(self.userblocks))
|
||||||
|
@ -538,7 +539,7 @@ class User(CreatedBase):
|
||||||
@lazy
|
@lazy
|
||||||
def saved_comment_idlist(self, page=1):
|
def saved_comment_idlist(self, page=1):
|
||||||
saved = [x[0] for x in g.db.query(CommentSaveRelationship.comment_id).filter_by(user_id=self.id).all()]
|
saved = [x[0] for x in g.db.query(CommentSaveRelationship.comment_id).filter_by(user_id=self.id).all()]
|
||||||
comments = g.db.query(Comment.id).filter(Comment.id.in_(saved), Comment.is_banned == False, Comment.state_user_deleted_utc == None)
|
comments = g.db.query(Comment.id).filter(Comment.id.in_(saved), Comment.state_mod == StateMod.Visible, Comment.state_user_deleted_utc == None)
|
||||||
|
|
||||||
if self.admin_level < 2:
|
if self.admin_level < 2:
|
||||||
comments = comments.filter(Comment.author_id.notin_(self.userblocks))
|
comments = comments.filter(Comment.author_id.notin_(self.userblocks))
|
||||||
|
|
13
files/classes/visstate.py
Normal file
13
files/classes/visstate.py
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
|
||||||
|
import enum
|
||||||
|
|
||||||
|
class StateMod(enum.Enum):
|
||||||
|
Visible = 0
|
||||||
|
Filtered = 1
|
||||||
|
Removed = 2
|
||||||
|
|
||||||
|
class StateReport(enum.Enum):
|
||||||
|
Unreported = 0
|
||||||
|
Resolved = 1
|
||||||
|
Reported = 2
|
||||||
|
Ignored = 3
|
|
@ -8,6 +8,7 @@ from werkzeug.security import generate_password_hash
|
||||||
|
|
||||||
from files.__main__ import app, db_session
|
from files.__main__ import app, db_session
|
||||||
from files.classes import Comment, CommentVote, Submission, User, Vote
|
from files.classes import Comment, CommentVote, Submission, User, Vote
|
||||||
|
from files.classes.visstate import StateMod
|
||||||
from files.helpers.comments import bulk_recompute_descendant_counts
|
from files.helpers.comments import bulk_recompute_descendant_counts
|
||||||
|
|
||||||
|
|
||||||
|
@ -104,7 +105,7 @@ def seed_db_worker(num_users = 900, num_posts = 40, num_toplevel_comments = 1000
|
||||||
title=f'Clever unique post title number {i}',
|
title=f'Clever unique post title number {i}',
|
||||||
title_html=f'Clever unique post title number {i}',
|
title_html=f'Clever unique post title number {i}',
|
||||||
ghost=False,
|
ghost=False,
|
||||||
filter_state='normal'
|
state_mod=StateMod.Visible,
|
||||||
)
|
)
|
||||||
db.add(post)
|
db.add(post)
|
||||||
posts.append(post)
|
posts.append(post)
|
||||||
|
@ -127,7 +128,8 @@ def seed_db_worker(num_users = 900, num_posts = 40, num_toplevel_comments = 1000
|
||||||
app_id=None,
|
app_id=None,
|
||||||
body_html=f'toplevel {i}',
|
body_html=f'toplevel {i}',
|
||||||
body=f'toplevel {i}',
|
body=f'toplevel {i}',
|
||||||
ghost=False
|
ghost=False,
|
||||||
|
state_mod=StateMod.Visible,
|
||||||
)
|
)
|
||||||
db.add(comment)
|
db.add(comment)
|
||||||
comments.append(comment)
|
comments.append(comment)
|
||||||
|
@ -156,7 +158,8 @@ def seed_db_worker(num_users = 900, num_posts = 40, num_toplevel_comments = 1000
|
||||||
app_id=None,
|
app_id=None,
|
||||||
body_html=f'reply {i}',
|
body_html=f'reply {i}',
|
||||||
body=f'reply {i}',
|
body=f'reply {i}',
|
||||||
ghost=False
|
ghost=False,
|
||||||
|
state_mod=StateMod.Visible,
|
||||||
)
|
)
|
||||||
db.add(comment)
|
db.add(comment)
|
||||||
comments.append(comment)
|
comments.append(comment)
|
||||||
|
|
|
@ -3,6 +3,7 @@ from flask import g
|
||||||
|
|
||||||
from .sanitize import *
|
from .sanitize import *
|
||||||
from .config.const import *
|
from .config.const import *
|
||||||
|
from files.classes.visstate import StateMod
|
||||||
|
|
||||||
def create_comment(text_html, autojanny=False):
|
def create_comment(text_html, autojanny=False):
|
||||||
if autojanny: author_id = AUTOJANNY_ID
|
if autojanny: author_id = AUTOJANNY_ID
|
||||||
|
@ -11,7 +12,8 @@ def create_comment(text_html, autojanny=False):
|
||||||
new_comment = Comment(author_id=author_id,
|
new_comment = Comment(author_id=author_id,
|
||||||
parent_submission=None,
|
parent_submission=None,
|
||||||
body_html=text_html,
|
body_html=text_html,
|
||||||
distinguish_level=6)
|
distinguish_level=6,
|
||||||
|
state_mod=StateMod.Visible,)
|
||||||
g.db.add(new_comment)
|
g.db.add(new_comment)
|
||||||
g.db.flush()
|
g.db.flush()
|
||||||
|
|
||||||
|
|
|
@ -9,6 +9,7 @@ from sqlalchemy.orm import Query, aliased
|
||||||
from sqlalchemy.sql.expression import alias, func, text
|
from sqlalchemy.sql.expression import alias, func, text
|
||||||
|
|
||||||
from files.classes import Comment, Notification, Subscription, User
|
from files.classes import Comment, Notification, Subscription, User
|
||||||
|
from files.classes.visstate import StateMod
|
||||||
from files.helpers.alerts import NOTIFY_USERS
|
from files.helpers.alerts import NOTIFY_USERS
|
||||||
from files.helpers.assetcache import assetcache_path
|
from files.helpers.assetcache import assetcache_path
|
||||||
from files.helpers.config.environment import (PUSHER_ID, PUSHER_KEY, SITE_FULL,
|
from files.helpers.config.environment import (PUSHER_ID, PUSHER_KEY, SITE_FULL,
|
||||||
|
@ -65,7 +66,7 @@ def update_author_comment_count(comment, delta):
|
||||||
comment.author.comment_count = g.db.query(Comment).filter(
|
comment.author.comment_count = g.db.query(Comment).filter(
|
||||||
Comment.author_id == comment.author_id,
|
Comment.author_id == comment.author_id,
|
||||||
Comment.parent_submission != None,
|
Comment.parent_submission != None,
|
||||||
Comment.is_banned == False,
|
Comment.state_mod == StateMod.Visible,
|
||||||
Comment.state_user_deleted_utc == None,
|
Comment.state_user_deleted_utc == None,
|
||||||
).count()
|
).count()
|
||||||
g.db.add(comment.author)
|
g.db.add(comment.author)
|
||||||
|
@ -218,7 +219,7 @@ def comment_on_publish(comment:Comment):
|
||||||
def comment_on_unpublish(comment:Comment):
|
def comment_on_unpublish(comment:Comment):
|
||||||
"""
|
"""
|
||||||
Run when a comment becomes invisible: when a moderator makes the comment non-visible
|
Run when a comment becomes invisible: when a moderator makes the comment non-visible
|
||||||
by changing the filter_state to "removed", or when the user deletes the comment.
|
by changing the state_mod to "removed", or when the user deletes the comment.
|
||||||
Should be used to update stateful counters, notifications, etc. that
|
Should be used to update stateful counters, notifications, etc. that
|
||||||
reflect the comments users will actually see.
|
reflect the comments users will actually see.
|
||||||
"""
|
"""
|
||||||
|
@ -231,8 +232,7 @@ def comment_filter_moderated(q: Query, v: Optional[User]) -> Query:
|
||||||
.filter(User.shadowbanned == None)
|
.filter(User.shadowbanned == None)
|
||||||
if not v or v.admin_level < 2:
|
if not v or v.admin_level < 2:
|
||||||
q = q.filter(
|
q = q.filter(
|
||||||
((Comment.filter_state != 'filtered')
|
Comment.state_mod == StateMod.Visible
|
||||||
& (Comment.filter_state != 'removed'))
|
|
||||||
| (Comment.author_id == ((v and v.id) or 0))
|
| (Comment.author_id == ((v and v.id) or 0))
|
||||||
)
|
)
|
||||||
return q
|
return q
|
||||||
|
|
|
@ -8,6 +8,7 @@ from typing import TYPE_CHECKING, Any, Optional
|
||||||
from sqlalchemy.orm import Session
|
from sqlalchemy.orm import Session
|
||||||
|
|
||||||
from files.helpers.config.const import PERMS
|
from files.helpers.config.const import PERMS
|
||||||
|
from files.classes.visstate import StateMod, StateReport
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
from files.classes import Comment, Submission, User
|
from files.classes import Comment, Submission, User
|
||||||
|
@ -108,11 +109,11 @@ class ModerationState:
|
||||||
@classmethod
|
@classmethod
|
||||||
def from_submittable(cls, target: Submittable) -> "ModerationState":
|
def from_submittable(cls, target: Submittable) -> "ModerationState":
|
||||||
return cls(
|
return cls(
|
||||||
removed=bool(target.is_banned or target.filter_state == 'removed'),
|
removed=bool(target.state_mod != StateMod.Visible),
|
||||||
removed_by_name=target.ban_reason, # type: ignore
|
removed_by_name=target.state_mod_set_by, # type: ignore
|
||||||
deleted=bool(target.state_user_deleted_utc != None),
|
deleted=bool(target.state_user_deleted_utc != None),
|
||||||
reports_ignored=bool(target.filter_state == 'ignored'),
|
reports_ignored=bool(target.state_report == StateReport.Ignored),
|
||||||
filtered=bool(target.filter_state == 'filtered'),
|
filtered=bool(target.state_mod == StateMod.Filtered),
|
||||||
op_shadowbanned=bool(target.author.shadowbanned),
|
op_shadowbanned=bool(target.author.shadowbanned),
|
||||||
op_id=target.author_id, # type: ignore
|
op_id=target.author_id, # type: ignore
|
||||||
op_name_safe=target.author_name
|
op_name_safe=target.author_name
|
||||||
|
|
|
@ -5,6 +5,7 @@ from jinja2 import pass_context
|
||||||
|
|
||||||
from files.__main__ import app
|
from files.__main__ import app
|
||||||
from files.classes.cron.tasks import ScheduledTaskType
|
from files.classes.cron.tasks import ScheduledTaskType
|
||||||
|
from files.classes.visstate import StateMod, StateReport
|
||||||
from files.helpers.assetcache import assetcache_path
|
from files.helpers.assetcache import assetcache_path
|
||||||
from files.helpers.config.environment import (CARD_VIEW, DEFAULT_COLOR,
|
from files.helpers.config.environment import (CARD_VIEW, DEFAULT_COLOR,
|
||||||
ENABLE_DOWNVOTES, FINGERPRINT_TOKEN, PUSHER_ID, SITE, SITE_FULL, SITE_ID,
|
ENABLE_DOWNVOTES, FINGERPRINT_TOKEN, PUSHER_ID, SITE, SITE_FULL, SITE_ID,
|
||||||
|
@ -84,6 +85,8 @@ def inject_constants():
|
||||||
"SORTS_POSTS":SORTS_POSTS,
|
"SORTS_POSTS":SORTS_POSTS,
|
||||||
"CSS_LENGTH_MAXIMUM":CSS_LENGTH_MAXIMUM,
|
"CSS_LENGTH_MAXIMUM":CSS_LENGTH_MAXIMUM,
|
||||||
"ScheduledTaskType":ScheduledTaskType,
|
"ScheduledTaskType":ScheduledTaskType,
|
||||||
|
"StateMod": StateMod,
|
||||||
|
"StateReport": StateReport,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -12,6 +12,7 @@ from sqlalchemy import func
|
||||||
from files.__main__ import cache
|
from files.__main__ import cache
|
||||||
from files.classes.submission import Submission
|
from files.classes.submission import Submission
|
||||||
from files.classes.user import User
|
from files.classes.user import User
|
||||||
|
from files.classes.visstate import StateMod
|
||||||
from files.classes.votes import Vote
|
from files.classes.votes import Vote
|
||||||
from files.helpers.contentsorting import apply_time_filter, sort_objects
|
from files.helpers.contentsorting import apply_time_filter, sort_objects
|
||||||
from files.helpers.strings import sql_ilike_clean
|
from files.helpers.strings import sql_ilike_clean
|
||||||
|
@ -30,7 +31,7 @@ def frontlist(v=None, sort='new', page=1, t="all", ids_only=True, ccmode="false"
|
||||||
posts = posts.filter(Submission.id.notin_(voted))
|
posts = posts.filter(Submission.id.notin_(voted))
|
||||||
|
|
||||||
if not v or v.admin_level < 2:
|
if not v or v.admin_level < 2:
|
||||||
filter_clause = (Submission.filter_state != 'filtered') & (Submission.filter_state != 'removed')
|
filter_clause = Submission.state_mod == StateMod.Visible
|
||||||
if v:
|
if v:
|
||||||
filter_clause = filter_clause | (Submission.author_id == v.id)
|
filter_clause = filter_clause | (Submission.author_id == v.id)
|
||||||
posts = posts.filter(filter_clause)
|
posts = posts.filter(filter_clause)
|
||||||
|
@ -44,7 +45,7 @@ def frontlist(v=None, sort='new', page=1, t="all", ids_only=True, ccmode="false"
|
||||||
if (ccmode == "true"):
|
if (ccmode == "true"):
|
||||||
posts = posts.filter(Submission.club == True)
|
posts = posts.filter(Submission.club == True)
|
||||||
|
|
||||||
posts = posts.filter_by(is_banned=False, private=False, state_user_deleted_utc=None)
|
posts = posts.filter_by(state_mod=StateMod.Visible, private=False, state_user_deleted_utc=None)
|
||||||
|
|
||||||
if ccmode == "false" and not gt and not lt:
|
if ccmode == "false" and not gt and not lt:
|
||||||
posts = posts.filter_by(stickied=None)
|
posts = posts.filter_by(stickied=None)
|
||||||
|
@ -77,7 +78,7 @@ def frontlist(v=None, sort='new', page=1, t="all", ids_only=True, ccmode="false"
|
||||||
posts = posts[:size]
|
posts = posts[:size]
|
||||||
|
|
||||||
if page == 1 and ccmode == "false" and not gt and not lt:
|
if page == 1 and ccmode == "false" and not gt and not lt:
|
||||||
pins = g.db.query(Submission).filter(Submission.stickied != None, Submission.is_banned == False)
|
pins = g.db.query(Submission).filter(Submission.stickied != None, Submission.state_mod == StateMod.Visible)
|
||||||
if v:
|
if v:
|
||||||
if v.admin_level < 2:
|
if v.admin_level < 2:
|
||||||
pins = pins.filter(Submission.author_id.notin_(v.userblocks))
|
pins = pins.filter(Submission.author_id.notin_(v.userblocks))
|
||||||
|
@ -107,7 +108,7 @@ def userpagelisting(u:User, v=None, page=1, sort="new", t="all"):
|
||||||
posts = g.db.query(Submission.id).filter_by(author_id=u.id, is_pinned=False)
|
posts = g.db.query(Submission.id).filter_by(author_id=u.id, is_pinned=False)
|
||||||
|
|
||||||
if not (v and (v.admin_level >= 2 or v.id == u.id)):
|
if not (v and (v.admin_level >= 2 or v.id == u.id)):
|
||||||
posts = posts.filter_by(state_user_deleted_utc=None, is_banned=False, private=False, ghost=False)
|
posts = posts.filter_by(state_user_deleted_utc=None, state_mod=StateMod.Visible, private=False, ghost=False)
|
||||||
|
|
||||||
posts = apply_time_filter(posts, t, Submission)
|
posts = apply_time_filter(posts, t, Submission)
|
||||||
posts = sort_objects(posts, sort, Submission)
|
posts = sort_objects(posts, sort, Submission)
|
||||||
|
@ -119,7 +120,7 @@ def userpagelisting(u:User, v=None, page=1, sort="new", t="all"):
|
||||||
|
|
||||||
@cache.memoize(timeout=CHANGELOGLIST_TIMEOUT_SECS)
|
@cache.memoize(timeout=CHANGELOGLIST_TIMEOUT_SECS)
|
||||||
def changeloglist(v=None, sort="new", page=1, t="all"):
|
def changeloglist(v=None, sort="new", page=1, t="all"):
|
||||||
posts = g.db.query(Submission.id).filter_by(is_banned=False, private=False,).filter(Submission.state_user_deleted_utc == None)
|
posts = g.db.query(Submission.id).filter_by(state_mod=StateMod.Visible, private=False,).filter(Submission.state_user_deleted_utc == None)
|
||||||
|
|
||||||
if v.admin_level < 2:
|
if v.admin_level < 2:
|
||||||
posts = posts.filter(Submission.author_id.notin_(v.userblocks))
|
posts = posts.filter(Submission.author_id.notin_(v.userblocks))
|
||||||
|
|
|
@ -5,6 +5,7 @@ from datetime import datetime
|
||||||
import requests
|
import requests
|
||||||
|
|
||||||
from files.classes import *
|
from files.classes import *
|
||||||
|
from files.classes.visstate import StateMod, StateReport
|
||||||
from files.helpers.alerts import *
|
from files.helpers.alerts import *
|
||||||
from files.helpers.caching import invalidate_cache
|
from files.helpers.caching import invalidate_cache
|
||||||
from files.helpers.comments import comment_on_publish, comment_on_unpublish
|
from files.helpers.comments import comment_on_publish, comment_on_unpublish
|
||||||
|
@ -136,8 +137,8 @@ def revert_actions(v, username):
|
||||||
comments = g.db.query(Comment).filter(Comment.id.in_(comments)).all()
|
comments = g.db.query(Comment).filter(Comment.id.in_(comments)).all()
|
||||||
|
|
||||||
for item in posts + comments:
|
for item in posts + comments:
|
||||||
item.is_banned = False
|
item.state_mod = StateMod.Visible
|
||||||
item.ban_reason = None
|
item.state_mod_set_by = v.username
|
||||||
g.db.add(item)
|
g.db.add(item)
|
||||||
|
|
||||||
users = (x[0] for x in g.db.query(ModAction.target_user_id).filter(ModAction.user_id == user.id, ModAction.created_utc > cutoff, ModAction.kind.in_(('shadowban', 'ban_user'))).all())
|
users = (x[0] for x in g.db.query(ModAction.target_user_id).filter(ModAction.user_id == user.id, ModAction.created_utc > cutoff, ModAction.kind.in_(('shadowban', 'ban_user'))).all())
|
||||||
|
@ -235,7 +236,7 @@ def filtered_submissions(v):
|
||||||
|
|
||||||
posts_just_ids = g.db.query(Submission) \
|
posts_just_ids = g.db.query(Submission) \
|
||||||
.order_by(Submission.id.desc()) \
|
.order_by(Submission.id.desc()) \
|
||||||
.filter(Submission.filter_state == 'filtered') \
|
.filter(Submission.state_mod == StateMod.Filtered) \
|
||||||
.limit(26) \
|
.limit(26) \
|
||||||
.offset(25 * (page - 1)) \
|
.offset(25 * (page - 1)) \
|
||||||
.with_entities(Submission.id)
|
.with_entities(Submission.id)
|
||||||
|
@ -255,7 +256,7 @@ def filtered_comments(v):
|
||||||
|
|
||||||
comments_just_ids = g.db.query(Comment) \
|
comments_just_ids = g.db.query(Comment) \
|
||||||
.order_by(Comment.id.desc()) \
|
.order_by(Comment.id.desc()) \
|
||||||
.filter(Comment.filter_state == 'filtered') \
|
.filter(Comment.state_mod == StateMod.Filtered) \
|
||||||
.limit(26) \
|
.limit(26) \
|
||||||
.offset(25 * (page - 1)) \
|
.offset(25 * (page - 1)) \
|
||||||
.with_entities(Comment.id)
|
.with_entities(Comment.id)
|
||||||
|
@ -266,6 +267,9 @@ def filtered_comments(v):
|
||||||
|
|
||||||
return render_template("admin/filtered_comments.html", v=v, listing=comments, next_exists=next_exists, page=page, sort="new")
|
return render_template("admin/filtered_comments.html", v=v, listing=comments, next_exists=next_exists, page=page, sort="new")
|
||||||
|
|
||||||
|
# NOTE:
|
||||||
|
# This function is pretty grimy and should be rolled into the Remove/Unremove functions.
|
||||||
|
# (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(2)
|
||||||
|
@ -277,29 +281,48 @@ def update_filter_status(v):
|
||||||
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' }
|
||||||
|
|
||||||
|
if new_status == 'normal':
|
||||||
|
state_mod_new = StateMod.Visible
|
||||||
|
state_report_new = StateReport.Resolved
|
||||||
|
elif new_status == 'removed':
|
||||||
|
state_mod_new = StateMod.Removed
|
||||||
|
state_report_new = StateReport.Resolved
|
||||||
|
elif new_status == 'ignored':
|
||||||
|
state_mod_new = None # we just leave this as-is
|
||||||
|
state_report_new = StateReport.Ignored
|
||||||
|
|
||||||
if post_id:
|
if post_id:
|
||||||
target = g.db.get(Submission, post_id)
|
target = g.db.get(Submission, post_id)
|
||||||
old_status = target.filter_state
|
old_status = target.state_mod
|
||||||
rows_updated = g.db.query(Submission).where(Submission.id == post_id) \
|
|
||||||
.update({Submission.filter_state: new_status})
|
# this could totally be one query but it would be kinda ugly
|
||||||
|
if state_mod_new:
|
||||||
|
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 = g.db.get(Comment, comment_id)
|
||||||
old_status = target.filter_state
|
old_status = target.state_mod
|
||||||
rows_updated = g.db.query(Comment).where(Comment.id == comment_id) \
|
|
||||||
.update({Comment.filter_state: new_status})
|
if state_mod_new:
|
||||||
|
g.db.query(Comment).where(Comment.id == comment_id) \
|
||||||
|
.update({Comment.state_mod: state_mod_new, Comment.state_mod_set_by: v.username})
|
||||||
|
g.db.query(Comment).where(Comment.id == comment_id) \
|
||||||
|
.update({Comment.state_report: state_report_new})
|
||||||
else:
|
else:
|
||||||
return { 'result': f'No valid item ID provided' }
|
return { 'result': f'No valid item ID provided' }
|
||||||
|
|
||||||
if rows_updated == 1:
|
if target is not None:
|
||||||
# If comment now visible, update state to reflect publication.
|
# If comment now visible, update state to reflect publication.
|
||||||
if (isinstance(target, Comment)
|
if (isinstance(target, Comment)
|
||||||
and old_status in ['filtered', 'removed']
|
and old_status != StateMod.Visible
|
||||||
and new_status in ['normal', 'ignored']):
|
and state_mod_new == StateMod.Visible):
|
||||||
comment_on_publish(target) # XXX: can cause discrepancies if removal state ≠ filter state
|
comment_on_publish(target) # XXX: can cause discrepancies if removal state ≠ filter state
|
||||||
|
|
||||||
if (isinstance(target, Comment)
|
if (isinstance(target, Comment)
|
||||||
and old_status in ['normal', 'ignored']
|
and old_status == StateMod.Visible
|
||||||
and new_status in ['filtered', 'removed']):
|
and state_mod_new != StateMod.Visible and state_mod_new is not None):
|
||||||
comment_on_unpublish(target) # XXX: can cause discrepancies if removal state ≠ filter state
|
comment_on_unpublish(target) # XXX: can cause discrepancies if removal state ≠ filter state
|
||||||
|
|
||||||
g.db.commit()
|
g.db.commit()
|
||||||
|
@ -332,7 +355,7 @@ def reported_posts(v):
|
||||||
page = max(1, int(request.values.get("page", 1)))
|
page = max(1, int(request.values.get("page", 1)))
|
||||||
|
|
||||||
subs_just_ids = g.db.query(Submission) \
|
subs_just_ids = g.db.query(Submission) \
|
||||||
.filter(Submission.filter_state == 'reported') \
|
.filter(Submission.state_report == StateReport.Reported) \
|
||||||
.order_by(Submission.id.desc()) \
|
.order_by(Submission.id.desc()) \
|
||||||
.offset(25 * (page - 1)) \
|
.offset(25 * (page - 1)) \
|
||||||
.limit(26) \
|
.limit(26) \
|
||||||
|
@ -351,13 +374,8 @@ def reported_posts(v):
|
||||||
def reported_comments(v):
|
def reported_comments(v):
|
||||||
page = max(1, int(request.values.get("page", 1)))
|
page = max(1, int(request.values.get("page", 1)))
|
||||||
|
|
||||||
listing = g.db.query(Comment
|
|
||||||
).filter_by(
|
|
||||||
is_approved=None,
|
|
||||||
is_banned=False
|
|
||||||
).join(Comment.reports).order_by(Comment.id.desc()).offset(25 * (page - 1)).limit(26).all()
|
|
||||||
comments_just_ids = g.db.query(Comment) \
|
comments_just_ids = g.db.query(Comment) \
|
||||||
.filter(Comment.filter_state == 'reported') \
|
.filter(Comment.state_report == StateReport.Reported) \
|
||||||
.order_by(Comment.id.desc()) \
|
.order_by(Comment.id.desc()) \
|
||||||
.offset(25 * (page - 1)) \
|
.offset(25 * (page - 1)) \
|
||||||
.limit(26) \
|
.limit(26) \
|
||||||
|
@ -415,7 +433,8 @@ def change_settings(v, setting):
|
||||||
level=1,
|
level=1,
|
||||||
body_html=body_html,
|
body_html=body_html,
|
||||||
sentto=MODMAIL_ID,
|
sentto=MODMAIL_ID,
|
||||||
distinguish_level=6
|
distinguish_level=6,
|
||||||
|
state_mod=StateMod.Visible,
|
||||||
)
|
)
|
||||||
g.db.add(new_comment)
|
g.db.add(new_comment)
|
||||||
g.db.flush()
|
g.db.flush()
|
||||||
|
@ -765,7 +784,7 @@ def admin_removed(v):
|
||||||
|
|
||||||
if page < 1: abort(400)
|
if page < 1: abort(400)
|
||||||
|
|
||||||
ids = g.db.query(Submission.id).join(User, User.id == Submission.author_id).filter(or_(Submission.is_banned==True, User.shadowbanned != None)).order_by(Submission.id.desc()).offset(25 * (page - 1)).limit(26).all()
|
ids = g.db.query(Submission.id).join(User, User.id == Submission.author_id).filter(or_(Submission.state_mod == StateMod.Removed, User.shadowbanned != None)).order_by(Submission.id.desc()).offset(25 * (page - 1)).limit(26).all()
|
||||||
|
|
||||||
ids=[x[0] for x in ids]
|
ids=[x[0] for x in ids]
|
||||||
|
|
||||||
|
@ -790,7 +809,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.is_banned==True, 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_mode == 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]
|
||||||
|
|
||||||
|
@ -840,7 +859,8 @@ def shadowban(user_id, v):
|
||||||
parent_submission=None,
|
parent_submission=None,
|
||||||
level=1,
|
level=1,
|
||||||
body_html=body_html,
|
body_html=body_html,
|
||||||
distinguish_level=6
|
distinguish_level=6,
|
||||||
|
state_mod=StateMod.Visible,
|
||||||
)
|
)
|
||||||
g.db.add(new_comment)
|
g.db.add(new_comment)
|
||||||
g.db.flush()
|
g.db.flush()
|
||||||
|
@ -1025,7 +1045,8 @@ def ban_user(user_id, v):
|
||||||
parent_submission=None,
|
parent_submission=None,
|
||||||
level=1,
|
level=1,
|
||||||
body_html=body_html,
|
body_html=body_html,
|
||||||
distinguish_level=6
|
distinguish_level=6,
|
||||||
|
state_mod=StateMod.Visible,
|
||||||
)
|
)
|
||||||
g.db.add(new_comment)
|
g.db.add(new_comment)
|
||||||
g.db.flush()
|
g.db.flush()
|
||||||
|
@ -1088,11 +1109,10 @@ def remove_post(post_id, v):
|
||||||
if not post:
|
if not post:
|
||||||
abort(400)
|
abort(400)
|
||||||
|
|
||||||
post.is_banned = True
|
post.state_mod = StateMod.Removed
|
||||||
post.is_approved = None
|
post.state_mod_set_by = v.username
|
||||||
post.stickied = None
|
post.stickied = None
|
||||||
post.is_pinned = False
|
post.is_pinned = False
|
||||||
post.ban_reason = v.username
|
|
||||||
g.db.add(post)
|
g.db.add(post)
|
||||||
|
|
||||||
|
|
||||||
|
@ -1125,7 +1145,7 @@ def unremove_post(post_id, v):
|
||||||
if not post:
|
if not post:
|
||||||
abort(400)
|
abort(400)
|
||||||
|
|
||||||
if post.is_banned:
|
if post.state_mod != StateMod.Visible:
|
||||||
ma=ModAction(
|
ma=ModAction(
|
||||||
kind="unremove_post",
|
kind="unremove_post",
|
||||||
user_id=v.id,
|
user_id=v.id,
|
||||||
|
@ -1133,9 +1153,8 @@ def unremove_post(post_id, v):
|
||||||
)
|
)
|
||||||
g.db.add(ma)
|
g.db.add(ma)
|
||||||
|
|
||||||
post.is_banned = False
|
post.state_mod = StateMod.Visible
|
||||||
post.ban_reason = None
|
post.state_mod_set_by = v.username
|
||||||
post.is_approved = v.id
|
|
||||||
|
|
||||||
g.db.add(post)
|
g.db.add(post)
|
||||||
|
|
||||||
|
@ -1187,7 +1206,7 @@ def api_distinguish_post(post_id, v):
|
||||||
def sticky_post(post_id, v):
|
def sticky_post(post_id, v):
|
||||||
post = g.db.query(Submission).filter_by(id=post_id).one_or_none()
|
post = g.db.query(Submission).filter_by(id=post_id).one_or_none()
|
||||||
if post and not post.stickied:
|
if post and not post.stickied:
|
||||||
pins = g.db.query(Submission.id).filter(Submission.stickied != None, Submission.is_banned == False).count()
|
pins = g.db.query(Submission.id).filter(Submission.stickied != None, Submission.state_mod == StateMod.Visible).count()
|
||||||
if pins > 2:
|
if pins > 2:
|
||||||
if v.admin_level >= 2:
|
if v.admin_level >= 2:
|
||||||
post.stickied = v.username
|
post.stickied = v.username
|
||||||
|
@ -1296,9 +1315,8 @@ def api_remove_comment(c_id, v):
|
||||||
if not comment:
|
if not comment:
|
||||||
abort(404)
|
abort(404)
|
||||||
|
|
||||||
comment.is_banned = True
|
comment.state_mod = StateMod.Removed
|
||||||
comment.is_approved = None
|
comment.state_mod_set_by = v.username
|
||||||
comment.ban_reason = v.username
|
|
||||||
comment_on_unpublish(comment) # XXX: can cause discrepancies if removal state ≠ filter state
|
comment_on_unpublish(comment) # XXX: can cause discrepancies if removal state ≠ filter state
|
||||||
ma=ModAction(
|
ma=ModAction(
|
||||||
kind="remove_comment",
|
kind="remove_comment",
|
||||||
|
@ -1317,7 +1335,7 @@ def api_unremove_comment(c_id, v):
|
||||||
comment = g.db.query(Comment).filter_by(id=c_id).one_or_none()
|
comment = g.db.query(Comment).filter_by(id=c_id).one_or_none()
|
||||||
if not comment: abort(404)
|
if not comment: abort(404)
|
||||||
|
|
||||||
if comment.is_banned:
|
if comment.state_mod == StateMod.Removed:
|
||||||
ma=ModAction(
|
ma=ModAction(
|
||||||
kind="unremove_comment",
|
kind="unremove_comment",
|
||||||
user_id=v.id,
|
user_id=v.id,
|
||||||
|
@ -1325,9 +1343,8 @@ def api_unremove_comment(c_id, v):
|
||||||
)
|
)
|
||||||
g.db.add(ma)
|
g.db.add(ma)
|
||||||
|
|
||||||
comment.is_banned = False
|
comment.state_mod = StateMod.Visible
|
||||||
comment.ban_reason = None
|
comment.state_mod_set_by = v.username
|
||||||
comment.is_approved = v.id
|
|
||||||
comment_on_publish(comment) # XXX: can cause discrepancies if removal state ≠ filter state
|
comment_on_publish(comment) # XXX: can cause discrepancies if removal state ≠ filter state
|
||||||
|
|
||||||
g.db.add(comment)
|
g.db.add(comment)
|
||||||
|
@ -1426,24 +1443,24 @@ def admin_toggle_ban_domain(v):
|
||||||
|
|
||||||
@app.post("/admin/nuke_user")
|
@app.post("/admin/nuke_user")
|
||||||
@limiter.exempt
|
@limiter.exempt
|
||||||
@admin_level_required(2)
|
@admin_level_required(3)
|
||||||
def admin_nuke_user(v):
|
def admin_nuke_user(v):
|
||||||
user=get_user(request.values.get("user"))
|
user=get_user(request.values.get("user"))
|
||||||
|
|
||||||
for post in g.db.query(Submission).filter_by(author_id=user.id).all():
|
for post in g.db.query(Submission).filter_by(author_id=user.id).all():
|
||||||
if post.is_banned:
|
if post.state_mod != StateMod.Removed:
|
||||||
continue
|
continue
|
||||||
|
|
||||||
post.is_banned = True
|
post.state_mod == StateMod.Removed
|
||||||
post.ban_reason = v.username
|
post.state_mod_set_by = v.username
|
||||||
g.db.add(post)
|
g.db.add(post)
|
||||||
|
|
||||||
for comment in g.db.query(Comment).filter_by(author_id=user.id).all():
|
for comment in g.db.query(Comment).filter_by(author_id=user.id).all():
|
||||||
if comment.is_banned:
|
if comment.state_mod != StateMod.Removed:
|
||||||
continue
|
continue
|
||||||
|
|
||||||
comment.is_banned = True
|
comment.state_mod == StateMod.Removed
|
||||||
comment.ban_reason = v.username
|
comment.state_mod_set_by = v.username
|
||||||
g.db.add(comment)
|
g.db.add(comment)
|
||||||
|
|
||||||
ma=ModAction(
|
ma=ModAction(
|
||||||
|
@ -1460,24 +1477,24 @@ def admin_nuke_user(v):
|
||||||
|
|
||||||
@app.post("/admin/unnuke_user")
|
@app.post("/admin/unnuke_user")
|
||||||
@limiter.exempt
|
@limiter.exempt
|
||||||
@admin_level_required(2)
|
@admin_level_required(3)
|
||||||
def admin_nunuke_user(v):
|
def admin_nunuke_user(v):
|
||||||
user=get_user(request.values.get("user"))
|
user=get_user(request.values.get("user"))
|
||||||
|
|
||||||
for post in g.db.query(Submission).filter_by(author_id=user.id).all():
|
for post in g.db.query(Submission).filter_by(author_id=user.id).all():
|
||||||
if not post.is_banned:
|
if post.state_mod == StateMod.Visible:
|
||||||
continue
|
continue
|
||||||
|
|
||||||
post.is_banned = False
|
post.state_mod == StateMod.Visible
|
||||||
post.ban_reason = None
|
post.state_mod_set_by = v.username
|
||||||
g.db.add(post)
|
g.db.add(post)
|
||||||
|
|
||||||
for comment in g.db.query(Comment).filter_by(author_id=user.id).all():
|
for comment in g.db.query(Comment).filter_by(author_id=user.id).all():
|
||||||
if not comment.is_banned:
|
if comment.state_mod == StateMod.Visible:
|
||||||
continue
|
continue
|
||||||
|
|
||||||
comment.is_banned = False
|
comment.state_mod == StateMod.Visible
|
||||||
comment.ban_reason = None
|
comment.state_mod_set_by = v.username
|
||||||
g.db.add(comment)
|
g.db.add(comment)
|
||||||
|
|
||||||
ma=ModAction(
|
ma=ModAction(
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
from files.__main__ import app, limiter
|
from files.__main__ import app, limiter
|
||||||
from files.classes import *
|
from files.classes import *
|
||||||
|
from files.classes.visstate import StateMod
|
||||||
from files.helpers.alerts import *
|
from files.helpers.alerts import *
|
||||||
from files.helpers.comments import comment_on_publish
|
from files.helpers.comments import comment_on_publish
|
||||||
from files.helpers.config.const import *
|
from files.helpers.config.const import *
|
||||||
|
@ -97,7 +98,7 @@ def post_pid_comment_cid(cid, pid=None, anything=None, v=None):
|
||||||
|
|
||||||
if request.headers.get("Authorization"): return top_comment.json
|
if request.headers.get("Authorization"): return top_comment.json
|
||||||
else:
|
else:
|
||||||
if post.is_banned and not (v and (v.admin_level >= 2 or post.author_id == v.id)): template = "submission_banned.html"
|
if post.state_mod != StateMod.Visible and not (v and (v.admin_level >= 2 or post.author_id == v.id)): template = "submission_banned.html"
|
||||||
else: template = "submission.html"
|
else: template = "submission.html"
|
||||||
return render_template(template, v=v, p=post, sort=sort, comment_info=comment_info, render_replies=True)
|
return render_template(template, v=v, p=post, sort=sort, comment_info=comment_info, render_replies=True)
|
||||||
|
|
||||||
|
@ -188,8 +189,8 @@ def api_comment(v):
|
||||||
days=1)
|
days=1)
|
||||||
|
|
||||||
for comment in similar_comments:
|
for comment in similar_comments:
|
||||||
comment.is_banned = True
|
comment.state_mod = StateMod.Removed
|
||||||
comment.ban_reason = "AutoJanny"
|
comment.state_mod_set_by = "AutoJanny"
|
||||||
g.db.add(comment)
|
g.db.add(comment)
|
||||||
ma=ModAction(
|
ma=ModAction(
|
||||||
user_id=AUTOJANNY_ID,
|
user_id=AUTOJANNY_ID,
|
||||||
|
@ -213,7 +214,7 @@ def api_comment(v):
|
||||||
body_html=body_html,
|
body_html=body_html,
|
||||||
body=body[:COMMENT_BODY_LENGTH_MAXIMUM],
|
body=body[:COMMENT_BODY_LENGTH_MAXIMUM],
|
||||||
ghost=parent_post.ghost,
|
ghost=parent_post.ghost,
|
||||||
filter_state='filtered' if is_filtered else 'normal'
|
state_mod=StateMod.Filtered if is_filtered else StateMod.Visible,
|
||||||
)
|
)
|
||||||
|
|
||||||
c.upvotes = 1
|
c.upvotes = 1
|
||||||
|
@ -287,8 +288,8 @@ def edit_comment(cid, v):
|
||||||
days=1)
|
days=1)
|
||||||
|
|
||||||
for comment in similar_comments:
|
for comment in similar_comments:
|
||||||
comment.is_banned = True
|
comment.state_mod = StateMod.Removed
|
||||||
comment.ban_reason = "AutoJanny"
|
comment.state_mod_set_by = "AutoJanny"
|
||||||
g.db.add(comment)
|
g.db.add(comment)
|
||||||
|
|
||||||
abort(403, "Too much spam!")
|
abort(403, "Too much spam!")
|
||||||
|
@ -313,7 +314,7 @@ def edit_comment(cid, v):
|
||||||
|
|
||||||
g.db.add(c)
|
g.db.add(c)
|
||||||
|
|
||||||
if c.filter_state != 'filtered':
|
if c.state_mod == StateMod.Visible:
|
||||||
notify_users = NOTIFY_USERS(body, v)
|
notify_users = NOTIFY_USERS(body, v)
|
||||||
|
|
||||||
for x in notify_users:
|
for x in notify_users:
|
||||||
|
|
|
@ -3,6 +3,7 @@ from sqlalchemy.orm import Query
|
||||||
import files.helpers.listing as listing
|
import files.helpers.listing as listing
|
||||||
from files.__main__ import app, limiter
|
from files.__main__ import app, limiter
|
||||||
from files.classes.submission import Submission
|
from files.classes.submission import Submission
|
||||||
|
from files.classes.visstate import StateMod
|
||||||
from files.helpers.comments import comment_filter_moderated
|
from files.helpers.comments import comment_filter_moderated
|
||||||
from files.helpers.contentsorting import (apply_time_filter,
|
from files.helpers.contentsorting import (apply_time_filter,
|
||||||
sort_comment_results, sort_objects)
|
sort_comment_results, sort_objects)
|
||||||
|
@ -26,7 +27,7 @@ def unread(v):
|
||||||
listing = g.db.query(Notification, Comment).join(Comment, Notification.comment_id == Comment.id).filter(
|
listing = g.db.query(Notification, Comment).join(Comment, Notification.comment_id == Comment.id).filter(
|
||||||
Notification.read == False,
|
Notification.read == False,
|
||||||
Notification.user_id == v.id,
|
Notification.user_id == v.id,
|
||||||
Comment.is_banned == False,
|
Comment.state_mod == StateMod.Visible,
|
||||||
Comment.state_user_deleted_utc == None,
|
Comment.state_user_deleted_utc == None,
|
||||||
Comment.author_id != AUTOJANNY_ID,
|
Comment.author_id != AUTOJANNY_ID,
|
||||||
).order_by(Notification.created_utc.desc()).all()
|
).order_by(Notification.created_utc.desc()).all()
|
||||||
|
@ -100,7 +101,7 @@ def notifications(v):
|
||||||
else:
|
else:
|
||||||
comments = g.db.query(Comment, Notification).join(Notification, Notification.comment_id == Comment.id).filter(
|
comments = g.db.query(Comment, Notification).join(Notification, Notification.comment_id == Comment.id).filter(
|
||||||
Notification.user_id == v.id,
|
Notification.user_id == v.id,
|
||||||
Comment.is_banned == False,
|
Comment.state_mod == StateMod.Visible,
|
||||||
Comment.state_user_deleted_utc == None,
|
Comment.state_user_deleted_utc == None,
|
||||||
Comment.author_id != AUTOJANNY_ID,
|
Comment.author_id != AUTOJANNY_ID,
|
||||||
Comment.body_html.notlike('%<p>New site mention: <a href="https://old.reddit.com/r/%')
|
Comment.body_html.notlike('%<p>New site mention: <a href="https://old.reddit.com/r/%')
|
||||||
|
@ -250,7 +251,7 @@ def changelog(v):
|
||||||
|
|
||||||
@app.get("/random_post")
|
@app.get("/random_post")
|
||||||
def random_post():
|
def random_post():
|
||||||
p = g.db.query(Submission.id).filter(Submission.state_user_deleted_utc == None, Submission.is_banned == False, Submission.private == False).order_by(func.random()).first()
|
p = g.db.query(Submission.id).filter(Submission.state_user_deleted_utc == None, Submission.state_mod == StateMod.Visible, Submission.private == False).order_by(func.random()).first()
|
||||||
|
|
||||||
if p: p = p[0]
|
if p: p = p[0]
|
||||||
else: abort(404)
|
else: abort(404)
|
||||||
|
@ -307,11 +308,10 @@ def get_comments_idlist(page=1, v=None, sort="new", t="all", gt=0, lt=0):
|
||||||
if v.admin_level < 2:
|
if v.admin_level < 2:
|
||||||
comments = comments.filter(
|
comments = comments.filter(
|
||||||
Comment.author_id.notin_(v.userblocks),
|
Comment.author_id.notin_(v.userblocks),
|
||||||
Comment.is_banned == False,
|
Comment.state_mod == StateMod.Visible,
|
||||||
Comment.state_user_deleted_utc == None,
|
Comment.state_user_deleted_utc == None,
|
||||||
Submission.private == False, # comment parent post not private
|
Submission.private == False, # comment parent post not private
|
||||||
User.shadowbanned == None, # comment author not shadowbanned
|
User.shadowbanned == None, # comment author not shadowbanned
|
||||||
Comment.filter_state.notin_(('filtered', 'removed')),
|
|
||||||
)
|
)
|
||||||
|
|
||||||
if gt: comments = comments.filter(Comment.created_utc > gt)
|
if gt: comments = comments.filter(Comment.created_utc > gt)
|
||||||
|
|
|
@ -62,7 +62,8 @@ def request_api_keys(v):
|
||||||
level=1,
|
level=1,
|
||||||
body_html=body_html,
|
body_html=body_html,
|
||||||
sentto=MODMAIL_ID,
|
sentto=MODMAIL_ID,
|
||||||
distinguish_level=6
|
distinguish_level=6,
|
||||||
|
state_mod=StateMod.Visible,
|
||||||
)
|
)
|
||||||
g.db.add(new_comment)
|
g.db.add(new_comment)
|
||||||
g.db.flush()
|
g.db.flush()
|
||||||
|
|
|
@ -15,6 +15,7 @@ from sqlalchemy.orm import Query
|
||||||
import files.helpers.validators as validators
|
import files.helpers.validators as validators
|
||||||
from files.__main__ import app, db_session, limiter
|
from files.__main__ import app, db_session, limiter
|
||||||
from files.classes import *
|
from files.classes import *
|
||||||
|
from files.classes.visstate import StateMod
|
||||||
from files.helpers.alerts import *
|
from files.helpers.alerts import *
|
||||||
from files.helpers.caching import invalidate_cache
|
from files.helpers.caching import invalidate_cache
|
||||||
from files.helpers.config.const import *
|
from files.helpers.config.const import *
|
||||||
|
@ -120,7 +121,7 @@ def post_id(pid, anything=None, v=None):
|
||||||
|
|
||||||
if request.headers.get("Authorization"): return post.json
|
if request.headers.get("Authorization"): return post.json
|
||||||
else:
|
else:
|
||||||
if post.is_banned and not (v and (v.admin_level >= 2 or post.author_id == v.id)): template = "submission_banned.html"
|
if post.state_mod != StateMod.Visible and not (v and (v.admin_level >= 2 or post.author_id == v.id)): template = "submission_banned.html"
|
||||||
else: template = "submission.html"
|
else: template = "submission.html"
|
||||||
return render_template(template, v=v, p=post, ids=list(ids), sort=sort, render_replies=True, offset=offset)
|
return render_template(template, v=v, p=post, ids=list(ids), sort=sort, render_replies=True, offset=offset)
|
||||||
|
|
||||||
|
@ -431,7 +432,7 @@ def api_is_repost():
|
||||||
repost = g.db.query(Submission).filter(
|
repost = g.db.query(Submission).filter(
|
||||||
Submission.url.ilike(search_url),
|
Submission.url.ilike(search_url),
|
||||||
Submission.state_user_deleted_utc == None,
|
Submission.state_user_deleted_utc == None,
|
||||||
Submission.is_banned == False
|
Submission.state_mod == StateMod.Visible
|
||||||
).first()
|
).first()
|
||||||
if repost: return {'permalink': repost.permalink}
|
if repost: return {'permalink': repost.permalink}
|
||||||
else: return {'permalink': ''}
|
else: return {'permalink': ''}
|
||||||
|
@ -468,9 +469,9 @@ def _do_antispam_submission_check(v:User, validated:validators.ValidatedSubmissi
|
||||||
|
|
||||||
v.ban(reason="Spamming.", days=1)
|
v.ban(reason="Spamming.", days=1)
|
||||||
for post in similar_posts + similar_urls:
|
for post in similar_posts + similar_urls:
|
||||||
post.is_banned = True
|
post.state_mod = StateMod.Removed
|
||||||
|
post.state_mod_set_by = "AutoJanny"
|
||||||
post.is_pinned = False
|
post.is_pinned = False
|
||||||
post.ban_reason = "AutoJanny"
|
|
||||||
g.db.add(post)
|
g.db.add(post)
|
||||||
ma=ModAction(
|
ma=ModAction(
|
||||||
user_id=AUTOJANNY_ID,
|
user_id=AUTOJANNY_ID,
|
||||||
|
@ -497,7 +498,7 @@ def _duplicate_check(search_url:Optional[str]) -> Optional[werkzeug.wrappers.Res
|
||||||
repost = g.db.query(Submission).filter(
|
repost = g.db.query(Submission).filter(
|
||||||
func.lower(Submission.url) == search_url.lower(),
|
func.lower(Submission.url) == search_url.lower(),
|
||||||
Submission.state_user_deleted_utc == None,
|
Submission.state_user_deleted_utc == None,
|
||||||
Submission.is_banned == False
|
Submission.state_mod == StateMod.Visible
|
||||||
).first()
|
).first()
|
||||||
if repost and SITE != 'localhost':
|
if repost and SITE != 'localhost':
|
||||||
return redirect(repost.permalink)
|
return redirect(repost.permalink)
|
||||||
|
@ -577,7 +578,7 @@ def submit_post(v):
|
||||||
title=validated_post.title,
|
title=validated_post.title,
|
||||||
title_html=validated_post.title_html,
|
title_html=validated_post.title_html,
|
||||||
ghost=False,
|
ghost=False,
|
||||||
filter_state='filtered' if v.admin_level == 0 and app.config['SETTINGS']['FilterNewPosts'] else 'normal',
|
state_mod=StateMod.Filtered if v.admin_level == 0 and app.config['SETTINGS']['FilterNewPosts'] else StateMod.Visible,
|
||||||
thumburl=validated_post.thumburl
|
thumburl=validated_post.thumburl
|
||||||
)
|
)
|
||||||
post.submit(g.db)
|
post.submit(g.db)
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
from flask import g
|
from flask import g
|
||||||
|
|
||||||
from files.__main__ import app, limiter
|
from files.__main__ import app, limiter
|
||||||
|
from files.classes.visstate import StateReport
|
||||||
from files.helpers.get import *
|
from files.helpers.get import *
|
||||||
from files.helpers.sanitize import filter_emojis_only
|
from files.helpers.sanitize import filter_emojis_only
|
||||||
from files.helpers.wrappers import *
|
from files.helpers.wrappers import *
|
||||||
|
@ -31,8 +32,8 @@ def api_flag_post(pid, v):
|
||||||
# We only want to notify if the user is not permabanned
|
# We only want to notify if the user is not permabanned
|
||||||
if not v.is_suspended_permanently:
|
if not v.is_suspended_permanently:
|
||||||
g.db.query(Submission) \
|
g.db.query(Submission) \
|
||||||
.where(Submission.id == post.id, Submission.filter_state != 'ignored') \
|
.where(Submission.id == post.id, Submission.state_report != StateReport.Ignored) \
|
||||||
.update({Submission.filter_state: 'reported'})
|
.update({Submission.state_report: StateReport.Reported})
|
||||||
|
|
||||||
g.db.commit()
|
g.db.commit()
|
||||||
|
|
||||||
|
@ -53,8 +54,9 @@ def api_flag_comment(cid, v):
|
||||||
# We only want to notify if the user is not permabanned
|
# We only want to notify if the user is not permabanned
|
||||||
if not v.is_suspended_permanently:
|
if not v.is_suspended_permanently:
|
||||||
g.db.query(Comment) \
|
g.db.query(Comment) \
|
||||||
.where(Comment.id == comment.id, Comment.filter_state != 'ignored') \
|
.where(Comment.id == comment.id, Comment.state_report != StateReport.Ignored) \
|
||||||
.update({Comment.filter_state: 'reported'})
|
.update({Comment.state_report: StateReport.Reported})
|
||||||
|
|
||||||
|
|
||||||
g.db.commit()
|
g.db.commit()
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
from sqlalchemy import *
|
from sqlalchemy import *
|
||||||
|
|
||||||
from files.__main__ import app
|
from files.__main__ import app
|
||||||
|
from files.classes.visstate import StateMod
|
||||||
from files.helpers.contentsorting import apply_time_filter, sort_objects
|
from files.helpers.contentsorting import apply_time_filter, sort_objects
|
||||||
from files.helpers.strings import sql_ilike_clean
|
from files.helpers.strings import sql_ilike_clean
|
||||||
from files.helpers.wrappers import *
|
from files.helpers.wrappers import *
|
||||||
|
@ -44,9 +45,9 @@ def searchposts(v):
|
||||||
if not (v and v.paid_dues): posts = posts.filter_by(club=False)
|
if not (v and v.paid_dues): posts = posts.filter_by(club=False)
|
||||||
|
|
||||||
if v and v.admin_level < 2:
|
if v and v.admin_level < 2:
|
||||||
posts = posts.filter(Submission.state_user_deleted_utc == None, Submission.is_banned == False, Submission.private == False, Submission.author_id.notin_(v.userblocks))
|
posts = posts.filter(Submission.state_user_deleted_utc == None, Submission.state_mod == StateMod.Visible, Submission.private == False, Submission.author_id.notin_(v.userblocks))
|
||||||
elif not v:
|
elif not v:
|
||||||
posts = posts.filter(Submission.state_user_deleted_utc == None, Submission.is_banned == False, Submission.private == False)
|
posts = posts.filter(Submission.state_user_deleted_utc == None, Submission.state_mod == StateMod.Visible, Submission.private == False)
|
||||||
|
|
||||||
|
|
||||||
if 'author' in criteria:
|
if 'author' in criteria:
|
||||||
|
@ -168,10 +169,10 @@ def searchcomments(v):
|
||||||
|
|
||||||
if v and v.admin_level < 2:
|
if v and v.admin_level < 2:
|
||||||
private = [x[0] for x in g.db.query(Submission.id).filter(Submission.private == True).all()]
|
private = [x[0] for x in g.db.query(Submission.id).filter(Submission.private == True).all()]
|
||||||
comments = comments.filter(Comment.author_id.notin_(v.userblocks), Comment.is_banned==False, Comment.state_user_deleted_utc == None, Comment.parent_submission.notin_(private))
|
comments = comments.filter(Comment.author_id.notin_(v.userblocks), Comment.state_mod == StateMod.Visible, Comment.state_user_deleted_utc == None, Comment.parent_submission.notin_(private))
|
||||||
elif not v:
|
elif not v:
|
||||||
private = [x[0] for x in g.db.query(Submission.id).filter(Submission.private == True).all()]
|
private = [x[0] for x in g.db.query(Submission.id).filter(Submission.private == True).all()]
|
||||||
comments = comments.filter(Comment.is_banned==False, Comment.state_user_deleted_utc == None, Comment.parent_submission.notin_(private))
|
comments = comments.filter(Comment.state_mod == StateMod.Visible, Comment.state_user_deleted_utc == None, Comment.parent_submission.notin_(private))
|
||||||
|
|
||||||
|
|
||||||
if not (v and v.paid_dues):
|
if not (v and v.paid_dues):
|
||||||
|
|
|
@ -6,6 +6,7 @@ from sqlalchemy import func
|
||||||
from files.classes.award import AWARDS
|
from files.classes.award import AWARDS
|
||||||
from files.classes.badges import BadgeDef
|
from files.classes.badges import BadgeDef
|
||||||
from files.classes.mod_logs import ACTIONTYPES, ACTIONTYPES2
|
from files.classes.mod_logs import ACTIONTYPES, ACTIONTYPES2
|
||||||
|
from files.classes.visstate import StateMod
|
||||||
from files.helpers.alerts import *
|
from files.helpers.alerts import *
|
||||||
from files.helpers.captcha import validate_captcha
|
from files.helpers.captcha import validate_captcha
|
||||||
from files.helpers.config.const import *
|
from files.helpers.config.const import *
|
||||||
|
@ -77,13 +78,13 @@ def participation_stats(v):
|
||||||
"signups last 24h": users.filter(User.created_utc > day).count(),
|
"signups last 24h": users.filter(User.created_utc > day).count(),
|
||||||
"total posts": submissions.count(),
|
"total posts": submissions.count(),
|
||||||
"posting users": g.db.query(Submission.author_id).distinct().count(),
|
"posting users": g.db.query(Submission.author_id).distinct().count(),
|
||||||
"listed posts": submissions.filter_by(is_banned=False).filter(Submission.state_user_deleted_utc == None).count(),
|
"listed posts": submissions.filter_by(Submission.state_mod == StateMod.Visible).filter(Submission.state_user_deleted_utc == None).count(),
|
||||||
"removed posts (by admins)": submissions.filter_by(is_banned=True).count(),
|
"removed posts (by admins)": submissions.filter_by(Submission.state_mod != StateMod.Visible).count(),
|
||||||
"deleted posts (by author)": submissions.filter(Submission.state_user_deleted_utc != None).count(),
|
"deleted posts (by author)": submissions.filter(Submission.state_user_deleted_utc != None).count(),
|
||||||
"posts last 24h": submissions.filter(Submission.created_utc > day).count(),
|
"posts last 24h": submissions.filter(Submission.created_utc > day).count(),
|
||||||
"total comments": comments.filter(Comment.author_id.notin_((AUTOJANNY_ID,NOTIFICATIONS_ID))).count(),
|
"total comments": comments.filter(Comment.author_id.notin_((AUTOJANNY_ID,NOTIFICATIONS_ID))).count(),
|
||||||
"commenting users": g.db.query(Comment.author_id).distinct().count(),
|
"commenting users": g.db.query(Comment.author_id).distinct().count(),
|
||||||
"removed comments (by admins)": comments.filter_by(is_banned=True).count(),
|
"removed comments (by admins)": comments.filter_by(Comment.state_mod != StateMod.Visible).count(),
|
||||||
"deleted comments (by author)": comments.filter(Comment.state_user_deleted_utc != None).count(),
|
"deleted comments (by author)": comments.filter(Comment.state_user_deleted_utc != None).count(),
|
||||||
"comments last_24h": comments.filter(Comment.created_utc > day, Comment.author_id.notin_((AUTOJANNY_ID,NOTIFICATIONS_ID))).count(),
|
"comments last_24h": comments.filter(Comment.created_utc > day, Comment.author_id.notin_((AUTOJANNY_ID,NOTIFICATIONS_ID))).count(),
|
||||||
"post votes": g.db.query(Vote.submission_id).count(),
|
"post votes": g.db.query(Vote.submission_id).count(),
|
||||||
|
@ -142,9 +143,9 @@ def cached_chart(kind, site):
|
||||||
|
|
||||||
daily_signups = [g.db.query(User.id).filter(User.created_utc < day_cutoffs[i], User.created_utc > day_cutoffs[i + 1]).count() for i in range(len(day_cutoffs) - 1)][::-1]
|
daily_signups = [g.db.query(User.id).filter(User.created_utc < day_cutoffs[i], User.created_utc > day_cutoffs[i + 1]).count() for i in range(len(day_cutoffs) - 1)][::-1]
|
||||||
|
|
||||||
post_stats = [g.db.query(Submission.id).filter(Submission.created_utc < day_cutoffs[i], Submission.created_utc > day_cutoffs[i + 1], Submission.is_banned == False).count() for i in range(len(day_cutoffs) - 1)][::-1]
|
post_stats = [g.db.query(Submission.id).filter(Submission.created_utc < day_cutoffs[i], Submission.created_utc > day_cutoffs[i + 1], Submission.state_mod == StateMod.Visible).count() for i in range(len(day_cutoffs) - 1)][::-1]
|
||||||
|
|
||||||
comment_stats = [g.db.query(Comment.id).filter(Comment.created_utc < day_cutoffs[i], Comment.created_utc > day_cutoffs[i + 1],Comment.is_banned == False, Comment.author_id.notin_((AUTOJANNY_ID,NOTIFICATIONS_ID))).count() for i in range(len(day_cutoffs) - 1)][::-1]
|
comment_stats = [g.db.query(Comment.id).filter(Comment.created_utc < day_cutoffs[i], Comment.created_utc > day_cutoffs[i + 1],Comment.state_mod == StateMod.Visible, Comment.author_id.notin_((AUTOJANNY_ID,NOTIFICATIONS_ID))).count() for i in range(len(day_cutoffs) - 1)][::-1]
|
||||||
|
|
||||||
plt.rcParams["figure.figsize"] = (30, 20)
|
plt.rcParams["figure.figsize"] = (30, 20)
|
||||||
|
|
||||||
|
@ -310,6 +311,7 @@ def submit_contact(v: Optional[User]):
|
||||||
level=1,
|
level=1,
|
||||||
body_html=html,
|
body_html=html,
|
||||||
sentto=MODMAIL_ID,
|
sentto=MODMAIL_ID,
|
||||||
|
state_mod=StateMod.Visible,
|
||||||
)
|
)
|
||||||
g.db.add(new_comment)
|
g.db.add(new_comment)
|
||||||
g.db.flush()
|
g.db.flush()
|
||||||
|
|
|
@ -12,6 +12,7 @@ from files.__main__ import app, cache, limiter
|
||||||
from files.classes.leaderboard import (BadgeMarseyLeaderboard, LeaderboardMeta,
|
from files.classes.leaderboard import (BadgeMarseyLeaderboard, LeaderboardMeta,
|
||||||
SimpleLeaderboard, UserBlockLeaderboard)
|
SimpleLeaderboard, UserBlockLeaderboard)
|
||||||
from files.classes.views import ViewerRelationship
|
from files.classes.views import ViewerRelationship
|
||||||
|
from files.classes.visstate import StateMod
|
||||||
from files.helpers.alerts import *
|
from files.helpers.alerts import *
|
||||||
from files.helpers.assetcache import assetcache_path
|
from files.helpers.assetcache import assetcache_path
|
||||||
from files.helpers.config.const import *
|
from files.helpers.config.const import *
|
||||||
|
@ -39,7 +40,7 @@ def upvoters_posts(v, username, uid):
|
||||||
|
|
||||||
page = max(1, int(request.values.get("page", 1)))
|
page = max(1, int(request.values.get("page", 1)))
|
||||||
|
|
||||||
listing = g.db.query(Submission).join(Vote, Vote.submission_id==Submission.id).filter(Submission.ghost == False, Submission.is_banned == False, Submission.state_user_deleted_utc == None, Vote.vote_type==1, Submission.author_id==id, Vote.user_id==uid).order_by(Submission.created_utc.desc()).offset(25 * (page - 1)).limit(26).all()
|
listing = g.db.query(Submission).join(Vote, Vote.submission_id==Submission.id).filter(Submission.ghost == False, Submission.state_mod == StateMod.Visible, Submission.state_user_deleted_utc == None, Vote.vote_type==1, Submission.author_id==id, Vote.user_id==uid).order_by(Submission.created_utc.desc()).offset(25 * (page - 1)).limit(26).all()
|
||||||
|
|
||||||
listing = [p.id for p in listing]
|
listing = [p.id for p in listing]
|
||||||
next_exists = len(listing) > 25
|
next_exists = len(listing) > 25
|
||||||
|
@ -60,7 +61,7 @@ def upvoters_comments(v, username, uid):
|
||||||
|
|
||||||
page = max(1, int(request.values.get("page", 1)))
|
page = max(1, int(request.values.get("page", 1)))
|
||||||
|
|
||||||
listing = g.db.query(Comment).join(CommentVote, CommentVote.comment_id==Comment.id).filter(Comment.ghost == False, Comment.is_banned == False, Comment.state_user_deleted_utc == None, CommentVote.vote_type==1, Comment.author_id==id, CommentVote.user_id==uid).order_by(Comment.created_utc.desc()).offset(25 * (page - 1)).limit(26).all()
|
listing = g.db.query(Comment).join(CommentVote, CommentVote.comment_id==Comment.id).filter(Comment.ghost == False, Comment.state_mod == StateMod.Visible, Comment.state_user_deleted_utc == None, CommentVote.vote_type==1, Comment.author_id==id, CommentVote.user_id==uid).order_by(Comment.created_utc.desc()).offset(25 * (page - 1)).limit(26).all()
|
||||||
|
|
||||||
listing = [c.id for c in listing]
|
listing = [c.id for c in listing]
|
||||||
next_exists = len(listing) > 25
|
next_exists = len(listing) > 25
|
||||||
|
@ -81,7 +82,7 @@ def downvoters_posts(v, username, uid):
|
||||||
|
|
||||||
page = max(1, int(request.values.get("page", 1)))
|
page = max(1, int(request.values.get("page", 1)))
|
||||||
|
|
||||||
listing = g.db.query(Submission).join(Vote, Vote.submission_id==Submission.id).filter(Submission.ghost == False, Submission.is_banned == False, Submission.state_user_deleted_utc == None, Vote.vote_type==-1, Submission.author_id==id, Vote.user_id==uid).order_by(Submission.created_utc.desc()).offset(25 * (page - 1)).limit(26).all()
|
listing = g.db.query(Submission).join(Vote, Vote.submission_id==Submission.id).filter(Submission.ghost == False, Submission.state_mod == StateMod.Visible, Submission.state_user_deleted_utc == None, Vote.vote_type==-1, Submission.author_id==id, Vote.user_id==uid).order_by(Submission.created_utc.desc()).offset(25 * (page - 1)).limit(26).all()
|
||||||
|
|
||||||
listing = [p.id for p in listing]
|
listing = [p.id for p in listing]
|
||||||
next_exists = len(listing) > 25
|
next_exists = len(listing) > 25
|
||||||
|
@ -102,7 +103,7 @@ def downvoters_comments(v, username, uid):
|
||||||
|
|
||||||
page = max(1, int(request.values.get("page", 1)))
|
page = max(1, int(request.values.get("page", 1)))
|
||||||
|
|
||||||
listing = g.db.query(Comment).join(CommentVote, CommentVote.comment_id==Comment.id).filter(Comment.ghost == False, Comment.is_banned == False, Comment.state_user_deleted_utc == None, CommentVote.vote_type==-1, Comment.author_id==id, CommentVote.user_id==uid).order_by(Comment.created_utc.desc()).offset(25 * (page - 1)).limit(26).all()
|
listing = g.db.query(Comment).join(CommentVote, CommentVote.comment_id==Comment.id).filter(Comment.ghost == False, Comment.state_mod == StateMod.Visible, Comment.state_user_deleted_utc == None, CommentVote.vote_type==-1, Comment.author_id==id, CommentVote.user_id==uid).order_by(Comment.created_utc.desc()).offset(25 * (page - 1)).limit(26).all()
|
||||||
|
|
||||||
listing = [c.id for c in listing]
|
listing = [c.id for c in listing]
|
||||||
next_exists = len(listing) > 25
|
next_exists = len(listing) > 25
|
||||||
|
@ -122,7 +123,7 @@ def upvoting_posts(v, username, uid):
|
||||||
|
|
||||||
page = max(1, int(request.values.get("page", 1)))
|
page = max(1, int(request.values.get("page", 1)))
|
||||||
|
|
||||||
listing = g.db.query(Submission).join(Vote, Vote.submission_id==Submission.id).filter(Submission.ghost == False, Submission.is_banned == False, Submission.state_user_deleted_utc == None, Vote.vote_type==1, Vote.user_id==id, Submission.author_id==uid).order_by(Submission.created_utc.desc()).offset(25 * (page - 1)).limit(26).all()
|
listing = g.db.query(Submission).join(Vote, Vote.submission_id==Submission.id).filter(Submission.ghost == False, Submission.state_mod == StateMod.Visible, Submission.state_user_deleted_utc == None, Vote.vote_type==1, Vote.user_id==id, Submission.author_id==uid).order_by(Submission.created_utc.desc()).offset(25 * (page - 1)).limit(26).all()
|
||||||
|
|
||||||
listing = [p.id for p in listing]
|
listing = [p.id for p in listing]
|
||||||
next_exists = len(listing) > 25
|
next_exists = len(listing) > 25
|
||||||
|
@ -143,7 +144,7 @@ def upvoting_comments(v, username, uid):
|
||||||
|
|
||||||
page = max(1, int(request.values.get("page", 1)))
|
page = max(1, int(request.values.get("page", 1)))
|
||||||
|
|
||||||
listing = g.db.query(Comment).join(CommentVote, CommentVote.comment_id==Comment.id).filter(Comment.ghost == False, Comment.is_banned == False, Comment.state_user_deleted_utc == None, CommentVote.vote_type==1, CommentVote.user_id==id, Comment.author_id==uid).order_by(Comment.created_utc.desc()).offset(25 * (page - 1)).limit(26).all()
|
listing = g.db.query(Comment).join(CommentVote, CommentVote.comment_id==Comment.id).filter(Comment.ghost == False, Comment.state_mod == StateMod.Visible, Comment.state_user_deleted_utc == None, CommentVote.vote_type==1, CommentVote.user_id==id, Comment.author_id==uid).order_by(Comment.created_utc.desc()).offset(25 * (page - 1)).limit(26).all()
|
||||||
|
|
||||||
listing = [c.id for c in listing]
|
listing = [c.id for c in listing]
|
||||||
next_exists = len(listing) > 25
|
next_exists = len(listing) > 25
|
||||||
|
@ -164,7 +165,7 @@ def downvoting_posts(v, username, uid):
|
||||||
|
|
||||||
page = max(1, int(request.values.get("page", 1)))
|
page = max(1, int(request.values.get("page", 1)))
|
||||||
|
|
||||||
listing = g.db.query(Submission).join(Vote, Vote.submission_id==Submission.id).filter(Submission.ghost == False, Submission.is_banned == False, Submission.state_user_deleted_utc == None, Vote.vote_type==-1, Vote.user_id==id, Submission.author_id==uid).order_by(Submission.created_utc.desc()).offset(25 * (page - 1)).limit(26).all()
|
listing = g.db.query(Submission).join(Vote, Vote.submission_id==Submission.id).filter(Submission.ghost == False, Submission.state_mod == StateMod.Visible, Submission.state_user_deleted_utc == None, Vote.vote_type==-1, Vote.user_id==id, Submission.author_id==uid).order_by(Submission.created_utc.desc()).offset(25 * (page - 1)).limit(26).all()
|
||||||
|
|
||||||
listing = [p.id for p in listing]
|
listing = [p.id for p in listing]
|
||||||
next_exists = len(listing) > 25
|
next_exists = len(listing) > 25
|
||||||
|
@ -185,7 +186,7 @@ def downvoting_comments(v, username, uid):
|
||||||
|
|
||||||
page = max(1, int(request.values.get("page", 1)))
|
page = max(1, int(request.values.get("page", 1)))
|
||||||
|
|
||||||
listing = g.db.query(Comment).join(CommentVote, CommentVote.comment_id==Comment.id).filter(Comment.ghost == False, Comment.is_banned == False, Comment.state_user_deleted_utc == None, CommentVote.vote_type==-1, CommentVote.user_id==id, Comment.author_id==uid).order_by(Comment.created_utc.desc()).offset(25 * (page - 1)).limit(26).all()
|
listing = g.db.query(Comment).join(CommentVote, CommentVote.comment_id==Comment.id).filter(Comment.ghost == False, Comment.state_mod == StateMod.Visible, Comment.state_user_deleted_utc == None, CommentVote.vote_type==-1, CommentVote.user_id==id, Comment.author_id==uid).order_by(Comment.created_utc.desc()).offset(25 * (page - 1)).limit(26).all()
|
||||||
|
|
||||||
listing = [c.id for c in listing]
|
listing = [c.id for c in listing]
|
||||||
next_exists = len(listing) > 25
|
next_exists = len(listing) > 25
|
||||||
|
@ -200,9 +201,9 @@ def downvoting_comments(v, username, uid):
|
||||||
def upvoters(v, username):
|
def upvoters(v, username):
|
||||||
id = get_user(username).id
|
id = get_user(username).id
|
||||||
|
|
||||||
votes = g.db.query(Vote.user_id, func.count(Vote.user_id)).join(Submission, Vote.submission_id==Submission.id).filter(Submission.ghost == False, Submission.is_banned == False, Submission.state_user_deleted_utc == None, Vote.vote_type==1, Submission.author_id==id).group_by(Vote.user_id).order_by(func.count(Vote.user_id).desc()).all()
|
votes = g.db.query(Vote.user_id, func.count(Vote.user_id)).join(Submission, Vote.submission_id==Submission.id).filter(Submission.ghost == False, Submission.state_mod == StateMod.Visible, Submission.state_user_deleted_utc == None, Vote.vote_type==1, Submission.author_id==id).group_by(Vote.user_id).order_by(func.count(Vote.user_id).desc()).all()
|
||||||
|
|
||||||
votes2 = g.db.query(CommentVote.user_id, func.count(CommentVote.user_id)).join(Comment, CommentVote.comment_id==Comment.id).filter(Comment.ghost == False, Comment.is_banned == False, Comment.state_user_deleted_utc == None, CommentVote.vote_type==1, Comment.author_id==id).group_by(CommentVote.user_id).order_by(func.count(CommentVote.user_id).desc()).all()
|
votes2 = g.db.query(CommentVote.user_id, func.count(CommentVote.user_id)).join(Comment, CommentVote.comment_id==Comment.id).filter(Comment.ghost == False, Comment.state_mod == StateMod.Visible, Comment.state_user_deleted_utc == None, CommentVote.vote_type==1, Comment.author_id==id).group_by(CommentVote.user_id).order_by(func.count(CommentVote.user_id).desc()).all()
|
||||||
|
|
||||||
votes = Counter(dict(votes)) + Counter(dict(votes2))
|
votes = Counter(dict(votes)) + Counter(dict(votes2))
|
||||||
|
|
||||||
|
@ -226,9 +227,9 @@ def upvoters(v, username):
|
||||||
def downvoters(v, username):
|
def downvoters(v, username):
|
||||||
id = get_user(username).id
|
id = get_user(username).id
|
||||||
|
|
||||||
votes = g.db.query(Vote.user_id, func.count(Vote.user_id)).join(Submission, Vote.submission_id==Submission.id).filter(Submission.ghost == False, Submission.is_banned == False, Submission.state_user_deleted_utc == None, Vote.vote_type==-1, Submission.author_id==id).group_by(Vote.user_id).order_by(func.count(Vote.user_id).desc()).all()
|
votes = g.db.query(Vote.user_id, func.count(Vote.user_id)).join(Submission, Vote.submission_id==Submission.id).filter(Submission.ghost == False, Submission.state_mod == StateMod.Visible, Submission.state_user_deleted_utc == None, Vote.vote_type==-1, Submission.author_id==id).group_by(Vote.user_id).order_by(func.count(Vote.user_id).desc()).all()
|
||||||
|
|
||||||
votes2 = g.db.query(CommentVote.user_id, func.count(CommentVote.user_id)).join(Comment, CommentVote.comment_id==Comment.id).filter(Comment.ghost == False, Comment.is_banned == False, Comment.state_user_deleted_utc == None, CommentVote.vote_type==-1, Comment.author_id==id).group_by(CommentVote.user_id).order_by(func.count(CommentVote.user_id).desc()).all()
|
votes2 = g.db.query(CommentVote.user_id, func.count(CommentVote.user_id)).join(Comment, CommentVote.comment_id==Comment.id).filter(Comment.ghost == False, Comment.state_mod == StateMod.Visible, Comment.state_user_deleted_utc == None, CommentVote.vote_type==-1, Comment.author_id==id).group_by(CommentVote.user_id).order_by(func.count(CommentVote.user_id).desc()).all()
|
||||||
|
|
||||||
votes = Counter(dict(votes)) + Counter(dict(votes2))
|
votes = Counter(dict(votes)) + Counter(dict(votes2))
|
||||||
|
|
||||||
|
@ -250,9 +251,9 @@ def downvoters(v, username):
|
||||||
def upvoting(v, username):
|
def upvoting(v, username):
|
||||||
id = get_user(username).id
|
id = get_user(username).id
|
||||||
|
|
||||||
votes = g.db.query(Submission.author_id, func.count(Submission.author_id)).join(Vote, Vote.submission_id==Submission.id).filter(Submission.ghost == False, Submission.is_banned == False, Submission.state_user_deleted_utc == None, Vote.vote_type==1, Vote.user_id==id).group_by(Submission.author_id).order_by(func.count(Submission.author_id).desc()).all()
|
votes = g.db.query(Submission.author_id, func.count(Submission.author_id)).join(Vote, Vote.submission_id==Submission.id).filter(Submission.ghost == False, Submission.state_mod == StateMod.Visible, Submission.state_user_deleted_utc == None, Vote.vote_type==1, Vote.user_id==id).group_by(Submission.author_id).order_by(func.count(Submission.author_id).desc()).all()
|
||||||
|
|
||||||
votes2 = g.db.query(Comment.author_id, func.count(Comment.author_id)).join(CommentVote, CommentVote.comment_id==Comment.id).filter(Comment.ghost == False, Comment.is_banned == False, Comment.state_user_deleted_utc == None, CommentVote.vote_type==1, CommentVote.user_id==id).group_by(Comment.author_id).order_by(func.count(Comment.author_id).desc()).all()
|
votes2 = g.db.query(Comment.author_id, func.count(Comment.author_id)).join(CommentVote, CommentVote.comment_id==Comment.id).filter(Comment.ghost == False, Comment.state_mod == StateMod.Visible, Comment.state_user_deleted_utc == None, CommentVote.vote_type==1, CommentVote.user_id==id).group_by(Comment.author_id).order_by(func.count(Comment.author_id).desc()).all()
|
||||||
|
|
||||||
votes = Counter(dict(votes)) + Counter(dict(votes2))
|
votes = Counter(dict(votes)) + Counter(dict(votes2))
|
||||||
|
|
||||||
|
@ -274,9 +275,9 @@ def upvoting(v, username):
|
||||||
def downvoting(v, username):
|
def downvoting(v, username):
|
||||||
id = get_user(username).id
|
id = get_user(username).id
|
||||||
|
|
||||||
votes = g.db.query(Submission.author_id, func.count(Submission.author_id)).join(Vote, Vote.submission_id==Submission.id).filter(Submission.ghost == False, Submission.is_banned == False, Submission.state_user_deleted_utc == None, Vote.vote_type==-1, Vote.user_id==id).group_by(Submission.author_id).order_by(func.count(Submission.author_id).desc()).all()
|
votes = g.db.query(Submission.author_id, func.count(Submission.author_id)).join(Vote, Vote.submission_id==Submission.id).filter(Submission.ghost == False, Submission.state_mod == StateMod.Visible, Submission.state_user_deleted_utc == None, Vote.vote_type==-1, Vote.user_id==id).group_by(Submission.author_id).order_by(func.count(Submission.author_id).desc()).all()
|
||||||
|
|
||||||
votes2 = g.db.query(Comment.author_id, func.count(Comment.author_id)).join(CommentVote, CommentVote.comment_id==Comment.id).filter(Comment.ghost == False, Comment.is_banned == False, Comment.state_user_deleted_utc == None, CommentVote.vote_type==-1, CommentVote.user_id==id).group_by(Comment.author_id).order_by(func.count(Comment.author_id).desc()).all()
|
votes2 = g.db.query(Comment.author_id, func.count(Comment.author_id)).join(CommentVote, CommentVote.comment_id==Comment.id).filter(Comment.ghost == False, Comment.state_mod == StateMod.Visible, Comment.state_user_deleted_utc == None, CommentVote.vote_type==-1, CommentVote.user_id==id).group_by(Comment.author_id).order_by(func.count(Comment.author_id).desc()).all()
|
||||||
|
|
||||||
votes = Counter(dict(votes)) + Counter(dict(votes2))
|
votes = Counter(dict(votes)) + Counter(dict(votes2))
|
||||||
|
|
||||||
|
@ -454,7 +455,8 @@ def message2(v, username):
|
||||||
parent_submission=None,
|
parent_submission=None,
|
||||||
level=1,
|
level=1,
|
||||||
sentto=user.id,
|
sentto=user.id,
|
||||||
body_html=body_html
|
body_html=body_html,
|
||||||
|
state_mod=StateMod.Visible,
|
||||||
)
|
)
|
||||||
g.db.add(c)
|
g.db.add(c)
|
||||||
g.db.flush()
|
g.db.flush()
|
||||||
|
@ -512,6 +514,7 @@ def messagereply(v):
|
||||||
level=parent.level + 1,
|
level=parent.level + 1,
|
||||||
sentto=user_id,
|
sentto=user_id,
|
||||||
body_html=body_html,
|
body_html=body_html,
|
||||||
|
state_mod=StateMod.Visible,
|
||||||
)
|
)
|
||||||
g.db.add(c)
|
g.db.add(c)
|
||||||
g.db.flush()
|
g.db.flush()
|
||||||
|
@ -755,9 +758,8 @@ def u_username_comments(username, v=None):
|
||||||
if not v or (v.id != u.id and v.admin_level < 2):
|
if not v or (v.id != u.id and v.admin_level < 2):
|
||||||
comments = comments.filter(
|
comments = comments.filter(
|
||||||
Comment.state_user_deleted_utc == None,
|
Comment.state_user_deleted_utc == None,
|
||||||
Comment.is_banned == False,
|
Comment.state_mod == StateMod.Visible,
|
||||||
Comment.ghost == False,
|
Comment.ghost == False,
|
||||||
(Comment.filter_state != 'filtered') & (Comment.filter_state != 'removed')
|
|
||||||
)
|
)
|
||||||
|
|
||||||
comments = apply_time_filter(comments, t, Comment)
|
comments = apply_time_filter(comments, t, Comment)
|
||||||
|
|
|
@ -4,6 +4,7 @@ from files.__main__ import app
|
||||||
from files.classes.comment import Comment
|
from files.classes.comment import Comment
|
||||||
from files.classes.flags import CommentFlag
|
from files.classes.flags import CommentFlag
|
||||||
from files.classes.user import User
|
from files.classes.user import User
|
||||||
|
from files.classes.visstate import StateReport
|
||||||
from files.classes.volunteer_janitor import VolunteerJanitorRecord, VolunteerJanitorResult
|
from files.classes.volunteer_janitor import VolunteerJanitorRecord, VolunteerJanitorResult
|
||||||
from files.helpers.volunteer_janitor import update_comment_badness
|
from files.helpers.volunteer_janitor import update_comment_badness
|
||||||
from files.routes.volunteer_common import VolunteerDuty
|
from files.routes.volunteer_common import VolunteerDuty
|
||||||
|
@ -43,7 +44,7 @@ def get_duty(u: User) -> Optional[VolunteerDutyJanitor]:
|
||||||
|
|
||||||
# find reported not-deleted comments not made by the current user
|
# find reported not-deleted comments not made by the current user
|
||||||
reported_comments = g.db.query(Comment) \
|
reported_comments = g.db.query(Comment) \
|
||||||
.where(Comment.filter_state == 'reported') \
|
.where(Comment.state_report == StateReport.Reported) \
|
||||||
.where(Comment.state_user_deleted_utc == None) \
|
.where(Comment.state_user_deleted_utc == None) \
|
||||||
.where(Comment.author_id != u.id) \
|
.where(Comment.author_id != u.id) \
|
||||||
.with_entities(Comment.id)
|
.with_entities(Comment.id)
|
||||||
|
|
|
@ -81,10 +81,10 @@
|
||||||
{%- include 'component/comment/user_info.html' -%}
|
{%- include 'component/comment/user_info.html' -%}
|
||||||
|
|
||||||
<div class="comment-body">
|
<div class="comment-body">
|
||||||
<div id="{% if comment_info and comment_info.id == c.id %}context{%else%}comment-{{c.id}}-only{% endif %}" class="{% if c.unread %}unread{% endif %} comment-{{c.id}}-only comment-anchor {% if comment_info and comment_info.id == c.id %}context{%endif%}{% if c.is_banned %} banned{% endif %}{% if c.state_user_deleted_utc %} deleted{% endif %}">
|
<div id="{% if comment_info and comment_info.id == c.id %}context{%else%}comment-{{c.id}}-only{% endif %}" class="{% if c.unread %}unread{% endif %} comment-{{c.id}}-only comment-anchor {% if comment_info and comment_info.id == c.id %}context{%endif%}{% if c.state_mod == StateMod.Removed %} removed{% endif %}{% if c.state_mod == StateMod.Filtered %} filtered{% endif %}{% if c.state_user_deleted_utc %} deleted{% endif %}">
|
||||||
{%- include 'component/comment/reports.html'-%}
|
{%- include 'component/comment/reports.html'-%}
|
||||||
{% if c.is_banned and c.ban_reason %} {# TODO: shouldn't be visible. See #359 #}
|
{% if c.state_mod == StateMod.Removed and c.state_mod_set_by and v and v.admin_level >= 2 %}
|
||||||
<div id="comment-banned-warning" class="comment-text text-removed mb-0">removed by @{{c.ban_reason}}</div>
|
<div id="comment-banned-warning" class="comment-text text-removed mb-0">removed by @{{c.state_mod_set_by}}</div>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
<div id="comment-text-{{c.id}}" class="comment-text mb-0">
|
<div id="comment-text-{{c.id}}" class="comment-text mb-0">
|
||||||
|
|
|
@ -19,7 +19,7 @@
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
{% if v and v.admin_level >= 2 and c.filter_state == 'filtered' %}
|
{% if v and v.admin_level >= 2 and c.state_mod == StateMod.Filtered %}
|
||||||
<button class="btn" role="button" id="filter-approve" onclick="filter_new_comment_status({{ c.id }}, 'normal')"><span>Approve</span></button>
|
<button class="btn" role="button" id="filter-approve" onclick="filter_new_comment_status({{ c.id }}, 'normal')"><span>Approve</span></button>
|
||||||
<button class="btn" role="button" id="filter-remove" onclick="filter_new_comment_status({{ c.id }}, 'removed')"><span>Remove</span></button>
|
<button class="btn" role="button" id="filter-remove" onclick="filter_new_comment_status({{ c.id }}, 'removed')"><span>Remove</span></button>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
@ -50,8 +50,8 @@
|
||||||
<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-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>
|
<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 %}
|
{% else %}
|
||||||
<button id="approve-{{c.id}}" class="dropdown-item list-inline-item d-none {% if c.is_banned %}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="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 not c.is_banned %}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>
|
<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 %}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
|
|
|
@ -31,8 +31,8 @@
|
||||||
<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>
|
<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>
|
||||||
<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>
|
<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>
|
||||||
{% else %}
|
{% else %}
|
||||||
<a id="remove2-{{c.id}}" class="{% if c.is_banned %}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="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="{% if not c.is_banned %}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>
|
<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 %}
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
{%- if v and c.filter_state == 'reported' and v.can_manage_reports() -%}
|
{%- if v and c.state_report == StateReport.Reported and v.can_manage_reports() -%}
|
||||||
<div id="flaggers-{{c.id}}" class="flaggers d-none">
|
<div id="flaggers-{{c.id}}" class="flaggers d-none">
|
||||||
<strong><i class="far fa-fw fa-flag"></i> Reports:</strong>
|
<strong><i class="far fa-fw fa-flag"></i> Reports:</strong>
|
||||||
<a class="btn btn-primary" style="margin:1px 5px" onclick="filter_new_comment_status({{c.id}}, 'normal')">Approve</a>
|
<a class="btn btn-primary" style="margin:1px 5px" onclick="filter_new_comment_status({{c.id}}, 'normal')">Approve</a>
|
||||||
|
|
|
@ -27,7 +27,7 @@
|
||||||
{% if c.bannedfor %}
|
{% if c.bannedfor %}
|
||||||
<a role="button"><i class="fas fa-hammer-crash text-danger" data-bs-toggle="tooltip" data-bs-placement="bottom" title="User was banned for this comment{% if c.author.banned_by %} by @{{c.author.banned_by.username}}{% endif %}"></i></a>
|
<a role="button"><i class="fas fa-hammer-crash text-danger" data-bs-toggle="tooltip" data-bs-placement="bottom" title="User was banned for this comment{% if c.author.banned_by %} by @{{c.author.banned_by.username}}{% endif %}"></i></a>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% if v and c.filter_state == 'reported' and v.can_manage_reports() %}
|
{% if v and c.state_report == StateReport.Reported and v.can_manage_reports() %}
|
||||||
<a class="btn btn-primary" id="report-btn-{{c.id}}" style="padding:1px 5px; font-size:10px" role="button" onclick="document.getElementById('flaggers-{{c.id}}').classList.toggle('d-none')">{{c.active_flags(v)}} Reports</a>
|
<a class="btn btn-primary" id="report-btn-{{c.id}}" style="padding:1px 5px; font-size:10px" role="button" onclick="document.getElementById('flaggers-{{c.id}}').classList.toggle('d-none')">{{c.active_flags(v)}} Reports</a>
|
||||||
<span class="volunteer_janitor_result_{{c.volunteer_janitor_css()}} volunteer_janitor_result">
|
<span class="volunteer_janitor_result_{{c.volunteer_janitor_css()}} volunteer_janitor_result">
|
||||||
{% if c.volunteer_janitor_is_unknown() %}
|
{% if c.volunteer_janitor_is_unknown() %}
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
<span class="mr-2 arrow-up comment-{{c.id}}-up active"></span>
|
<span class="mr-2 arrow-up comment-{{c.id}}-up active"></span>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
<span class="comment-mobile-score-{{c.id}} score comment-score-{{c.id}} {% if voted==1 %}score-up{% elif voted==-1%}score-down{% endif %}{% if c.controversial %} controversial{% endif %}"{% if not c.is_banned %} data-bs-toggle="tooltip" data-bs-placement="top" title="+{{ups}} | -{{downs}}"{% endif %}>{{score}}</span>
|
<span class="comment-mobile-score-{{c.id}} score comment-score-{{c.id}} {% if voted==1 %}score-up{% elif voted==-1%}score-down{% endif %}{% if c.controversial %} controversial{% endif %}"{% if c.state_mod == StateMod.Visible %} data-bs-toggle="tooltip" data-bs-placement="top" title="+{{ups}} | -{{downs}}"{% endif %}>{{score}}</span>
|
||||||
{% if voted==-1 %}
|
{% if voted==-1 %}
|
||||||
<span class="ml-2 my-0 arrow-down comment-{{c.id}}-down active"></span>
|
<span class="ml-2 my-0 arrow-down comment-{{c.id}}-down active"></span>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
@ -12,7 +12,7 @@
|
||||||
{% elif v %}
|
{% elif v %}
|
||||||
<li id="voting-{{c.id}}-mobile" class="voting list-inline-item d-md-none">
|
<li id="voting-{{c.id}}-mobile" class="voting list-inline-item d-md-none">
|
||||||
<span tabindex="0" role="button" onclick="vote('comment-mobile', '{{c.id}}', '1')" class="comment-mobile-{{c.id}}-up mx-0 pr-1 arrow-up upvote-button comment-{{c.id}}-up {% if voted==1 %}active{% endif %}"></span>
|
<span tabindex="0" role="button" onclick="vote('comment-mobile', '{{c.id}}', '1')" class="comment-mobile-{{c.id}}-up mx-0 pr-1 arrow-up upvote-button comment-{{c.id}}-up {% if voted==1 %}active{% endif %}"></span>
|
||||||
<span class="comment-mobile-score-{{c.id}} score comment-score-{{c.id}} {% if voted==1 %}score-up{% elif voted==-1%}score-down{% endif %}{% if c.controversial %} controversial{% endif %}"{% if not c.is_banned %} data-bs-toggle="tooltip" data-bs-placement="top" title="+{{ups}} | -{{downs}}"{% endif %}>{{score}}</span>
|
<span class="comment-mobile-score-{{c.id}} score comment-score-{{c.id}} {% if voted==1 %}score-up{% elif voted==-1%}score-down{% endif %}{% if c.controversial %} controversial{% endif %}"{% if c.state_mod == StateMod.Visible %} data-bs-toggle="tooltip" data-bs-placement="top" title="+{{ups}} | -{{downs}}"{% endif %}>{{score}}</span>
|
||||||
<span {% if not ENABLE_DOWNVOTES %}style="display: none!important"{% endif %} tabindex="0" role="button" onclick="vote('comment-mobile', '{{c.id}}', '-1')" class="comment-mobile-{{c.id}}-down mx-0 pl-1 my-0 arrow-down downvote-button comment-{{c.id}}-down {% if voted==-1 %}active{% endif %}"></span>
|
<span {% if not ENABLE_DOWNVOTES %}style="display: none!important"{% endif %} tabindex="0" role="button" onclick="vote('comment-mobile', '{{c.id}}', '-1')" class="comment-mobile-{{c.id}}-down mx-0 pl-1 my-0 arrow-down downvote-button comment-{{c.id}}-down {% if voted==-1 %}active{% endif %}"></span>
|
||||||
</li>
|
</li>
|
||||||
{% else %}
|
{% else %}
|
||||||
|
@ -20,7 +20,7 @@
|
||||||
<span tabindex="0" class="arrow-{{c.id}}-mobile-up mx-0 pr-1 arrow-mobile-up" onclick="location.href='/login';">
|
<span tabindex="0" class="arrow-{{c.id}}-mobile-up mx-0 pr-1 arrow-mobile-up" onclick="location.href='/login';">
|
||||||
<i class="fas fa-arrow-alt-up mx-0" aria-hidden="true"></i>
|
<i class="fas fa-arrow-alt-up mx-0" aria-hidden="true"></i>
|
||||||
</span>
|
</span>
|
||||||
<span class="comment-mobile-score-{{c.id}} score{% if c.controversial %} controversial{% endif %}"{% if not c.is_banned %} data-bs-toggle="tooltip" data-bs-placement="top" title="+{{ups}} | -{{downs}}"{% endif %}>{{score}}</span>
|
<span class="comment-mobile-score-{{c.id}} score{% if c.controversial %} controversial{% endif %}"{% if c.state_mod == StateMod.Visible %} data-bs-toggle="tooltip" data-bs-placement="top" title="+{{ups}} | -{{downs}}"{% endif %}>{{score}}</span>
|
||||||
<span tabindex="0" class="arrow-{{c.id}}-mobile-down arrow-mobile-down mx-0 pl-1 my-0" onclick="location.href='/login';">
|
<span tabindex="0" class="arrow-{{c.id}}-mobile-down arrow-mobile-down mx-0 pl-1 my-0" onclick="location.href='/login';">
|
||||||
<i class="fas fa-arrow-alt-down mx-0" aria-hidden="true"></i>
|
<i class="fas fa-arrow-alt-down mx-0" aria-hidden="true"></i>
|
||||||
</span>
|
</span>
|
||||||
|
|
|
@ -35,7 +35,7 @@
|
||||||
<a id="delete2-{{p.id}}" class="{% if p.state_user_deleted_utc %}d-none{% endif %} list-inline-item" role="button" data-bs-toggle="modal" data-bs-dismiss="modal" data-bs-target="#deletePostModal" onclick="delete_postModal('{{p.id}}')"><i class="fas fa-trash-alt"></i>Delete</a>
|
<a id="delete2-{{p.id}}" class="{% if p.state_user_deleted_utc %}d-none{% endif %} list-inline-item" role="button" data-bs-toggle="modal" data-bs-dismiss="modal" data-bs-target="#deletePostModal" onclick="delete_postModal('{{p.id}}')"><i class="fas fa-trash-alt"></i>Delete</a>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
{% if v and v.admin_level >= 2 and p.filter_state == 'filtered' %}
|
{% if v and v.admin_level >= 2 and p.state_mod == StateMod.Filtered %}
|
||||||
<a id="filter-approve" class="list-inline-item" role="button" onclick="filter_new_status({{p.id}}, 'normal')">Approve</a>
|
<a id="filter-approve" class="list-inline-item" role="button" onclick="filter_new_status({{p.id}}, 'normal')">Approve</a>
|
||||||
<a id="filter-remove" class="list-inline-item" role="button" onclick="filter_new_status({{p.id}}, 'removed')">Remove</a>
|
<a id="filter-remove" class="list-inline-item" role="button" onclick="filter_new_status({{p.id}}, 'removed')">Remove</a>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
@ -63,8 +63,8 @@
|
||||||
{% 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 %}
|
{% 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 %}
|
||||||
<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 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>
|
||||||
{% else %}
|
{% else %}
|
||||||
{% if v.id != p.author.id %}<a id="remove-{{p.id}}" class="dropdown-item {% if p.is_banned %}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 %}
|
{% 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 %}
|
||||||
<a id="approve-{{p.id}}" class="dropdown-item {% if not p.is_banned %}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>
|
<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 %}
|
{% endif %}
|
||||||
|
|
||||||
{% if p.oauth_app %}
|
{% if p.oauth_app %}
|
||||||
|
|
|
@ -27,11 +27,11 @@
|
||||||
<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>
|
<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>
|
||||||
<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>
|
<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>
|
||||||
{% else %}
|
{% else %}
|
||||||
<button id="remove2-{{p.id}}" class="{% if p.is_banned %}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>
|
<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>
|
||||||
<button id="approve2-{{p.id}}" class="{% if not p.is_banned %}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>
|
<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.filter_state == 'filtered' %}
|
{% 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-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>
|
<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 %}
|
{% endif %}
|
||||||
|
|
|
@ -38,7 +38,7 @@
|
||||||
<meta charset="utf-8">
|
<meta charset="utf-8">
|
||||||
<meta property="og:type" content="article">
|
<meta property="og:type" content="article">
|
||||||
|
|
||||||
{% if comment_info and not comment_info.is_banned and not comment_info.state_user_deleted_utc %}
|
{% if comment_info and comment_info.state_mod == StateMod.Visible and not comment_info.state_user_deleted_utc %}
|
||||||
<title>{{'@'+comment_info.author_name}} comments on "{{p.plaintitle(v)}} - {{SITE_TITLE}}"</title>
|
<title>{{'@'+comment_info.author_name}} comments on "{{p.plaintitle(v)}} - {{SITE_TITLE}}"</title>
|
||||||
|
|
||||||
|
|
||||||
|
@ -132,7 +132,7 @@
|
||||||
|
|
||||||
<div class="row mb-3" style="background-color:var(--gray-600)">
|
<div class="row mb-3" style="background-color:var(--gray-600)">
|
||||||
<div id="post-root" class="col-12">
|
<div id="post-root" class="col-12">
|
||||||
<div class="card border-0 mt-3{% if p.is_banned %} banned{% endif %}{% if p.stickied %} stickied{% endif %}{% if voted==1 %} upvoted{% elif voted==-1 %} downvoted{% endif %}">
|
<div class="card border-0 mt-3{% if p.state_mod == StateMod.Removed %} removed{% endif %}{% if p.state_mod == StateMod.Filtered %} filtered{% endif %}{% if p.stickied %} stickied{% endif %}{% if voted==1 %} upvoted{% elif voted==-1 %} downvoted{% endif %}">
|
||||||
<div id="post-{{p.id}}" class="{% if p.state_user_deleted_utc %}deleted {% endif %}d-flex flex-row-reverse flex-nowrap justify-content-end">
|
<div id="post-{{p.id}}" class="{% if p.state_user_deleted_utc %}deleted {% endif %}d-flex flex-row-reverse flex-nowrap justify-content-end">
|
||||||
|
|
||||||
<div id="post-content" class="{% if p.state_user_deleted_utc %}deleted {% endif %}card-block w-100 my-md-auto">
|
<div id="post-content" class="{% if p.state_user_deleted_utc %}deleted {% endif %}card-block w-100 my-md-auto">
|
||||||
|
@ -157,7 +157,7 @@
|
||||||
{% if p.is_bot %} <i class="fas fa-robot text-info" data-bs-toggle="tooltip" data-bs-placement="bottom" title="Bot"></i>{% endif %}
|
{% if p.is_bot %} <i class="fas fa-robot text-info" data-bs-toggle="tooltip" data-bs-placement="bottom" title="Bot"></i>{% endif %}
|
||||||
{% if p.over_18 %}<span class="badge badge-danger text-small-extra mr-1">+18</span>{% endif %}
|
{% if p.over_18 %}<span class="badge badge-danger text-small-extra mr-1">+18</span>{% endif %}
|
||||||
{% if p.private %}<span class="badge border-warning border-1 text-small-extra">Draft</span>{% endif %}
|
{% if p.private %}<span class="badge border-warning border-1 text-small-extra">Draft</span>{% endif %}
|
||||||
{% if v and p.filter_state == 'reported' and v.can_manage_reports() %}
|
{% if v and p.state_report == StateReport.Reported and v.can_manage_reports() %}
|
||||||
<a class="btn btn-primary" id="submission-report-button" role="button" style="padding:1px 5px; font-size:10px"onclick="document.getElementById('flaggers').classList.toggle('d-none')">{{p.active_flags(v)}} Reports</a>
|
<a class="btn btn-primary" id="submission-report-button" role="button" style="padding:1px 5px; font-size:10px"onclick="document.getElementById('flaggers').classList.toggle('d-none')">{{p.active_flags(v)}} Reports</a>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% if p.ghost %}
|
{% if p.ghost %}
|
||||||
|
@ -183,7 +183,7 @@
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{{p.views}} thread views
|
{{p.views}} thread views
|
||||||
</div>
|
</div>
|
||||||
{% if v and p.filter_state == 'reported' and v.can_manage_reports() %}
|
{% if v and p.state_mod_reported and v.can_manage_reports() %}
|
||||||
<div id="flaggers" class="flaggers d-none">
|
<div id="flaggers" class="flaggers d-none">
|
||||||
<strong><i class="far fa-fw fa-flag"></i> Reports:</strong>
|
<strong><i class="far fa-fw fa-flag"></i> Reports:</strong>
|
||||||
<a class="btn btn-primary" style="margin:1px 5px" onclick="filter_new_status({{p.id}}, 'normal')">Approve</a>
|
<a class="btn btn-primary" style="margin:1px 5px" onclick="filter_new_status({{p.id}}, 'normal')">Approve</a>
|
||||||
|
@ -257,8 +257,8 @@
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{{p.realbody(v) | safe}}
|
{{p.realbody(v) | safe}}
|
||||||
|
|
||||||
{% if p.is_banned and p.ban_reason %}
|
{% if p.state_mod == StateMod.Removed and p.state_mod_set_by %}
|
||||||
<div class="text-removed mb-0">removed by @{{p.ban_reason}}</div>
|
<div class="text-removed mb-0">removed by @{{p.state_mod_set_by}}</div>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
@ -341,7 +341,7 @@
|
||||||
<div id="voting" class="voting d-none d-md-block mb-auto">
|
<div id="voting" class="voting d-none d-md-block mb-auto">
|
||||||
<div tabindex="0" role="button" onclick="vote('post', '{{p.id}}', '1')" class="post-{{p.id}}-up arrow-up mx-auto" onclick="location.href='/login?redirect={{request.path | urlencode}}';">
|
<div tabindex="0" role="button" onclick="vote('post', '{{p.id}}', '1')" class="post-{{p.id}}-up arrow-up mx-auto" onclick="location.href='/login?redirect={{request.path | urlencode}}';">
|
||||||
</div>
|
</div>
|
||||||
<span class="post-{{p.id}}-score-none score text-muted{% if p.controversial %} controversial{% endif %}"{% if not p.is_banned %} data-bs-toggle="tooltip" data-bs-placement="right" title="+{{ups}} | -{{downs}}"{% endif %}>{{score}}</span>
|
<span class="post-{{p.id}}-score-none score text-muted{% if p.controversial %} controversial{% endif %}"{% if p.state_mod == StateMod.Visible %} data-bs-toggle="tooltip" data-bs-placement="right" title="+{{ups}} | -{{downs}}"{% endif %}>{{score}}</span>
|
||||||
<div {% if not ENABLE_DOWNVOTES %}style="display:None!important"{% endif %} tabindex="0" role="button" onclick="vote('post', '{{p.id}}', '-1')" class="post-{{p.id}}-down arrow-down mx-auto" onclick="location.href='/login?redirect={{request.path | urlencode}}';"></div>
|
<div {% if not ENABLE_DOWNVOTES %}style="display:None!important"{% endif %} tabindex="0" role="button" onclick="vote('post', '{{p.id}}', '-1')" class="post-{{p.id}}-down arrow-down mx-auto" onclick="location.href='/login?redirect={{request.path | urlencode}}';"></div>
|
||||||
</div>
|
</div>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
|
@ -11,21 +11,16 @@
|
||||||
|
|
||||||
{% block title %}
|
{% block title %}
|
||||||
<title>{{p.plaintitle(v)}}</title>
|
<title>{{p.plaintitle(v)}}</title>
|
||||||
{% if p.is_banned %}
|
|
||||||
|
|
||||||
{% else %}
|
|
||||||
|
|
||||||
{% endif %}
|
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
<div class="mb-2 p-3">
|
<div class="mb-2 p-3">
|
||||||
<div class="col-12">
|
<div class="col-12">
|
||||||
<div id="post-{{p.id}}" class="card d-flex flex-row-reverse flex-nowrap justify-content-end border-0 p-0 {% if voted==1 %} upvoted{% elif voted==-1 %} downvoted{% endif %}">
|
<div id="post-{{p.id}}" class="card d-flex flex-row-reverse flex-nowrap justify-content-end border-0 p-0 {% if voted==1 %} upvoted{% elif voted==-1 %} downvoted{% endif %}">
|
||||||
<div class="card-block my-md-auto{% if p.is_banned %} banned{% endif %}">
|
<div class="card-block my-md-auto{% if p.state_mod == StateMod.Removed %} banned{% endif %}">
|
||||||
<div class="post-meta text-left d-md-none mb-1">{% if p.over_18 %}<span class="badge badge-danger">+18</span> {% endif %}{% if p.is_banned %}removed by @{{p.ban_reason}}{% else %}[Deleted by user]{% endif %}</div>
|
<div class="post-meta text-left d-md-none mb-1">{% if p.over_18 %}<span class="badge badge-danger">+18</span> {% endif %}{% if p.state_mod == StateMod.Removed %}removed by @{{p.state_mod_set_by}}{% else %}[Deleted by user]{% endif %}</div>
|
||||||
<h5 class="card-title post-title text-left mb-0 mb-md-1">{{p.plaintitle(v)}}</h5>
|
<h5 class="card-title post-title text-left mb-0 mb-md-1">{{p.plaintitle(v)}}</h5>
|
||||||
<div class="post-meta text-left d-none d-md-block">{% if p.over_18 %}<span class="badge badge-danger">+18</span> {% endif %}{% if p.is_banned %}removed by @{{p.ban_reason}}{% else %}[Deleted by user]{% endif %}</div>
|
<div class="post-meta text-left d-none d-md-block">{% if p.over_18 %}<span class="badge badge-danger">+18</span> {% endif %}{% if p.state_mod == StateMod.Removed %}removed by @{{p.state_mod_set_by}}{% else %}[Deleted by user]{% endif %}</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
|
@ -63,7 +63,7 @@
|
||||||
{% set voted=-2 %}
|
{% set voted=-2 %}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
{% if v and p.filter_state == 'reported' and v.can_manage_reports() %}
|
{% if v and p.state_mod_reported and v.can_manage_reports() %}
|
||||||
<div id="flaggers-{{p.id}}" class="flaggers d-none">
|
<div id="flaggers-{{p.id}}" class="flaggers d-none">
|
||||||
<strong><i class="far fa-fw fa-flag"></i> Reports:</strong>
|
<strong><i class="far fa-fw fa-flag"></i> Reports:</strong>
|
||||||
<a class="btn btn-primary" style="margin:1px 5px" onclick="filter_new_status({{p.id}}, 'normal')">Approve</a>
|
<a class="btn btn-primary" style="margin:1px 5px" onclick="filter_new_status({{p.id}}, 'normal')">Approve</a>
|
||||||
|
@ -78,7 +78,7 @@
|
||||||
</div>
|
</div>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
<div id="post-{{p.id}}" class="card{% if p.is_banned %} banned{% endif %}{% if p.state_user_deleted_utc %} deleted{% endif %}{% if p.stickied %} stickied{% endif %}{% if voted==1 %} upvoted{% elif voted==-1 %} downvoted{% endif %}{% if p.over_18 %} nsfw{% endif %}">
|
<div id="post-{{p.id}}" class="card{% if p.state_mod == StateMod.Removed %} removed{% endif %}{% if p.state_mod == StateMod.Filtered %} filtered{% endif %}{% if p.state_user_deleted_utc %} deleted{% endif %}{% if p.stickied %} stickied{% endif %}{% if voted==1 %} upvoted{% elif voted==-1 %} downvoted{% endif %}{% if p.over_18 %} nsfw{% endif %}">
|
||||||
|
|
||||||
<div class="d-flex flex-row flex-nowrap justify-content-end align-items-center">
|
<div class="d-flex flex-row flex-nowrap justify-content-end align-items-center">
|
||||||
|
|
||||||
|
@ -90,7 +90,7 @@
|
||||||
<div class="mx-auto arrow-up post-{{p.id}}-up active"></div>
|
<div class="mx-auto arrow-up post-{{p.id}}-up active"></div>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
<span class="post-score-{{p.id}} score post-score-{{p.id}} {% if voted==1 %}score-up{% elif voted==-1%}score-down{% endif %}{% if p.controversial %} controversial{% endif %}"{% if not p.is_banned %} data-bs-toggle="tooltip" data-bs-placement="right" title="+{{ups}} | -{{downs}}"{% endif %}>{{score}}</span>
|
<span class="post-score-{{p.id}} score post-score-{{p.id}} {% if voted==1 %}score-up{% elif voted==-1%}score-down{% endif %}{% if p.controversial %} controversial{% endif %}"{% if p.state_mod == StateMod.Visible %} data-bs-toggle="tooltip" data-bs-placement="right" title="+{{ups}} | -{{downs}}"{% endif %}>{{score}}</span>
|
||||||
|
|
||||||
{% if voted==-1 %}
|
{% if voted==-1 %}
|
||||||
<div class="text-muted mx-auto arrow-down post-{{p.id}}-down active"></div>
|
<div class="text-muted mx-auto arrow-down post-{{p.id}}-down active"></div>
|
||||||
|
@ -100,7 +100,7 @@
|
||||||
|
|
||||||
<div tabindex="0" role="button" onclick="vote('post', '{{p.id}}', '1', '{{v.id}}')" class="post-{{p.id}}-up mx-auto arrow-up upvote-button post-{{p.id}}-up {% if voted==1 %}active{% endif %}"></div>
|
<div tabindex="0" role="button" onclick="vote('post', '{{p.id}}', '1', '{{v.id}}')" class="post-{{p.id}}-up mx-auto arrow-up upvote-button post-{{p.id}}-up {% if voted==1 %}active{% endif %}"></div>
|
||||||
|
|
||||||
<span class="post-score-{{p.id}} score post-score-{{p.id}} {% if voted==1 %}score-up{% elif voted==-1%}score-down{% endif %}{% if p.controversial %} controversial{% endif %}"{% if not p.is_banned %} data-bs-toggle="tooltip" data-bs-placement="right" title="+{{ups}} | -{{downs}}"{% endif %}>{{score}}</span>
|
<span class="post-score-{{p.id}} score post-score-{{p.id}} {% if voted==1 %}score-up{% elif voted==-1%}score-down{% endif %}{% if p.controversial %} controversial{% endif %}"{% if p.state_mod == StateMod.Visible %} data-bs-toggle="tooltip" data-bs-placement="right" title="+{{ups}} | -{{downs}}"{% endif %}>{{score}}</span>
|
||||||
|
|
||||||
<div {% if not ENABLE_DOWNVOTES %}style="display:None!important"{% endif %} tabindex="0" role="button" onclick="vote('post', '{{p.id}}', '-1', '{{v.id}}')" class="post-{{p.id}}-down text-muted mx-auto arrow-down downvote-button post-{{p.id}}-down {% if voted==-1 %}active{% endif %}"></div>
|
<div {% if not ENABLE_DOWNVOTES %}style="display:None!important"{% endif %} tabindex="0" role="button" onclick="vote('post', '{{p.id}}', '-1', '{{v.id}}')" class="post-{{p.id}}-down text-muted mx-auto arrow-down downvote-button post-{{p.id}}-down {% if voted==-1 %}active{% endif %}"></div>
|
||||||
|
|
||||||
|
@ -108,7 +108,7 @@
|
||||||
|
|
||||||
<div tabindex="0" role="button" onclick="vote('post', '{{p.id}}', '1', '{{v.id}}')" class="post-{{p.id}}-up mx-auto arrow-up" onclick="location.href='/login';"></div>
|
<div tabindex="0" role="button" onclick="vote('post', '{{p.id}}', '1', '{{v.id}}')" class="post-{{p.id}}-up mx-auto arrow-up" onclick="location.href='/login';"></div>
|
||||||
|
|
||||||
<span class="post-{{p.id}}-score-none score{% if p.controversial %} controversial{% endif %}"{% if not p.is_banned %} data-bs-toggle="tooltip" data-bs-placement="right" title="+{{ups}} | -{{downs}}"{% endif %}>{{score}}</span>
|
<span class="post-{{p.id}}-score-none score{% if p.controversial %} controversial{% endif %}"{% if p.state_mod == StateMod.Visible %} data-bs-toggle="tooltip" data-bs-placement="right" title="+{{ups}} | -{{downs}}"{% endif %}>{{score}}</span>
|
||||||
|
|
||||||
<div {% if not ENABLE_DOWNVOTES %}style="display:None!important"{% endif %} tabindex="0" role="button" onclick="vote('post', '{{p.id}}', '-1', '{{v.id}}')" class="post-{{p.id}}-down text-muted mx-auto arrow-down" onclick="location.href='/login';"></div>
|
<div {% if not ENABLE_DOWNVOTES %}style="display:None!important"{% endif %} tabindex="0" role="button" onclick="vote('post', '{{p.id}}', '-1', '{{v.id}}')" class="post-{{p.id}}-down text-muted mx-auto arrow-down" onclick="location.href='/login';"></div>
|
||||||
|
|
||||||
|
@ -183,7 +183,7 @@
|
||||||
{% if p.is_blocking %}<i class="fas fa-user-minus text-warning" data-bs-toggle="tooltip" data-bs-placement="bottom" title="You're blocking this user, but you can see this post because you're an admin."></i>{% endif %}
|
{% if p.is_blocking %}<i class="fas fa-user-minus text-warning" data-bs-toggle="tooltip" data-bs-placement="bottom" title="You're blocking this user, but you can see this post because you're an admin."></i>{% endif %}
|
||||||
{% if p.is_blocked %}<i class="fas fa-user-minus text-danger" data-bs-toggle="tooltip" data-bs-placement="bottom" title="This user is blocking you."></i>{% endif %}
|
{% if p.is_blocked %}<i class="fas fa-user-minus text-danger" data-bs-toggle="tooltip" data-bs-placement="bottom" title="This user is blocking you."></i>{% endif %}
|
||||||
{% if p.private %}<span class="badge border-warning border-1 text-small-extra">Draft</span>{% endif %}
|
{% if p.private %}<span class="badge border-warning border-1 text-small-extra">Draft</span>{% endif %}
|
||||||
{% if v and p.filter_state == 'reported' and v.can_manage_reports() %}
|
{% if v and p.state_report == StateReport.Reported and v.can_manage_reports() %}
|
||||||
<a class="btn btn-primary" id="report-btn-{{p.id}}" role="button" style="padding:1px 5px; font-size:10px"onclick="document.getElementById('flaggers-{{p.id}}').classList.toggle('d-none')">{{p.active_flags(v)}} Reports</a>
|
<a class="btn btn-primary" id="report-btn-{{p.id}}" role="button" style="padding:1px 5px; font-size:10px"onclick="document.getElementById('flaggers-{{p.id}}').classList.toggle('d-none')">{{p.active_flags(v)}} Reports</a>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
|
|
|
@ -6,6 +6,7 @@ from . import util
|
||||||
from flask import g
|
from flask import g
|
||||||
from files.__main__ import app, db_session
|
from files.__main__ import app, db_session
|
||||||
from files.classes import Submission, Comment, User
|
from files.classes import Submission, Comment, User
|
||||||
|
from files.classes.visstate import StateMod
|
||||||
from files.helpers.comments import bulk_recompute_descendant_counts
|
from files.helpers.comments import bulk_recompute_descendant_counts
|
||||||
import json
|
import json
|
||||||
import random
|
import random
|
||||||
|
@ -203,7 +204,7 @@ def test_bulk_update_descendant_count_quick(accounts, submissions, comments):
|
||||||
'title': f'Clever unique post title number {i}',
|
'title': f'Clever unique post title number {i}',
|
||||||
'title_html': f'Clever unique post title number {i}',
|
'title_html': f'Clever unique post title number {i}',
|
||||||
'ghost': False,
|
'ghost': False,
|
||||||
'filter_state': 'normal'
|
'state_mod': StateMod.Visible,
|
||||||
})
|
})
|
||||||
db.add(post)
|
db.add(post)
|
||||||
db.commit()
|
db.commit()
|
||||||
|
@ -222,7 +223,8 @@ def test_bulk_update_descendant_count_quick(accounts, submissions, comments):
|
||||||
'app_id': None,
|
'app_id': None,
|
||||||
'body_html': f'reply {i} {j}',
|
'body_html': f'reply {i} {j}',
|
||||||
'body': f'reply {i} {j}',
|
'body': f'reply {i} {j}',
|
||||||
'ghost': False
|
'ghost': False,
|
||||||
|
'state_mod': StateMod.Visible,
|
||||||
})
|
})
|
||||||
if parent_comment is None:
|
if parent_comment is None:
|
||||||
top_comment = comment
|
top_comment = comment
|
||||||
|
|
|
@ -0,0 +1,233 @@
|
||||||
|
"""rejigger of the mod/report comment/post state flags
|
||||||
|
|
||||||
|
Revision ID: ea282d7c711c
|
||||||
|
Revises: 4bb8194c8ac0
|
||||||
|
Create Date: 2023-06-25 07:09:36.333792+00:00
|
||||||
|
|
||||||
|
"""
|
||||||
|
from alembic import op
|
||||||
|
import sqlalchemy as sa
|
||||||
|
|
||||||
|
|
||||||
|
# revision identifiers, used by Alembic.
|
||||||
|
revision = 'ea282d7c711c'
|
||||||
|
down_revision = '4bb8194c8ac0'
|
||||||
|
branch_labels = None
|
||||||
|
depends_on = None
|
||||||
|
|
||||||
|
|
||||||
|
def upgrade():
|
||||||
|
state_mod_enum = sa.Enum('Visible', 'Filtered', 'Removed', name='statemod', create_type=False)
|
||||||
|
state_report_enum = sa.Enum('Unreported', 'Resolved', 'Reported', 'Ignored', name='statereport', create_type=False)
|
||||||
|
|
||||||
|
state_mod_enum.create(op.get_bind(), checkfirst=True)
|
||||||
|
state_report_enum.create(op.get_bind(), checkfirst=True)
|
||||||
|
|
||||||
|
op.add_column('comments', sa.Column('state_mod', state_mod_enum, nullable=True))
|
||||||
|
op.add_column('comments', sa.Column('state_mod_set_by', sa.String(), nullable=True))
|
||||||
|
op.add_column('comments', sa.Column('state_report', state_report_enum, nullable=True))
|
||||||
|
op.drop_index('fki_comment_approver_fkey', table_name='comments')
|
||||||
|
op.drop_constraint('comment_approver_fkey', 'comments', type_='foreignkey')
|
||||||
|
|
||||||
|
# If `is_banned`, set `state_mod` to the `Removed` enum
|
||||||
|
# otherwise, if `filter_state` is `filtered`, set `state_mod` to the `Filtered` enum
|
||||||
|
# otherwise, set `state_mod` to the `Visible` enum
|
||||||
|
op.execute("""
|
||||||
|
UPDATE comments
|
||||||
|
SET state_mod = CASE
|
||||||
|
WHEN is_banned THEN 'Removed'::statemod
|
||||||
|
WHEN filter_state = 'filtered' THEN 'Filtered'::statemod
|
||||||
|
ELSE 'Visible'::statemod
|
||||||
|
END
|
||||||
|
""")
|
||||||
|
|
||||||
|
# if `state_mod` is `Removed`, set `state_mod_set_by` to `ban_reason`
|
||||||
|
# otherwise, if `state_mod` is `Visible`, set `state_mod_set_by` to the `username` of the `users` table, indexed by `is_approved == users.id`
|
||||||
|
op.execute("""
|
||||||
|
UPDATE comments
|
||||||
|
SET state_mod_set_by = CASE
|
||||||
|
WHEN state_mod = 'Removed' THEN ban_reason
|
||||||
|
WHEN state_mod = 'Visible' THEN (SELECT username FROM users WHERE id = is_approved)
|
||||||
|
END
|
||||||
|
""")
|
||||||
|
|
||||||
|
# if `filter_state` is `ignored`, set `state_report` to the `Ignored` enum
|
||||||
|
# otherwise, if `filter_state` is `reported`, set `state_report` to the `Reported` enum
|
||||||
|
# otherwise, if `state_mod_set_by` is non-NULL, set `state_report` to the `Resolved` enum
|
||||||
|
# otherwise, set `state_report` to the `Unreported` enum
|
||||||
|
op.execute("""
|
||||||
|
UPDATE comments
|
||||||
|
SET state_report = CASE
|
||||||
|
WHEN filter_state = 'ignored' THEN 'Ignored'::statereport
|
||||||
|
WHEN filter_state = 'reported' THEN 'Reported'::statereport
|
||||||
|
WHEN state_mod_set_by IS NOT NULL THEN 'Resolved'::statereport
|
||||||
|
ELSE 'Unreported'::statereport
|
||||||
|
END
|
||||||
|
""")
|
||||||
|
|
||||||
|
op.alter_column('comments', 'state_mod', nullable=False)
|
||||||
|
op.alter_column('comments', 'state_report', nullable=False)
|
||||||
|
|
||||||
|
op.drop_column('comments', 'is_banned')
|
||||||
|
op.drop_column('comments', 'ban_reason')
|
||||||
|
op.drop_column('comments', 'is_approved')
|
||||||
|
op.drop_column('comments', 'filter_state')
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
op.add_column('submissions', sa.Column('state_mod', state_mod_enum, nullable=True))
|
||||||
|
op.add_column('submissions', sa.Column('state_mod_set_by', sa.String(), nullable=True))
|
||||||
|
op.add_column('submissions', sa.Column('state_report', state_report_enum, nullable=True))
|
||||||
|
op.drop_index('fki_submissions_approver_fkey', table_name='submissions')
|
||||||
|
op.drop_index('submission_isbanned_idx', table_name='submissions')
|
||||||
|
op.drop_index('subimssion_binary_group_idx', table_name='submissions')
|
||||||
|
op.create_index('subimssion_binary_group_idx', 'submissions', ['state_mod', 'state_user_deleted_utc', 'over_18'], unique=False)
|
||||||
|
op.drop_index('submission_new_sort_idx', table_name='submissions')
|
||||||
|
op.create_index('submission_new_sort_idx', 'submissions', ['state_mod', 'state_user_deleted_utc', sa.text('created_utc DESC'), 'over_18'], unique=False)
|
||||||
|
op.create_index('submission_state_mod_idx', 'submissions', ['state_mod'], unique=False)
|
||||||
|
op.drop_constraint('submissions_approver_fkey', 'submissions', type_='foreignkey')
|
||||||
|
|
||||||
|
# If `is_banned`, set `state_mod` to the `Removed` enum
|
||||||
|
# otherwise, if `filter_state` is `filtered`, set `state_mod` to the `Filtered` enum
|
||||||
|
# otherwise, set `state_mod` to the `Visible` enum
|
||||||
|
op.execute("""
|
||||||
|
UPDATE submissions
|
||||||
|
SET state_mod = CASE
|
||||||
|
WHEN is_banned THEN 'Removed'::statemod
|
||||||
|
WHEN filter_state = 'filtered' THEN 'Filtered'::statemod
|
||||||
|
ELSE 'Visible'::statemod
|
||||||
|
END
|
||||||
|
""")
|
||||||
|
|
||||||
|
# if `state_mod` is `Removed`, set `state_mod_set_by` to `ban_reason`
|
||||||
|
# otherwise, if `state_mod` is `Visible`, set `state_mod_set_by` to the `username` of the `users` table, indexed by `is_approved == users.id`
|
||||||
|
op.execute("""
|
||||||
|
UPDATE submissions
|
||||||
|
SET state_mod_set_by = CASE
|
||||||
|
WHEN state_mod = 'Removed' THEN ban_reason
|
||||||
|
WHEN state_mod = 'Visible' THEN (SELECT username FROM users WHERE id = is_approved)
|
||||||
|
END
|
||||||
|
""")
|
||||||
|
|
||||||
|
# if `filter_state` is `ignored`, set `state_report` to the `Ignored` enum
|
||||||
|
# otherwise, if `filter_state` is `reported`, set `state_report` to the `Reported` enum
|
||||||
|
# otherwise, if `state_mod_set_by` is non-NULL, set `state_report` to the `Resolved` enum
|
||||||
|
# otherwise, set `state_report` to the `Unreported` enum
|
||||||
|
op.execute("""
|
||||||
|
UPDATE submissions
|
||||||
|
SET state_report = CASE
|
||||||
|
WHEN filter_state = 'ignored' THEN 'Ignored'::statereport
|
||||||
|
WHEN filter_state = 'reported' THEN 'Reported'::statereport
|
||||||
|
WHEN state_mod_set_by IS NOT NULL THEN 'Resolved'::statereport
|
||||||
|
ELSE 'Unreported'::statereport
|
||||||
|
END
|
||||||
|
""")
|
||||||
|
|
||||||
|
op.alter_column('submissions', 'state_mod', nullable=False)
|
||||||
|
op.alter_column('submissions', 'state_report', nullable=False)
|
||||||
|
|
||||||
|
op.drop_column('submissions', 'is_banned')
|
||||||
|
op.drop_column('submissions', 'ban_reason')
|
||||||
|
op.drop_column('submissions', 'is_approved')
|
||||||
|
op.drop_column('submissions', 'filter_state')
|
||||||
|
|
||||||
|
|
||||||
|
def downgrade():
|
||||||
|
op.add_column('comments', sa.Column('filter_state', sa.VARCHAR(length=40), autoincrement=False, nullable=True))
|
||||||
|
op.add_column('comments', sa.Column('is_approved', sa.INTEGER(), autoincrement=False, nullable=True))
|
||||||
|
op.add_column('comments', sa.Column('ban_reason', sa.VARCHAR(length=25), autoincrement=False, nullable=True))
|
||||||
|
op.add_column('comments', sa.Column('is_banned', sa.BOOLEAN(), server_default=sa.text('false'), autoincrement=False, nullable=True))
|
||||||
|
op.create_foreign_key('comment_approver_fkey', 'comments', 'users', ['is_approved'], ['id'])
|
||||||
|
op.create_index('fki_comment_approver_fkey', 'comments', ['is_approved'], unique=False)
|
||||||
|
|
||||||
|
op.execute("""
|
||||||
|
UPDATE comments
|
||||||
|
SET is_banned = CASE
|
||||||
|
WHEN state_mod = 'Removed' THEN TRUE
|
||||||
|
ELSE FALSE
|
||||||
|
END
|
||||||
|
""")
|
||||||
|
|
||||||
|
op.execute("""
|
||||||
|
UPDATE comments
|
||||||
|
SET is_approved = (SELECT id FROM users WHERE username = state_mod_set_by)
|
||||||
|
WHERE state_mod = 'Visible' AND (state_report = 'Resolved' OR state_report = 'Ignored')
|
||||||
|
""")
|
||||||
|
|
||||||
|
op.execute("""
|
||||||
|
UPDATE comments
|
||||||
|
SET ban_reason = CASE
|
||||||
|
WHEN state_mod = 'Removed' THEN state_mod_set_by
|
||||||
|
ELSE NULL
|
||||||
|
END
|
||||||
|
""")
|
||||||
|
|
||||||
|
op.execute("""
|
||||||
|
UPDATE comments
|
||||||
|
SET filter_state = CASE
|
||||||
|
WHEN state_report = 'Ignored' THEN 'ignored'
|
||||||
|
WHEN state_report = 'Reported' THEN 'reported'
|
||||||
|
WHEN state_mod = 'Filtered' THEN 'filtered'
|
||||||
|
ELSE NULL
|
||||||
|
END
|
||||||
|
""")
|
||||||
|
|
||||||
|
op.alter_column('comments', sa.Column('filter_state', sa.VARCHAR(length=40), autoincrement=False, nullable=True))
|
||||||
|
op.alter_column('comments', sa.Column('is_banned', sa.BOOLEAN(), server_default=sa.text('false'), autoincrement=False, nullable=True))
|
||||||
|
|
||||||
|
op.drop_column('comments', 'state_report')
|
||||||
|
op.drop_column('comments', 'state_mod_set_by')
|
||||||
|
op.drop_column('comments', 'state_mod')
|
||||||
|
|
||||||
|
op.add_column('submissions', sa.Column('filter_state', sa.VARCHAR(length=40), autoincrement=False, nullable=True))
|
||||||
|
op.add_column('submissions', sa.Column('is_approved', sa.INTEGER(), autoincrement=False, nullable=True))
|
||||||
|
op.add_column('submissions', sa.Column('ban_reason', sa.VARCHAR(length=25), autoincrement=False, nullable=True))
|
||||||
|
op.add_column('submissions', sa.Column('is_banned', sa.BOOLEAN(), server_default=sa.text('false'), autoincrement=False, nullable=True))
|
||||||
|
op.create_foreign_key('submissions_approver_fkey', 'submissions', 'users', ['is_approved'], ['id'])
|
||||||
|
op.drop_index('submission_state_mod_idx', table_name='submissions')
|
||||||
|
op.drop_index('submission_new_sort_idx', table_name='submissions')
|
||||||
|
op.create_index('submission_new_sort_idx', 'submissions', ['is_banned', 'state_user_deleted_utc', 'created_utc', 'over_18'], unique=False)
|
||||||
|
op.drop_index('subimssion_binary_group_idx', table_name='submissions')
|
||||||
|
op.create_index('subimssion_binary_group_idx', 'submissions', ['is_banned', 'state_user_deleted_utc', 'over_18'], unique=False)
|
||||||
|
op.create_index('submission_isbanned_idx', 'submissions', ['is_banned'], unique=False)
|
||||||
|
op.create_index('fki_submissions_approver_fkey', 'submissions', ['is_approved'], unique=False)
|
||||||
|
|
||||||
|
op.execute("""
|
||||||
|
UPDATE submissions
|
||||||
|
SET is_banned = CASE
|
||||||
|
WHEN state_mod = 'Removed' THEN TRUE
|
||||||
|
ELSE FALSE
|
||||||
|
END
|
||||||
|
""")
|
||||||
|
|
||||||
|
op.execute("""
|
||||||
|
UPDATE submissions
|
||||||
|
SET is_approved = (SELECT id FROM users WHERE username = state_mod_set_by)
|
||||||
|
WHERE state_mod = 'Visible' AND (state_report = 'Resolved' OR state_report = 'Ignored')
|
||||||
|
""")
|
||||||
|
|
||||||
|
op.execute("""
|
||||||
|
UPDATE submissions
|
||||||
|
SET ban_reason = CASE
|
||||||
|
WHEN state_mod = 'Removed' THEN state_mod_set_by
|
||||||
|
ELSE NULL
|
||||||
|
END
|
||||||
|
""")
|
||||||
|
|
||||||
|
op.execute("""
|
||||||
|
UPDATE submissions
|
||||||
|
SET filter_state = CASE
|
||||||
|
WHEN state_report = 'Ignored' THEN 'ignored'
|
||||||
|
WHEN state_report = 'Reported' THEN 'reported'
|
||||||
|
WHEN state_mod = 'Filtered' THEN 'filtered'
|
||||||
|
ELSE NULL
|
||||||
|
END
|
||||||
|
""")
|
||||||
|
|
||||||
|
op.alter_column('submissions', sa.Column('filter_state', sa.VARCHAR(length=40), autoincrement=False, nullable=True))
|
||||||
|
op.alter_column('submissions', sa.Column('is_banned', sa.BOOLEAN(), server_default=sa.text('false'), autoincrement=False, nullable=True))
|
||||||
|
|
||||||
|
op.drop_column('submissions', 'state_report')
|
||||||
|
op.drop_column('submissions', 'state_mod_set_by')
|
||||||
|
op.drop_column('submissions', 'state_mod')
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue