df
This commit is contained in:
parent
4b89a5b6db
commit
a4eeee5a11
68 changed files with 3376 additions and 2605 deletions
|
@ -24,9 +24,6 @@ from redis import ConnectionPool
|
|||
|
||||
from werkzeug.middleware.proxy_fix import ProxyFix
|
||||
|
||||
|
||||
_version = "2.37.4"
|
||||
|
||||
app = Flask(__name__,
|
||||
template_folder='./templates',
|
||||
static_folder='./static'
|
||||
|
@ -56,7 +53,7 @@ app.config["SERVER_NAME"] = environ.get("domain", environ.get("SERVER_NAME", "")
|
|||
|
||||
app.config["SHORT_DOMAIN"]=environ.get("SHORT_DOMAIN","").strip()
|
||||
app.config["SESSION_COOKIE_NAME"] = "session_drama"
|
||||
app.config["VERSION"] = _version
|
||||
app.config["VERSION"] = "1.0.0"
|
||||
app.config['MAX_CONTENT_LENGTH'] = 64 * 1024 * 1024
|
||||
app.config["SESSION_COOKIE_SECURE"] = bool(int(environ.get("FORCE_HTTPS", 1)))
|
||||
app.config["SESSION_COOKIE_SAMESITE"] = "Lax"
|
||||
|
@ -69,7 +66,7 @@ app.config["DISABLE_SIGNUPS"]=int(environ.get("DISABLE_SIGNUPS",0))
|
|||
|
||||
app.jinja_env.cache = {}
|
||||
|
||||
app.config["UserAgent"] = f"Content Aquisition for Pink message board v{_version}."
|
||||
app.config["UserAgent"] = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/92.0.4515.107 Safari/537.36"
|
||||
|
||||
if "localhost" in app.config["SERVER_NAME"]:
|
||||
app.config["CACHE_TYPE"] = "null"
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
User-Agent: *
|
||||
Disallow: /api/*
|
||||
Disallow: /mod/*
|
||||
Disallow: /admin/*
|
||||
Disallow: /submit
|
||||
Disallow: /settings
|
||||
Disallow: /me
|
||||
|
|
|
@ -1,7 +1,5 @@
|
|||
from .alts import *
|
||||
from .badges import *
|
||||
from .boards import *
|
||||
from .board_relationships import *
|
||||
from .clients import *
|
||||
from .comment import *
|
||||
from .domains import Domain
|
||||
|
|
|
@ -1,198 +0,0 @@
|
|||
from sqlalchemy import *
|
||||
from sqlalchemy.orm import relationship
|
||||
from drama.__main__ import Base, cache
|
||||
from .mix_ins import *
|
||||
import time
|
||||
|
||||
|
||||
class ModRelationship(Base, Age_times):
|
||||
__tablename__ = "mods"
|
||||
id = Column(BigInteger, primary_key=True)
|
||||
user_id = Column(Integer, ForeignKey("users.id"))
|
||||
board_id = Column(Integer, ForeignKey("boards.id"))
|
||||
created_utc = Column(Integer, default=0)
|
||||
accepted = Column(Boolean, default=False)
|
||||
invite_rescinded = Column(Boolean, default=False)
|
||||
|
||||
perm_content = Column(Boolean, default=False)
|
||||
perm_appearance = Column(Boolean, default=False)
|
||||
perm_config = Column(Boolean, default=False)
|
||||
perm_access = Column(Boolean, default=False)
|
||||
perm_full = Column(Boolean, default=False)
|
||||
#permRules = Column(Boolean, default=False)
|
||||
#permTitles = Column(Boolean, default=False)
|
||||
#permLodges = Column(Boolean, default=False)
|
||||
|
||||
user = relationship("User", lazy="joined")
|
||||
board = relationship("Board", lazy="joined")
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
if "created_utc" not in kwargs:
|
||||
kwargs["created_utc"] = int(time.time())
|
||||
|
||||
super().__init__(*args, **kwargs)
|
||||
|
||||
def __repr__(self):
|
||||
return f"<Mod(id={self.id}, uid={self.user_id}, board_id={self.board_id})>"
|
||||
|
||||
@property
|
||||
def permlist(self):
|
||||
if self.perm_full:
|
||||
return "full"
|
||||
|
||||
output=[]
|
||||
for p in ["access","appearance", "config","content"]:
|
||||
if self.__dict__[f"perm_{p}"]:
|
||||
output.append(p)
|
||||
|
||||
|
||||
return ", ".join(output) if output else "none"
|
||||
|
||||
@property
|
||||
def permchangelist(self):
|
||||
output=[]
|
||||
for p in ["full", "access","appearance", "config","content"]:
|
||||
if self.__dict__.get(f"perm_{p}"):
|
||||
output.append(f"+{p}")
|
||||
else:
|
||||
output.append(f"-{p}")
|
||||
|
||||
return ", ".join(output)
|
||||
|
||||
|
||||
@property
|
||||
def json_core(self):
|
||||
return {
|
||||
'user_id':self.user_id,
|
||||
'board_id':self.board_id,
|
||||
'created_utc':self.created_utc,
|
||||
'accepted':self.accepted,
|
||||
'invite_rescinded':self.invite_rescinded,
|
||||
'perm_content':self.perm_full or self.perm_content,
|
||||
'perm_config':self.perm_full or self.perm_config,
|
||||
'perm_access':self.perm_full or self.perm_access,
|
||||
'perm_appearance':self.perm_full or self.perm_appearance,
|
||||
'perm_full':self.perm_full,
|
||||
}
|
||||
|
||||
|
||||
@property
|
||||
def json(self):
|
||||
data=self.json_core
|
||||
|
||||
data["user"]=self.user.json_core
|
||||
#data["guild"]=self.board.json_core
|
||||
|
||||
return data
|
||||
|
||||
|
||||
|
||||
|
||||
class BanRelationship(Base, Stndrd, Age_times):
|
||||
|
||||
__tablename__ = "bans"
|
||||
id = Column(BigInteger, primary_key=True)
|
||||
user_id = Column(Integer, ForeignKey("users.id"))
|
||||
board_id = Column(Integer, ForeignKey("boards.id"))
|
||||
created_utc = Column(BigInteger, default=0)
|
||||
banning_mod_id = Column(Integer, ForeignKey("users.id"))
|
||||
is_active = Column(Boolean, default=False)
|
||||
mod_note = Column(String(128), default="")
|
||||
|
||||
user = relationship(
|
||||
"User",
|
||||
lazy="joined",
|
||||
primaryjoin="User.id==BanRelationship.user_id")
|
||||
banning_mod = relationship(
|
||||
"User",
|
||||
lazy="joined",
|
||||
primaryjoin="User.id==BanRelationship.banning_mod_id")
|
||||
board = relationship("Board")
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
if "created_utc" not in kwargs:
|
||||
kwargs["created_utc"] = int(time.time())
|
||||
|
||||
super().__init__(*args, **kwargs)
|
||||
|
||||
def __repr__(self):
|
||||
return f"<Ban(id={self.id}, uid={self.uid}, board_id={self.board_id})>"
|
||||
|
||||
@property
|
||||
def json_core(self):
|
||||
return {
|
||||
'user_id':self.user_id,
|
||||
'board_id':self.board_id,
|
||||
'created_utc':self.created_utc,
|
||||
'mod_id':self.banning_mod_id
|
||||
}
|
||||
|
||||
|
||||
@property
|
||||
def json(self):
|
||||
data=self.json_core
|
||||
|
||||
data["user"]=self.user.json_core
|
||||
data["mod"]=self.banning_mod.json_core
|
||||
data["guild"]=self.board.json_core
|
||||
|
||||
return data
|
||||
|
||||
class ContributorRelationship(Base, Stndrd, Age_times):
|
||||
|
||||
__tablename__ = "contributors"
|
||||
id = Column(BigInteger, primary_key=True)
|
||||
user_id = Column(Integer, ForeignKey("users.id"))
|
||||
board_id = Column(Integer, ForeignKey("boards.id"))
|
||||
created_utc = Column(BigInteger, default=0)
|
||||
is_active = Column(Boolean, default=True)
|
||||
approving_mod_id = Column(Integer, ForeignKey("users.id"))
|
||||
|
||||
user = relationship(
|
||||
"User",
|
||||
lazy="joined",
|
||||
primaryjoin="User.id==ContributorRelationship.user_id")
|
||||
approving_mod = relationship(
|
||||
"User",
|
||||
lazy='joined',
|
||||
primaryjoin="User.id==ContributorRelationship.approving_mod_id")
|
||||
board = relationship("Board", lazy="subquery")
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
if "created_utc" not in kwargs:
|
||||
kwargs["created_utc"] = int(time.time())
|
||||
|
||||
super().__init__(*args, **kwargs)
|
||||
|
||||
def __repr__(self):
|
||||
return f"<Contributor(id={self.id}, uid={self.uid}, board_id={self.board_id})>"
|
||||
|
||||
|
||||
class PostRelationship(Base):
|
||||
|
||||
__tablename__ = "postrels"
|
||||
id = Column(BigInteger, primary_key=True)
|
||||
post_id = Column(Integer, ForeignKey("submissions.id"))
|
||||
board_id = Column(Integer, ForeignKey("boards.id"))
|
||||
|
||||
post = relationship("Submission", lazy="subquery")
|
||||
board = relationship("Board", lazy="subquery")
|
||||
|
||||
def __repr__(self):
|
||||
return f"<PostRel(id={self.id}, pid={self.post_id}, board_id={self.board_id})>"
|
||||
|
||||
|
||||
class BoardBlock(Base, Stndrd, Age_times):
|
||||
|
||||
__tablename__ = "boardblocks"
|
||||
|
||||
id = Column(BigInteger, primary_key=True)
|
||||
user_id = Column(Integer, ForeignKey("users.id"))
|
||||
board_id = Column(Integer, ForeignKey("boards.id"))
|
||||
created_utc = Column(Integer)
|
||||
|
||||
user = relationship("User")
|
||||
board = relationship("Board")
|
||||
|
||||
def __repr__(self):
|
||||
return f"<BoardBlock(id={self.id}, uid={self.user_id}, board_id={self.board_id})>"
|
|
@ -1,391 +0,0 @@
|
|||
from sqlalchemy.orm import lazyload
|
||||
from .userblock import *
|
||||
from .submission import *
|
||||
from .board_relationships import *
|
||||
from .comment import Comment
|
||||
from .mix_ins import *
|
||||
from drama.__main__ import Base, cache
|
||||
|
||||
|
||||
class Board(Base, Stndrd, Age_times):
|
||||
|
||||
__tablename__ = "boards"
|
||||
|
||||
id = Column(Integer, primary_key=True)
|
||||
name = Column(String)
|
||||
created_utc = Column(Integer)
|
||||
description = Column(String)
|
||||
|
||||
description_html=Column(String)
|
||||
over_18=Column(Boolean, default=False)
|
||||
is_nsfl=Column(Boolean, default=False)
|
||||
is_banned=Column(Boolean, default=False)
|
||||
disablesignups=Column(Boolean, default=False)
|
||||
has_banner=Column(Boolean, default=False)
|
||||
creator_id=Column(Integer, ForeignKey("users.id"))
|
||||
ban_reason=Column(String(256), default=None)
|
||||
color=Column(String(8), default="FF66AC")
|
||||
restricted_posting=Column(Boolean, default=False)
|
||||
hide_banner_data=Column(Boolean, default=False)
|
||||
profile_nonce=Column(Integer, default=0)
|
||||
banner_nonce=Column(Integer, default=0)
|
||||
is_private=Column(Boolean, default=False)
|
||||
color_nonce=Column(Integer, default=0)
|
||||
rank_trending=Column(Float, default=0)
|
||||
stored_subscriber_count=Column(Integer, default=1)
|
||||
all_opt_out=Column(Boolean, default=False)
|
||||
is_siegable=Column(Boolean, default=True)
|
||||
secondary_color=Column(String(6), default="cfcfcf")
|
||||
motd = Column(String(1000), default='')
|
||||
|
||||
moderators=relationship("ModRelationship")
|
||||
submissions=relationship("Submission", primaryjoin="Board.id==Submission.board_id")
|
||||
contributors=relationship("ContributorRelationship", lazy="dynamic")
|
||||
bans=relationship("BanRelationship", lazy="dynamic")
|
||||
postrels=relationship("PostRelationship", lazy="dynamic")
|
||||
trending_rank=deferred(Column(Float, server_default=FetchedValue()))
|
||||
|
||||
# db side functions
|
||||
subscriber_count = deferred(Column(Integer, server_default=FetchedValue()))
|
||||
|
||||
def __init__(self, **kwargs):
|
||||
|
||||
kwargs["created_utc"] = int(time.time())
|
||||
|
||||
super().__init__(**kwargs)
|
||||
|
||||
def __repr__(self):
|
||||
return f"<Board(name={self.name})>"
|
||||
|
||||
@property
|
||||
def fullname(self):
|
||||
return f"t4_{self.base36id}"
|
||||
|
||||
@property
|
||||
def mods_list(self):
|
||||
|
||||
z = [x for x in self.moderators if x.accepted and not (
|
||||
x.user.is_deleted or (x.user.is_banned and not x.user.unban_utc))]
|
||||
|
||||
z = sorted(z, key=lambda x: x.created_utc)
|
||||
return z
|
||||
|
||||
@property
|
||||
def mods(self):
|
||||
|
||||
z = [x for x in self.moderators if x.accepted]
|
||||
|
||||
z = sorted(z, key=lambda x: x.created_utc)
|
||||
|
||||
z = [x.user for x in z]
|
||||
|
||||
return z
|
||||
|
||||
@property
|
||||
def invited_mods(self):
|
||||
|
||||
z = [x.user for x in self.moderators if x.accepted ==
|
||||
False and x.invite_rescinded == False]
|
||||
z = sorted(z, key=lambda x: x.created_utc)
|
||||
return z
|
||||
|
||||
@property
|
||||
def mod_invites(self):
|
||||
z = [x for x in self.moderators if x.accepted ==
|
||||
False and x.invite_rescinded == False]
|
||||
z = sorted(z, key=lambda x: x.created_utc)
|
||||
return z
|
||||
|
||||
@property
|
||||
def mods_count(self):
|
||||
|
||||
return len(self.mods_list)
|
||||
|
||||
@property
|
||||
def permalink(self):
|
||||
|
||||
return f"/+{self.name}"
|
||||
|
||||
def can_take(self, post):
|
||||
if self.is_banned:
|
||||
return False
|
||||
return not self.postrels.filter_by(post_id=post.id).first()
|
||||
|
||||
def has_mod(self, user, perm=None):
|
||||
|
||||
if user is None:
|
||||
return None
|
||||
|
||||
if self.is_banned:
|
||||
return False
|
||||
|
||||
m=self.__dict__.get("_mod")
|
||||
if not m:
|
||||
for x in user.moderates:
|
||||
if x.board_id == self.id and x.accepted and not x.invite_rescinded:
|
||||
self.__dict__["mod"]=x
|
||||
m=x
|
||||
|
||||
if not m:
|
||||
return False
|
||||
|
||||
if perm:
|
||||
|
||||
return m if (m.perm_full or m.__dict__[f"perm_{perm}"]) else False
|
||||
|
||||
else:
|
||||
return m
|
||||
|
||||
|
||||
return False
|
||||
|
||||
def has_mod_record(self, user, perm=None):
|
||||
|
||||
if user is None:
|
||||
return None
|
||||
|
||||
if self.is_banned:
|
||||
return False
|
||||
|
||||
for x in user.moderates:
|
||||
if x.board_id == self.id and not x.invite_rescinded:
|
||||
|
||||
if perm:
|
||||
return x if x.__dict__[f"perm_{perm}"] else False
|
||||
else:
|
||||
return x
|
||||
|
||||
|
||||
return False
|
||||
def can_invite_mod(self, user):
|
||||
|
||||
return user.id not in [
|
||||
x.user_id for x in self.moderators if not x.invite_rescinded]
|
||||
|
||||
def has_rescinded_invite(self, user):
|
||||
|
||||
return user.id in [
|
||||
x.user_id for x in self.moderators if x.invite_rescinded == True]
|
||||
|
||||
def has_invite(self, user):
|
||||
|
||||
if user is None:
|
||||
return None
|
||||
|
||||
for x in [
|
||||
i for i in self.moderators if not i.invite_rescinded and not i.accepted]:
|
||||
|
||||
if x.user_id == user.id:
|
||||
return x
|
||||
|
||||
return None
|
||||
|
||||
def has_ban(self, user):
|
||||
|
||||
if user is None:
|
||||
return None
|
||||
|
||||
if user.admin_level >=2:
|
||||
return None
|
||||
|
||||
return g.db.query(BanRelationship).filter_by(
|
||||
board_id=self.id, user_id=user.id, is_active=True).first()
|
||||
|
||||
def has_contributor(self, user):
|
||||
|
||||
if user is None:
|
||||
return False
|
||||
|
||||
return g.db.query(ContributorRelationship).filter_by(
|
||||
user_id=user.id, board_id=self.id, is_active=True).first()
|
||||
|
||||
def can_submit(self, user):
|
||||
|
||||
if user is None:
|
||||
return False
|
||||
|
||||
if user.admin_level >= 4:
|
||||
return True
|
||||
|
||||
if self.has_ban(user):
|
||||
return False
|
||||
|
||||
if self.has_contributor(user) or self.has_mod(user):
|
||||
return True
|
||||
|
||||
if self.is_private or self.restricted_posting:
|
||||
return False
|
||||
|
||||
return True
|
||||
|
||||
def can_comment(self, user):
|
||||
|
||||
if user is None:
|
||||
return False
|
||||
|
||||
if user.admin_level >= 4:
|
||||
return True
|
||||
|
||||
if self.has_ban(user):
|
||||
return False
|
||||
|
||||
if self.has_contributor(user) or self.has_mod(user):
|
||||
return True
|
||||
|
||||
if self.is_private:
|
||||
return False
|
||||
|
||||
return True
|
||||
|
||||
def can_view(self, user):
|
||||
|
||||
if user is None:
|
||||
return False
|
||||
|
||||
if user.admin_level >= 4:
|
||||
return True
|
||||
|
||||
if self.has_contributor(user) or self.has_mod(
|
||||
user) or self.has_invite(user):
|
||||
return True
|
||||
|
||||
if self.is_private:
|
||||
return False
|
||||
|
||||
@property
|
||||
def banner_url(self):
|
||||
return "/assets/images/preview.png"
|
||||
|
||||
@property
|
||||
def profile_url(self):
|
||||
return "/assets/images/favicon.png"
|
||||
|
||||
@property
|
||||
def css_url(self):
|
||||
return f"/assets/{self.fullname}/main/{self.color_nonce}.css"
|
||||
|
||||
@property
|
||||
def css_dark_url(self):
|
||||
return f"/assets/{self.fullname}/dark/{self.color_nonce}.css"
|
||||
|
||||
def has_participant(self, user):
|
||||
return (g.db.query(Submission).filter_by(original_board_id=self.id, author_id=user.id).first() or
|
||||
g.db.query(Comment).filter_by(
|
||||
author_id=user.id, original_board_id=self.id).first()
|
||||
)
|
||||
|
||||
@property
|
||||
@lazy
|
||||
def n_pins(self):
|
||||
return g.db.query(Submission).filter_by(
|
||||
board_id=self.id, is_pinned=True).count()
|
||||
|
||||
@property
|
||||
def can_pin_another(self):
|
||||
|
||||
return self.n_pins < 4
|
||||
|
||||
@property
|
||||
def json_core(self):
|
||||
|
||||
if self.is_banned:
|
||||
return {'name': self.name,
|
||||
'permalink': self.permalink,
|
||||
'is_banned': True,
|
||||
'ban_reason': self.ban_reason,
|
||||
'id': self.base36id
|
||||
}
|
||||
return {'name': self.name,
|
||||
'profile_url': self.profile_url,
|
||||
'banner_url': self.banner_url,
|
||||
'created_utc': self.created_utc,
|
||||
'permalink': self.permalink,
|
||||
'description': self.description,
|
||||
'description_html': self.description_html,
|
||||
'over_18': self.over_18,
|
||||
'is_banned': False,
|
||||
'is_private': self.is_private,
|
||||
'is_restricted': self.restricted_posting,
|
||||
'id': self.base36id,
|
||||
'fullname': self.fullname,
|
||||
'banner_url': self.banner_url,
|
||||
'profile_url': self.profile_url,
|
||||
'color': "#" + self.color,
|
||||
'is_siege_protected': not self.is_siegable
|
||||
}
|
||||
|
||||
@property
|
||||
def json(self):
|
||||
data=self.json_core
|
||||
|
||||
if self.is_banned:
|
||||
return data
|
||||
|
||||
|
||||
data['guildmasters']=[x.json_core for x in self.mods]
|
||||
data['subscriber_count']= self.subscriber_count
|
||||
|
||||
return data
|
||||
|
||||
|
||||
@property
|
||||
def show_settings_icons(self):
|
||||
return self.is_private or self.restricted_posting or self.over_18 or self.all_opt_out
|
||||
|
||||
@cache.memoize(600)
|
||||
def comment_idlist(self, page=1, v=None, nsfw=False, **kwargs):
|
||||
|
||||
posts = g.db.query(Submission).options(
|
||||
lazyload('*')).filter_by(board_id=self.id)
|
||||
|
||||
if not nsfw:
|
||||
posts = posts.filter_by(over_18=False)
|
||||
|
||||
if v and not v.show_nsfl:
|
||||
posts = posts.filter_by(is_nsfl=False)
|
||||
|
||||
if self.is_private:
|
||||
if v and (self.can_view(v) or v.admin_level >= 4):
|
||||
pass
|
||||
elif v:
|
||||
posts = posts.filter(or_(Submission.post_public == True,
|
||||
Submission.author_id == v.id
|
||||
)
|
||||
)
|
||||
else:
|
||||
posts = posts.filter_by(post_public=True)
|
||||
|
||||
posts = posts.subquery()
|
||||
|
||||
comments = g.db.query(Comment).options(lazyload('*'))
|
||||
|
||||
if v and v.hide_offensive:
|
||||
comments = comments.filter_by(is_offensive=False)
|
||||
|
||||
if v and v.hide_bot:
|
||||
comments = comments.filter_by(is_bot=False)
|
||||
|
||||
if v and not self.has_mod(v) and v.admin_level <= 3:
|
||||
# blocks
|
||||
blocking = g.db.query(
|
||||
UserBlock.target_id).filter_by(
|
||||
user_id=v.id).subquery()
|
||||
blocked = g.db.query(
|
||||
UserBlock.user_id).filter_by(
|
||||
target_id=v.id).subquery()
|
||||
|
||||
comments = comments.filter(
|
||||
Comment.author_id.notin_(blocking),
|
||||
Comment.author_id.notin_(blocked)
|
||||
)
|
||||
|
||||
if not v or not v.admin_level >= 3:
|
||||
comments = comments.filter_by(is_banned=False).filter(Comment.deleted_utc == 0)
|
||||
|
||||
comments = comments.join(
|
||||
posts, Comment.parent_submission == posts.c.id)
|
||||
|
||||
comments = comments.order_by(Comment.created_utc.desc()).offset(
|
||||
25 * (page - 1)).limit(26).all()
|
||||
|
||||
return [x.id for x in comments]
|
|
@ -68,7 +68,6 @@ class ClientAuth(Base, Stndrd):
|
|||
scope_update = Column(Boolean, default=False)
|
||||
scope_delete = Column(Boolean, default=False)
|
||||
scope_vote = Column(Boolean, default=False)
|
||||
scope_guildmaster = Column(Boolean, default=False)
|
||||
access_token = Column(String(128))
|
||||
refresh_token = Column(String(128))
|
||||
access_token_expire_utc = Column(Integer)
|
||||
|
@ -86,7 +85,6 @@ class ClientAuth(Base, Stndrd):
|
|||
output += "update," if self.scope_update else ""
|
||||
output += "delete," if self.scope_delete else ""
|
||||
output += "vote," if self.scope_vote else ""
|
||||
output += "guildmaster," if self.scope_guildmaster else ""
|
||||
|
||||
output = output.rstrip(',')
|
||||
|
||||
|
|
|
@ -34,14 +34,11 @@ class Comment(Base, Age_times, Scores, Stndrd, Fuzzing):
|
|||
parent_submission = Column(Integer, ForeignKey("submissions.id"))
|
||||
# this column is foreignkeyed to comment(id) but we can't do that yet as
|
||||
# "comment" class isn't yet defined
|
||||
parent_fullname = Column(Integer)
|
||||
created_utc = Column(Integer, default=0)
|
||||
edited_utc = Column(Integer, default=0)
|
||||
is_banned = Column(Boolean, default=False)
|
||||
shadowbanned = Column(Boolean, default=False)
|
||||
distinguish_level = Column(Integer, default=0)
|
||||
gm_distinguish = Column(Integer, ForeignKey("boards.id"), default=0)
|
||||
distinguished_board = relationship("Board", lazy="joined", primaryjoin="Comment.gm_distinguish==Board.id")
|
||||
deleted_utc = Column(Integer, default=0)
|
||||
purged_utc = Column(Integer, default=0)
|
||||
is_approved = Column(Integer, default=0)
|
||||
|
@ -51,11 +48,8 @@ class Comment(Base, Age_times, Scores, Stndrd, Fuzzing):
|
|||
score_top = Column(Integer, default=1)
|
||||
level = Column(Integer, default=0)
|
||||
parent_comment_id = Column(Integer, ForeignKey("comments.id"))
|
||||
original_board_id = Column(Integer, ForeignKey("boards.id"))
|
||||
|
||||
over_18 = Column(Boolean, default=False)
|
||||
is_offensive = Column(Boolean, default=False)
|
||||
is_nsfl = Column(Boolean, default=False)
|
||||
is_bot = Column(Boolean, default=False)
|
||||
banaward = Column(String, default=None)
|
||||
is_pinned = Column(Boolean, default=False)
|
||||
|
@ -72,9 +66,6 @@ class Comment(Base, Age_times, Scores, Stndrd, Fuzzing):
|
|||
lazy="joined",
|
||||
innerjoin=True,
|
||||
primaryjoin="User.id==Comment.author_id")
|
||||
board = association_proxy("post", "board")
|
||||
original_board = relationship(
|
||||
"Board", primaryjoin="Board.id==Comment.original_board_id")
|
||||
|
||||
upvotes = Column(Integer, default=1)
|
||||
downvotes = Column(Integer, default=0)
|
||||
|
@ -95,8 +86,6 @@ class Comment(Base, Age_times, Scores, Stndrd, Fuzzing):
|
|||
rank_fiery = deferred(Column(Float, server_default=FetchedValue()))
|
||||
rank_hot = deferred(Column(Float, server_default=FetchedValue()))
|
||||
|
||||
board_id = deferred(Column(Integer, server_default=FetchedValue()))
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
|
||||
if "created_utc" not in kwargs:
|
||||
|
@ -115,28 +104,9 @@ class Comment(Base, Age_times, Scores, Stndrd, Fuzzing):
|
|||
def score_disputed(self):
|
||||
return (self.upvotes+1) * (self.downvotes+1)
|
||||
|
||||
@property
|
||||
@lazy
|
||||
def fullname(self):
|
||||
return f"t3_{self.base36id}"
|
||||
|
||||
def children(self, v):
|
||||
return sorted([x for x in self.child_comments if not x.author.shadowbanned or (v and v.id == x.author_id)], key=lambda x: x.score, reverse=True)
|
||||
|
||||
@property
|
||||
@lazy
|
||||
def is_deleted(self):
|
||||
return bool(self.deleted_utc)
|
||||
|
||||
@property
|
||||
@lazy
|
||||
def is_top_level(self):
|
||||
return self.parent_fullname and self.parent_fullname.startswith("t2_")
|
||||
|
||||
@property
|
||||
def is_archived(self):
|
||||
return self.post.is_archived
|
||||
|
||||
@property
|
||||
@lazy
|
||||
def parent(self):
|
||||
|
@ -144,7 +114,7 @@ class Comment(Base, Age_times, Scores, Stndrd, Fuzzing):
|
|||
if not self.parent_submission:
|
||||
return None
|
||||
|
||||
if self.is_top_level:
|
||||
if self.level == 1:
|
||||
return self.post
|
||||
|
||||
else:
|
||||
|
@ -229,27 +199,13 @@ class Comment(Base, Age_times, Scores, Stndrd, Fuzzing):
|
|||
else:
|
||||
return self.flag_count
|
||||
|
||||
def visibility_reason(self, v):
|
||||
if not v or self.author_id == v.id:
|
||||
return "this is your content."
|
||||
elif not self.board:
|
||||
return None
|
||||
elif self.board.has_mod(v):
|
||||
return f"you are a guildmaster of +{self.board.name}."
|
||||
elif self.board.has_contributor(v):
|
||||
return f"you are an approved contributor in +{self.board.name}."
|
||||
elif self.parent.author_id == v.id:
|
||||
return "this is a reply to your content."
|
||||
elif v.admin_level >= 4:
|
||||
return "you are a Drama admin."
|
||||
|
||||
@property
|
||||
def json_raw(self):
|
||||
data= {
|
||||
'id': self.base36id,
|
||||
'fullname': self.fullname,
|
||||
'level': self.level,
|
||||
'author_name': self.author.username if not self.author.is_deleted else None,
|
||||
'author_name': self.author.username if not self.author.deleted_utc > 0 else None,
|
||||
'body': self.body,
|
||||
'body_html': self.body_html,
|
||||
'is_archived': self.is_archived,
|
||||
|
@ -257,10 +213,9 @@ class Comment(Base, Age_times, Scores, Stndrd, Fuzzing):
|
|||
'created_utc': self.created_utc,
|
||||
'edited_utc': self.edited_utc or 0,
|
||||
'is_banned': bool(self.is_banned),
|
||||
'is_deleted': self.is_deleted,
|
||||
'deleted_utc': self.deleted_utc,
|
||||
'is_nsfw': self.over_18,
|
||||
'is_offensive': self.is_offensive,
|
||||
'is_nsfl': self.is_nsfl,
|
||||
'permalink': self.permalink,
|
||||
'post_id': self.post.base36id,
|
||||
'score': self.score_fuzzed,
|
||||
|
@ -284,14 +239,12 @@ class Comment(Base, Age_times, Scores, Stndrd, Fuzzing):
|
|||
'id': self.base36id,
|
||||
'post': self.post.base36id,
|
||||
'level': self.level,
|
||||
'parent': self.parent_fullname
|
||||
}
|
||||
elif self.deleted_utc > 0:
|
||||
data= {'deleted_utc': self.deleted_utc,
|
||||
'id': self.base36id,
|
||||
'post': self.post.base36id,
|
||||
'level': self.level,
|
||||
'parent': self.parent_fullname
|
||||
}
|
||||
else:
|
||||
|
||||
|
@ -315,7 +268,6 @@ class Comment(Base, Age_times, Scores, Stndrd, Fuzzing):
|
|||
|
||||
data["author"]=self.author.json_core
|
||||
data["post"]=self.post.json_core
|
||||
data["guild"]=self.post.board.json_core
|
||||
|
||||
if self.level >= 2:
|
||||
data["parent"]=self.parent.json_core
|
||||
|
@ -435,7 +387,6 @@ class Comment(Base, Age_times, Scores, Stndrd, Fuzzing):
|
|||
"deleted_utc": self.deleted_utc,
|
||||
'created_utc': self.created_utc,
|
||||
'id': self.base36id,
|
||||
'fullname': self.fullname,
|
||||
'permalink': self.permalink,
|
||||
'post_id': self.post.base36id,
|
||||
'level': self.level
|
||||
|
@ -461,7 +412,7 @@ class Comment(Base, Age_times, Scores, Stndrd, Fuzzing):
|
|||
@property
|
||||
@lazy
|
||||
def is_op(self):
|
||||
return self.author_id==self.post.author_id and not self.author.is_deleted and not self.post.author.is_deleted and not self.post.is_deleted
|
||||
return self.author_id==self.post.author_id and not self.author.deleted_utc > 0 and not self.post.author.deleted_utc > 0 and not self.post.deleted_utc
|
||||
|
||||
|
||||
|
||||
|
|
|
@ -45,8 +45,6 @@ class Report(Base):
|
|||
post_id = Column(Integer, ForeignKey("submissions.id"))
|
||||
user_id = Column(Integer, ForeignKey("users.id"))
|
||||
created_utc = Column(Integer)
|
||||
|
||||
board_id = Column(Integer, server_default=FetchedValue())
|
||||
|
||||
user = relationship("User", lazy = "joined", primaryjoin = "Report.user_id == User.id", uselist = False)
|
||||
|
||||
|
|
|
@ -37,6 +37,7 @@ class Submission(Base, Stndrd, Age_times, Scores, Fuzzing):
|
|||
uselist=False,
|
||||
innerjoin=True,
|
||||
primaryjoin="Submission.id==SubmissionAux.id")
|
||||
gm_distinguish = Column(Integer, default=0)
|
||||
author_id = Column(BigInteger, ForeignKey("users.id"))
|
||||
repost_id = Column(BigInteger, ForeignKey("submissions.id"), default=0)
|
||||
edited_utc = Column(BigInteger, default=0)
|
||||
|
@ -48,8 +49,6 @@ class Submission(Base, Stndrd, Age_times, Scores, Fuzzing):
|
|||
banaward = Column(String, default=None)
|
||||
purged_utc = Column(Integer, default=0)
|
||||
distinguish_level = Column(Integer, default=0)
|
||||
gm_distinguish = Column(Integer, ForeignKey("boards.id"), default=0)
|
||||
distinguished_board = relationship("Board", lazy="joined", primaryjoin="Board.id==Submission.gm_distinguish")
|
||||
created_str = Column(String(255), default=None)
|
||||
stickied = Column(Boolean, default=False)
|
||||
is_pinned = Column(Boolean, default=False)
|
||||
|
@ -64,11 +63,7 @@ class Submission(Base, Stndrd, Age_times, Scores, Fuzzing):
|
|||
flags = relationship("Flag", backref="submission")
|
||||
is_approved = Column(Integer, ForeignKey("users.id"), default=0)
|
||||
approved_utc = Column(Integer, default=0)
|
||||
board_id = Column(Integer, ForeignKey("boards.id"), default=None)
|
||||
original_board_id = Column(Integer, ForeignKey("boards.id"), default=None)
|
||||
over_18 = Column(Boolean, default=False)
|
||||
original_board = relationship(
|
||||
"Board", primaryjoin="Board.id==Submission.original_board_id")
|
||||
creation_ip = Column(String(64), default="")
|
||||
mod_approved = Column(Integer, default=None)
|
||||
accepted_utc = Column(Integer, default=0)
|
||||
|
@ -78,12 +73,6 @@ class Submission(Base, Stndrd, Age_times, Scores, Fuzzing):
|
|||
score_top = Column(Float, default=1)
|
||||
score_activity = Column(Float, default=0)
|
||||
is_offensive = Column(Boolean, default=False)
|
||||
is_nsfl = Column(Boolean, default=False)
|
||||
board = relationship(
|
||||
"Board",
|
||||
lazy="joined",
|
||||
innerjoin=True,
|
||||
primaryjoin="Submission.board_id==Board.id")
|
||||
author = relationship(
|
||||
"User",
|
||||
lazy="joined",
|
||||
|
@ -138,16 +127,6 @@ class Submission(Base, Stndrd, Age_times, Scores, Fuzzing):
|
|||
|
||||
def __repr__(self):
|
||||
return f"<Submission(id={self.id})>"
|
||||
|
||||
@property
|
||||
@lazy
|
||||
def board_base36id(self):
|
||||
return base36encode(self.board_id)
|
||||
|
||||
@property
|
||||
@lazy
|
||||
def is_deleted(self):
|
||||
return bool(self.deleted_utc)
|
||||
|
||||
@property
|
||||
@lazy
|
||||
|
@ -215,17 +194,12 @@ class Submission(Base, Stndrd, Age_times, Scores, Fuzzing):
|
|||
if "replies" not in self.__dict__ and "_preloaded_comments" in self.__dict__:
|
||||
self.tree_comments(comment=comment)
|
||||
|
||||
# return template
|
||||
is_allowed_to_comment = self.board.can_comment(
|
||||
v) and not self.is_archived
|
||||
|
||||
return render_template(template,
|
||||
v=v,
|
||||
p=self,
|
||||
sort=sort,
|
||||
linked_comment=comment,
|
||||
comment_info=comment_info,
|
||||
is_allowed_to_comment=is_allowed_to_comment,
|
||||
render_replies=True,
|
||||
)
|
||||
|
||||
|
@ -288,33 +262,18 @@ class Submission(Base, Stndrd, Age_times, Scores, Fuzzing):
|
|||
else:
|
||||
return None
|
||||
|
||||
def visibility_reason(self, v):
|
||||
|
||||
|
||||
if not v or self.author_id == v.id:
|
||||
return "this is your content."
|
||||
elif self.is_pinned:
|
||||
return "a guildmaster has pinned it."
|
||||
elif self.board.has_mod(v):
|
||||
return f"you are a guildmaster of +{self.board.name}."
|
||||
elif self.board.has_contributor(v):
|
||||
return f"you are an approved contributor in +{self.board.name}."
|
||||
elif v.admin_level >= 4:
|
||||
return "you are a Drama admin."
|
||||
|
||||
@property
|
||||
|
||||
def json_raw(self):
|
||||
data = {'author_name': self.author.username if not self.author.is_deleted else None,
|
||||
data = {'author_name': self.author.username if not self.author.deleted_utc > 0 else None,
|
||||
'permalink': self.permalink,
|
||||
'is_banned': bool(self.is_banned),
|
||||
'is_deleted': self.is_deleted,
|
||||
'deleted_utc': self.deleted_utc,
|
||||
'created_utc': self.created_utc,
|
||||
'id': self.base36id,
|
||||
'fullname': self.fullname,
|
||||
'title': self.title,
|
||||
'is_nsfw': self.over_18,
|
||||
'is_nsfl': self.is_nsfl,
|
||||
'is_bot': self.is_bot,
|
||||
'thumb_url': self.thumb_url,
|
||||
'domain': self.domain,
|
||||
|
@ -324,8 +283,6 @@ class Submission(Base, Stndrd, Age_times, Scores, Fuzzing):
|
|||
'body_html': self.body_html,
|
||||
'created_utc': self.created_utc,
|
||||
'edited_utc': self.edited_utc or 0,
|
||||
'guild_name': self.board.name,
|
||||
'guild_id': base36encode(self.board_id),
|
||||
'comment_count': self.comment_count,
|
||||
'score': self.score_fuzzed,
|
||||
'upvotes': self.upvotes_fuzzed,
|
||||
|
@ -339,9 +296,6 @@ class Submission(Base, Stndrd, Age_times, Scores, Fuzzing):
|
|||
if self.ban_reason:
|
||||
data["ban_reason"]=self.ban_reason
|
||||
|
||||
if self.board_id != self.original_board_id and self.original_board:
|
||||
data['original_guild_name'] = self.original_board.name
|
||||
data['original_guild_id'] = base36encode(self.original_board_id)
|
||||
return data
|
||||
|
||||
@property
|
||||
|
@ -349,20 +303,18 @@ class Submission(Base, Stndrd, Age_times, Scores, Fuzzing):
|
|||
|
||||
if self.is_banned:
|
||||
return {'is_banned': True,
|
||||
'is_deleted': self.is_deleted,
|
||||
'deleted_utc': self.deleted_utc,
|
||||
'ban_reason': self.ban_reason,
|
||||
'id': self.base36id,
|
||||
'title': self.title,
|
||||
'permalink': self.permalink,
|
||||
'guild_name': self.board.name
|
||||
}
|
||||
elif self.is_deleted:
|
||||
elif self.deleted_utc:
|
||||
return {'is_banned': bool(self.is_banned),
|
||||
'is_deleted': True,
|
||||
'deleted_utc': True,
|
||||
'id': self.base36id,
|
||||
'title': self.title,
|
||||
'permalink': self.permalink,
|
||||
'guild_name': self.board.name
|
||||
}
|
||||
|
||||
return self.json_raw
|
||||
|
@ -376,8 +328,6 @@ class Submission(Base, Stndrd, Age_times, Scores, Fuzzing):
|
|||
return data
|
||||
|
||||
data["author"]=self.author.json_core
|
||||
data["guild"]=self.board.json_core
|
||||
data["original_guild"]=self.original_board.json_core if not self.board_id==self.original_board_id else None
|
||||
data["comment_count"]=self.comment_count
|
||||
|
||||
|
||||
|
@ -506,10 +456,6 @@ class Submission(Base, Stndrd, Age_times, Scores, Fuzzing):
|
|||
def is_blocking(self):
|
||||
return self.__dict__.get('_is_blocking', False)
|
||||
|
||||
@property
|
||||
def is_public(self):
|
||||
return self.post_public or not self.board.is_private
|
||||
|
||||
@property
|
||||
def flag_count(self):
|
||||
return len(self.flags)
|
||||
|
@ -553,15 +499,10 @@ class Submission(Base, Stndrd, Age_times, Scores, Fuzzing):
|
|||
'created_utc': self.created_utc,
|
||||
'id': self.base36id,
|
||||
'fullname': self.fullname,
|
||||
'guild_name': self.board.name,
|
||||
'comment_count': self.comment_count,
|
||||
'permalink': self.permalink
|
||||
}
|
||||
|
||||
if self.original_board_id and (self.original_board_id!= self.board_id):
|
||||
|
||||
data['original_guild_name'] = self.original_board.name
|
||||
|
||||
return data
|
||||
|
||||
@property
|
||||
|
|
|
@ -8,13 +8,11 @@ class Subscription(Base):
|
|||
__tablename__ = "subscriptions"
|
||||
id = Column(BigInteger, primary_key=True)
|
||||
user_id = Column(BigInteger, ForeignKey("users.id"))
|
||||
board_id = Column(BigInteger, ForeignKey("boards.id"))
|
||||
created_utc = Column(BigInteger, default=0)
|
||||
is_active = Column(Boolean, default=True)
|
||||
submission_id = Column(BigInteger, default=0)
|
||||
|
||||
user = relationship("User", uselist=False)
|
||||
board = relationship("Board", uselist=False)
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
if "created_utc" not in kwargs:
|
||||
|
|
|
@ -8,8 +8,6 @@ from .alts import Alt
|
|||
from .titles import Title
|
||||
from .submission import SaveRelationship
|
||||
from .comment import Notification
|
||||
from .boards import Board
|
||||
from .board_relationships import *
|
||||
from .subscriptions import *
|
||||
from .userblock import *
|
||||
from .badges import *
|
||||
|
@ -93,12 +91,11 @@ class User(Base, Stndrd, Age_times):
|
|||
mfa_secret = deferred(Column(String(16), default=None))
|
||||
hide_offensive = Column(Boolean, default=False)
|
||||
hide_bot = Column(Boolean, default=False)
|
||||
show_nsfl = Column(Boolean, default=False)
|
||||
is_private = Column(Boolean, default=False)
|
||||
read_announcement_utc = Column(Integer, default=0)
|
||||
unban_utc = Column(Integer, default=0)
|
||||
|
||||
is_deleted = Column(Boolean, default=False)
|
||||
deleted_utc = Column(Boolean, default=False)
|
||||
delete_reason = Column(String(500), default='')
|
||||
filter_nsfw = Column(Boolean, default=False)
|
||||
stored_subscriber_count = Column(Integer, default=0)
|
||||
|
@ -129,12 +126,6 @@ class User(Base, Stndrd, Age_times):
|
|||
moderates = relationship("ModRelationship")
|
||||
banned_from = relationship("BanRelationship", primaryjoin="BanRelationship.user_id==User.id")
|
||||
subscriptions = relationship("Subscription")
|
||||
boards_created = relationship("Board", lazy="dynamic")
|
||||
contributes = relationship(
|
||||
"ContributorRelationship",
|
||||
lazy="dynamic",
|
||||
primaryjoin="ContributorRelationship.user_id==User.id")
|
||||
board_blocks = relationship("BoardBlock", lazy="dynamic")
|
||||
|
||||
following = relationship("Follow", primaryjoin="Follow.user_id==User.id")
|
||||
followers = relationship("Follow", primaryjoin="Follow.target_id==User.id")
|
||||
|
@ -262,21 +253,7 @@ class User(Base, Stndrd, Age_times):
|
|||
m = g.db.query(ModRelationship).filter_by(user_id=v.id, invite_rescinded=False).subquery()
|
||||
c = v.contributes.subquery()
|
||||
|
||||
comments = comments.join(m,
|
||||
m.c.board_id == Submission.board_id,
|
||||
isouter=True
|
||||
).join(c,
|
||||
c.c.board_id == Submission.board_id,
|
||||
isouter=True
|
||||
).join(Board, Board.id == Submission.board_id)
|
||||
comments = comments.filter(or_(Comment.author_id == v.id,
|
||||
Submission.post_public == True,
|
||||
Board.is_private == False,
|
||||
m.c.board_id != None,
|
||||
c.c.board_id != None))
|
||||
else:
|
||||
comments = comments.join(Board, Board.id == Submission.board_id).filter(
|
||||
or_(Submission.post_public == True, Board.is_private == False))
|
||||
comments = comments.filter(or_(Comment.author_id == v.id))
|
||||
|
||||
comments = comments.options(contains_eager(Comment.post))
|
||||
|
||||
|
@ -310,20 +287,6 @@ class User(Base, Stndrd, Age_times):
|
|||
secondrange = firstrange + 26
|
||||
return [x.id for x in comments[firstrange:secondrange]]
|
||||
|
||||
@property
|
||||
@lazy
|
||||
def mods_anything(self):
|
||||
|
||||
return bool([i for i in self.moderates if i.accepted])
|
||||
|
||||
@property
|
||||
def boards_modded(self):
|
||||
|
||||
z = [x.board for x in self.moderates if x and x.board and x.accepted and not x.board.is_banned]
|
||||
z = sorted(z, key=lambda x: x.name)
|
||||
|
||||
return z
|
||||
|
||||
@property
|
||||
def base36id(self):
|
||||
return base36encode(self.id)
|
||||
|
@ -332,15 +295,6 @@ class User(Base, Stndrd, Age_times):
|
|||
def fullname(self):
|
||||
return f"t1_{self.base36id}"
|
||||
|
||||
@property
|
||||
@cache.memoize(timeout=60)
|
||||
def has_report_queue(self):
|
||||
board_ids = [
|
||||
x.board_id for x in self.moderates.filter_by(
|
||||
accepted=True).all()]
|
||||
return bool(g.db.query(Submission).filter(Submission.board_id.in_(
|
||||
board_ids), Submission.mod_approved == 0, Submission.is_banned == False).join(Submission.reports).first())
|
||||
|
||||
@property
|
||||
def banned_by(self):
|
||||
|
||||
|
@ -617,44 +571,8 @@ class User(Base, Stndrd, Age_times):
|
|||
else:
|
||||
return self.defaultpicture()
|
||||
|
||||
@property
|
||||
def available_titles(self):
|
||||
|
||||
locs = {"v": self,
|
||||
"Board": Board,
|
||||
"Submission": Submission
|
||||
}
|
||||
|
||||
titles = [
|
||||
i for i in g.db.query(Title).order_by(
|
||||
text("id asc")).all() if eval(
|
||||
i.qualification_expr, {}, locs)]
|
||||
return titles
|
||||
|
||||
@property
|
||||
def can_make_guild(self):
|
||||
return False
|
||||
|
||||
@property
|
||||
def can_join_gms(self):
|
||||
return len([x for x in self.boards_modded if x.is_siegable]) < 10
|
||||
|
||||
@property
|
||||
def can_siege(self):
|
||||
|
||||
if self.is_suspended:
|
||||
return False
|
||||
|
||||
now = int(time.time())
|
||||
|
||||
return now - max(self.last_siege_utc,
|
||||
self.created_utc) > 60 * 60 * 24 * 7
|
||||
|
||||
@property
|
||||
def can_submit_image(self):
|
||||
# Has premium
|
||||
# Has 1000 Rep, or 500 for older accounts
|
||||
# if connecting through Tor, must have verified email
|
||||
return self.dramacoins >= 0
|
||||
|
||||
@property
|
||||
|
@ -700,10 +618,10 @@ class User(Base, Stndrd, Age_times):
|
|||
'id': self.base36id
|
||||
}
|
||||
|
||||
elif self.is_deleted:
|
||||
elif self.deleted_utc:
|
||||
return {'username': self.username,
|
||||
'permalink': self.permalink,
|
||||
'is_deleted': True,
|
||||
'deleted_utc': True,
|
||||
'id': self.base36id
|
||||
}
|
||||
return self.json_raw
|
||||
|
@ -712,7 +630,7 @@ class User(Base, Stndrd, Age_times):
|
|||
def json(self):
|
||||
data = self.json_core
|
||||
|
||||
if self.is_deleted or self.is_banned:
|
||||
if self.deleted_utc > 0 or self.is_banned:
|
||||
return data
|
||||
|
||||
data["badges"] = [x.json_core for x in self.badges]
|
||||
|
@ -734,7 +652,7 @@ class User(Base, Stndrd, Age_times):
|
|||
if self.is_banned and self.unban_utc == 0:
|
||||
return False
|
||||
|
||||
elif self.is_deleted:
|
||||
elif self.deleted_utc:
|
||||
return False
|
||||
|
||||
else:
|
||||
|
@ -869,90 +787,12 @@ class User(Base, Stndrd, Age_times):
|
|||
|
||||
return [x[0] for x in comments.offset(25 * (page - 1)).limit(26).all()]
|
||||
|
||||
def guild_rep(self, guild, recent=0):
|
||||
|
||||
posts = g.db.query(Submission.score).filter_by(
|
||||
is_banned=False,
|
||||
original_board_id=guild.id)
|
||||
|
||||
if recent:
|
||||
cutoff = int(time.time()) - 60 * 60 * 24 * recent
|
||||
posts = posts.filter(Submission.created_utc > cutoff)
|
||||
|
||||
posts = posts.all()
|
||||
|
||||
post_rep = sum([x[0] for x in posts]) - len(list(sum([x[0] for x in posts])))
|
||||
|
||||
comments = g.db.query(Comment.score).filter_by(
|
||||
is_banned=False,
|
||||
original_board_id=guild.id)
|
||||
|
||||
if recent:
|
||||
cutoff = int(time.time()) - 60 * 60 * 24 * recent
|
||||
comments = comments.filter(Comment.created_utc > cutoff)
|
||||
|
||||
comments = comments.all()
|
||||
|
||||
comment_rep = sum([x[0] for x in comments]) - len(list(sum([x[0] for x in comments])))
|
||||
|
||||
return int(post_rep + comment_rep)
|
||||
|
||||
@property
|
||||
def has_premium(self):
|
||||
|
||||
now = int(time.time())
|
||||
|
||||
if self.negative_balance_cents:
|
||||
return False
|
||||
|
||||
elif self.premium_expires_utc > now:
|
||||
return True
|
||||
|
||||
elif self.coin_balance >= 1:
|
||||
self.coin_balance -= 1
|
||||
self.premium_expires_utc = now + 60 * 60 * 24 * 7
|
||||
|
||||
g.db.add(self)
|
||||
|
||||
return True
|
||||
|
||||
else:
|
||||
|
||||
if self.premium_expires_utc:
|
||||
self.premium_expires_utc = 0
|
||||
g.db.add(self)
|
||||
|
||||
return False
|
||||
|
||||
@property
|
||||
def has_premium_no_renew(self):
|
||||
|
||||
now = int(time.time())
|
||||
|
||||
if self.negative_balance_cents:
|
||||
return False
|
||||
elif self.premium_expires_utc > now:
|
||||
return True
|
||||
elif self.coin_balance >= 1:
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
|
||||
@property
|
||||
def renew_premium_time(self):
|
||||
return time.strftime("%d %b %Y at %H:%M:%S",
|
||||
time.gmtime(self.premium_expires_utc))
|
||||
|
||||
@property
|
||||
def filter_words(self):
|
||||
l = [i.strip() for i in self.custom_filter_list.split('\n')] if self.custom_filter_list else []
|
||||
l = [i for i in l if i]
|
||||
return l
|
||||
|
||||
@property
|
||||
def boards_modded_ids(self):
|
||||
return [x.id for x in self.boards_modded]
|
||||
|
||||
@property
|
||||
def json_admin(self):
|
||||
data = self.json_raw
|
||||
|
@ -966,7 +806,7 @@ class User(Base, Stndrd, Age_times):
|
|||
|
||||
@property
|
||||
def can_upload_comment_image(self):
|
||||
return self.dramacoins >= 0 and (request.headers.get("cf-ipcountry") != "T1" or self.is_activated)
|
||||
return self.dramacoins >= 0 and request.headers.get("cf-ipcountry") != "T1"
|
||||
|
||||
@property
|
||||
def can_change_name(self):
|
||||
|
|
|
@ -3,18 +3,11 @@ import time
|
|||
from .security import *
|
||||
|
||||
|
||||
def session_over18(board):
|
||||
def session_over18():
|
||||
|
||||
now = int(time.time())
|
||||
|
||||
return session.get('over_18', {}).get(board.base36id, 0) >= now
|
||||
|
||||
|
||||
def session_isnsfl(board):
|
||||
|
||||
now = int(time.time())
|
||||
|
||||
return session.get('show_nsfl', {}).get(board.base36id, 0) >= now
|
||||
return session.get('over_18', {}).get(1) >= now
|
||||
|
||||
|
||||
def make_logged_out_formkey(t):
|
||||
|
|
|
@ -47,11 +47,9 @@ def get_logged_in_user(db=None):
|
|||
nonce = session.get("login_nonce", 0)
|
||||
if not uid:
|
||||
x= (None, None)
|
||||
v = db.query(User).options(
|
||||
joinedload(User.moderates).joinedload(ModRelationship.board), #joinedload(Board.reports),
|
||||
).filter_by(
|
||||
v = db.query(User).filter_by(
|
||||
id=uid,
|
||||
is_deleted=False
|
||||
deleted_utc=False
|
||||
).first()
|
||||
|
||||
if v and v.agendaposter_expires_utc and v.agendaposter_expires_utc < g.timestamp:
|
||||
|
@ -94,7 +92,6 @@ def check_ban_evade(v):
|
|||
kind="ban_post",
|
||||
user_id=2317,
|
||||
target_submission_id=post.id,
|
||||
board_id=post.board_id,
|
||||
note="ban evasion"
|
||||
)
|
||||
g.db.add(ma)
|
||||
|
@ -113,7 +110,6 @@ def check_ban_evade(v):
|
|||
kind="ban_comment",
|
||||
user_id=2317,
|
||||
target_comment_id=comment.id,
|
||||
board_id=comment.post.board_id,
|
||||
note="ban evasion"
|
||||
)
|
||||
g.db.add(ma)
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
from .admin import *
|
||||
from .boards import *
|
||||
from .comments import *
|
||||
from .discord import *
|
||||
from .errors import *
|
||||
|
|
|
@ -126,8 +126,7 @@ def flagged_comments(v):
|
|||
@app.route("/admin", methods=["GET"])
|
||||
@admin_level_required(3)
|
||||
def admin_home(v):
|
||||
b = g.db.query(Board).filter_by(id=1).first()
|
||||
return render_template("admin/admin_home.html", v=v, b=b)
|
||||
return render_template("admin/admin_home.html", v=v)
|
||||
|
||||
|
||||
@app.route("/admin/badge_grant", methods=["GET"])
|
||||
|
@ -536,7 +535,6 @@ def agendaposter(user_id, v):
|
|||
kind=kind,
|
||||
user_id=v.id,
|
||||
target_user_id=user.id,
|
||||
board_id=1,
|
||||
note = note
|
||||
)
|
||||
g.db.add(ma)
|
||||
|
@ -546,14 +544,11 @@ def agendaposter(user_id, v):
|
|||
else:
|
||||
return redirect(user.url)
|
||||
|
||||
@app.route("/disablesignups", methods=["POST"])
|
||||
@admin_level_required(6)
|
||||
@validate_formkey
|
||||
def disablesignups(v):
|
||||
board = g.db.query(Board).filter_by(id=1).first()
|
||||
board.disablesignups = not board.disablesignups
|
||||
g.db.add(board)
|
||||
return "", 204
|
||||
# @app.route("/disablesignups", methods=["POST"])
|
||||
# @admin_level_required(6)
|
||||
# @validate_formkey
|
||||
# def disablesignups(v):
|
||||
# return "", 204
|
||||
|
||||
|
||||
@app.route("/shadowban/<user_id>", methods=["POST"])
|
||||
|
@ -572,7 +567,6 @@ def shadowban(user_id, v):
|
|||
kind="shadowban",
|
||||
user_id=v.id,
|
||||
target_user_id=user.id,
|
||||
board_id=1,
|
||||
)
|
||||
g.db.add(ma)
|
||||
cache.delete_memoized(frontlist)
|
||||
|
@ -595,7 +589,6 @@ def unshadowban(user_id, v):
|
|||
kind="unshadowban",
|
||||
user_id=v.id,
|
||||
target_user_id=user.id,
|
||||
board_id=1,
|
||||
)
|
||||
g.db.add(ma)
|
||||
cache.delete_memoized(frontlist)
|
||||
|
@ -629,7 +622,6 @@ def admin_title_change(user_id, v):
|
|||
kind=kind,
|
||||
user_id=v.id,
|
||||
target_user_id=user.id,
|
||||
board_id=1,
|
||||
note=f'"{new_name}"'
|
||||
)
|
||||
g.db.add(ma)
|
||||
|
@ -683,7 +675,6 @@ def ban_user(user_id, v):
|
|||
kind="exile_user",
|
||||
user_id=v.id,
|
||||
target_user_id=user.id,
|
||||
board_id=1,
|
||||
note=f'reason: "{reason}", duration: {duration}'
|
||||
)
|
||||
g.db.add(ma)
|
||||
|
@ -717,7 +708,6 @@ def unban_user(user_id, v):
|
|||
kind="unexile_user",
|
||||
user_id=v.id,
|
||||
target_user_id=user.id,
|
||||
board_id=1,
|
||||
)
|
||||
g.db.add(ma)
|
||||
g.db.commit()
|
||||
|
@ -757,7 +747,6 @@ def ban_post(post_id, v):
|
|||
kind="ban_post",
|
||||
user_id=v.id,
|
||||
target_submission_id=post.id,
|
||||
board_id=post.board_id,
|
||||
)
|
||||
g.db.add(ma)
|
||||
return "", 204
|
||||
|
@ -778,7 +767,6 @@ def unban_post(post_id, v):
|
|||
kind="unban_post",
|
||||
user_id=v.id,
|
||||
target_submission_id=post.id,
|
||||
board_id=post.board_id,
|
||||
)
|
||||
g.db.add(ma)
|
||||
|
||||
|
@ -857,7 +845,6 @@ def api_ban_comment(c_id, v):
|
|||
kind="ban_comment",
|
||||
user_id=v.id,
|
||||
target_comment_id=comment.id,
|
||||
board_id=comment.post.board_id,
|
||||
)
|
||||
g.db.add(ma)
|
||||
return "", 204
|
||||
|
@ -877,7 +864,6 @@ def api_unban_comment(c_id, v):
|
|||
kind="unban_comment",
|
||||
user_id=v.id,
|
||||
target_comment_id=comment.id,
|
||||
board_id=comment.post.board_id,
|
||||
)
|
||||
g.db.add(ma)
|
||||
|
||||
|
@ -911,7 +897,6 @@ def admin_distinguish_comment(c_id, v):
|
|||
v=v,
|
||||
comments=[comment],
|
||||
render_replies=False,
|
||||
is_allowed_to_comment=True
|
||||
)
|
||||
|
||||
html=str(BeautifulSoup(html, features="html.parser").find(id=f"comment-{comment.base36id}-only"))
|
||||
|
@ -987,7 +972,6 @@ def admin_nuke_user(v):
|
|||
kind="nuke_user",
|
||||
user_id=v.id,
|
||||
target_user_id=user.id,
|
||||
board_id=1,
|
||||
)
|
||||
g.db.add(ma)
|
||||
|
||||
|
@ -1018,7 +1002,6 @@ def admin_nunuke_user(v):
|
|||
kind="unnuke_user",
|
||||
user_id=v.id,
|
||||
target_user_id=user.id,
|
||||
board_id=1,
|
||||
)
|
||||
g.db.add(ma)
|
||||
|
||||
|
@ -1178,4 +1161,51 @@ def multiple_plots(**kwargs):
|
|||
plt.savefig(name)
|
||||
plt.clf()
|
||||
|
||||
return upload_from_file(name, name)
|
||||
return upload_from_file(name, name)
|
||||
|
||||
|
||||
@app.route("/admin/distinguish_post/<pid>", methods=["POST"])
|
||||
@app.route("/api/v1/distinguish_post/<pid>", methods=["POST"])
|
||||
@admin_level_required(6)
|
||||
@api("update")
|
||||
def distinguish_post(pid, v):
|
||||
|
||||
post = get_post(pid, v=v)
|
||||
|
||||
if post.author_id != v.id:
|
||||
abort(403)
|
||||
|
||||
if post.gm_distinguish:
|
||||
post.gm_distinguish = 0
|
||||
else:
|
||||
post.gm_distinguish = 1
|
||||
g.db.add(post)
|
||||
|
||||
ma=ModAction(
|
||||
kind="herald_post" if post.gm_distinguish else "unherald_post",
|
||||
user_id=v.id,
|
||||
target_submission_id=post.id,
|
||||
)
|
||||
g.db.add(ma)
|
||||
|
||||
return "", 204
|
||||
|
||||
@app.route("/admin/add_admin", methods=["POST"])
|
||||
@auth_required
|
||||
@validate_formkey
|
||||
def invite_username(v):
|
||||
|
||||
username = request.form.get("username", '').lstrip('@')
|
||||
user = get_user(username)
|
||||
if not user:
|
||||
return jsonify({"error": "That user doesn't exist."}), 404
|
||||
user.admin_level = 6
|
||||
g.db.add(user)
|
||||
ma=ModAction(
|
||||
kind="add_mod",
|
||||
user_id=v.id,
|
||||
target_user_id=user.id,
|
||||
)
|
||||
g.db.add(ma)
|
||||
|
||||
return "", 204
|
|
@ -1,311 +0,0 @@
|
|||
from drama.helpers.wrappers import *
|
||||
from drama.helpers.alerts import *
|
||||
from drama.classes import *
|
||||
from flask import *
|
||||
from drama.__main__ import app, limiter, cache
|
||||
|
||||
valid_board_regex = re.compile("^[a-zA-Z0-9][a-zA-Z0-9_]{2,24}$")
|
||||
|
||||
@app.route("/mod/distinguish_post/<bid>/<pid>", methods=["POST"])
|
||||
@app.route("/api/v1/distinguish_post/<bid>/<pid>", methods=["POST"])
|
||||
@auth_required
|
||||
@api("guildmaster")
|
||||
def mod_distinguish_post(bid, pid, board, v):
|
||||
|
||||
#print(pid, board, v)
|
||||
|
||||
post = get_post(pid, v=v)
|
||||
|
||||
if not post.board_id==board.id:
|
||||
abort(400)
|
||||
|
||||
if post.author_id != v.id:
|
||||
abort(403)
|
||||
|
||||
if post.gm_distinguish:
|
||||
post.gm_distinguish = 0
|
||||
else:
|
||||
post.gm_distinguish = board.id
|
||||
g.db.add(post)
|
||||
|
||||
ma=ModAction(
|
||||
kind="herald_post" if post.gm_distinguish else "unherald_post",
|
||||
user_id=v.id,
|
||||
target_submission_id=post.id,
|
||||
board_id=board.id
|
||||
)
|
||||
g.db.add(ma)
|
||||
|
||||
return "", 204
|
||||
|
||||
@app.route("/mod/invite_mod", methods=["POST"])
|
||||
@auth_required
|
||||
@validate_formkey
|
||||
def mod_invite_username(v):
|
||||
|
||||
username = request.form.get("username", '').lstrip('@')
|
||||
user = get_user(username)
|
||||
if not user:
|
||||
return jsonify({"error": "That user doesn't exist."}), 404
|
||||
|
||||
if not user.can_join_gms:
|
||||
return jsonify({"error": f"@{user.username} already leads enough guilds."}), 409
|
||||
|
||||
x = g.db.query(ModRelationship).filter_by(
|
||||
user_id=user.id, board_id=1).first()
|
||||
|
||||
if x and x.accepted:
|
||||
return jsonify({"error": f"@{user.username} is already a mod."}), 409
|
||||
|
||||
if x and not x.invite_rescinded:
|
||||
return jsonify({"error": f"@{user.username} has already been invited."}), 409
|
||||
|
||||
if x:
|
||||
|
||||
x.invite_rescinded = False
|
||||
g.db.add(x)
|
||||
|
||||
else:
|
||||
x = ModRelationship(
|
||||
user_id=user.id,
|
||||
board_id=1,
|
||||
accepted=False,
|
||||
perm_full=True,
|
||||
perm_content=True,
|
||||
perm_appearance=True,
|
||||
perm_access=True,
|
||||
perm_config=True
|
||||
)
|
||||
|
||||
text = f"You have been invited to become an admin. You can [click here](/badmins) and accept this invitation. Or, if you weren't expecting this, you can ignore it."
|
||||
send_notification(1046, user, text)
|
||||
|
||||
g.db.add(x)
|
||||
|
||||
ma=ModAction(
|
||||
kind="invite_mod",
|
||||
user_id=v.id,
|
||||
target_user_id=user.id,
|
||||
board_id=1
|
||||
)
|
||||
g.db.add(ma)
|
||||
|
||||
return "", 204
|
||||
|
||||
|
||||
@app.route("/mod/<bid>/rescind/<username>", methods=["POST"])
|
||||
@auth_required
|
||||
@validate_formkey
|
||||
def mod_rescind_bid_username(bid, username, board, v):
|
||||
|
||||
user = get_user(username)
|
||||
|
||||
invitation = g.db.query(ModRelationship).filter_by(board_id=board.id,
|
||||
user_id=user.id,
|
||||
accepted=False).first()
|
||||
if not invitation:
|
||||
abort(404)
|
||||
|
||||
invitation.invite_rescinded = True
|
||||
|
||||
g.db.add(invitation)
|
||||
ma=ModAction(
|
||||
kind="uninvite_mod",
|
||||
user_id=v.id,
|
||||
target_user_id=user.id,
|
||||
board_id=1
|
||||
)
|
||||
g.db.add(ma)
|
||||
return "", 204
|
||||
|
||||
|
||||
@app.route("/mod/accept/<bid>", methods=["POST"])
|
||||
@app.route("/api/v1/accept_invite/<bid>", methods=["POST"])
|
||||
@auth_required
|
||||
@validate_formkey
|
||||
@api("guildmaster")
|
||||
def mod_accept_board(bid, v):
|
||||
|
||||
board = g.db.query(Board).first()
|
||||
|
||||
x = board.has_invite(v)
|
||||
if not x:
|
||||
abort(404)
|
||||
|
||||
if not v.can_join_gms:
|
||||
return jsonify({"error": f"You already lead enough guilds."}), 409
|
||||
if board.has_ban(v):
|
||||
return jsonify({"error": f"You are exiled from +{board.name} and can't currently become a guildmaster."}), 409
|
||||
x.accepted = True
|
||||
x.created_utc=int(time.time())
|
||||
g.db.add(x)
|
||||
|
||||
ma=ModAction(
|
||||
kind="accept_mod_invite",
|
||||
user_id=v.id,
|
||||
target_user_id=v.id,
|
||||
board_id=board.id
|
||||
)
|
||||
g.db.add(ma)
|
||||
|
||||
v.admin_level = 6
|
||||
return "", 204
|
||||
|
||||
@app.route("/mod/<bid>/step_down", methods=["POST"])
|
||||
@auth_required
|
||||
@validate_formkey
|
||||
def mod_step_down(bid, board, v):
|
||||
|
||||
|
||||
v_mod = board.has_mod(v)
|
||||
|
||||
if not v_mod:
|
||||
abort(404)
|
||||
|
||||
g.db.delete(v_mod)
|
||||
|
||||
ma=ModAction(
|
||||
kind="dethrone_self",
|
||||
user_id=v.id,
|
||||
target_user_id=v.id,
|
||||
board_id=board.id
|
||||
)
|
||||
g.db.add(ma)
|
||||
v.admin_level = 0
|
||||
return "", 204
|
||||
|
||||
|
||||
|
||||
@app.route("/mod/<bid>/remove/<username>", methods=["POST"])
|
||||
@auth_required
|
||||
@validate_formkey
|
||||
def mod_remove_username(bid, username, board, v):
|
||||
|
||||
user = get_user(username)
|
||||
|
||||
u_mod = board.has_mod(user)
|
||||
v_mod = board.has_mod(v)
|
||||
|
||||
if not u_mod:
|
||||
abort(400)
|
||||
elif not v_mod:
|
||||
abort(400)
|
||||
|
||||
if not u_mod.board_id==board.id:
|
||||
abort(400)
|
||||
|
||||
if not v_mod.board_id==board.id:
|
||||
abort(400)
|
||||
|
||||
if v_mod.id > u_mod.id:
|
||||
abort(403)
|
||||
|
||||
g.db.delete(u_mod)
|
||||
|
||||
ma=ModAction(
|
||||
kind="remove_mod",
|
||||
user_id=v.id,
|
||||
target_user_id=user.id,
|
||||
board_id=board.id
|
||||
)
|
||||
g.db.add(ma)
|
||||
|
||||
user.admin_level = 0
|
||||
return "", 204
|
||||
|
||||
@app.route("/badmins", methods=["GET"])
|
||||
@app.route("/api/vue/mod/mods", methods=["GET"])
|
||||
@app.route("/api/v1/mod/mods", methods=["GET"])
|
||||
@auth_desired
|
||||
@public("read")
|
||||
def board_about_mods(v):
|
||||
|
||||
board = g.db.query(Board).first()
|
||||
|
||||
me = board.has_mod(v)
|
||||
|
||||
return {
|
||||
"html":lambda:render_template("mods.html", v=v, b=board, me=me),
|
||||
"api":lambda:jsonify({"data":[x.json for x in board.mods_list]})
|
||||
}
|
||||
|
||||
@app.route("/log", methods=["GET"])
|
||||
@app.route("/api/v1/mod_log", methods=["GET"])
|
||||
@auth_desired
|
||||
@api("read")
|
||||
def board_mod_log(v):
|
||||
|
||||
page=int(request.args.get("page",1))
|
||||
|
||||
if v and v.admin_level == 6: actions = g.db.query(ModAction).order_by(ModAction.id.desc()).offset(25 * (page - 1)).limit(26).all()
|
||||
else: actions=g.db.query(ModAction).filter(ModAction.kind!="shadowban", ModAction.kind!="unshadowban").order_by(ModAction.id.desc()).offset(25*(page-1)).limit(26).all()
|
||||
actions=[i for i in actions]
|
||||
|
||||
next_exists=len(actions)==26
|
||||
actions=actions[0:25]
|
||||
|
||||
return {
|
||||
"html":lambda:render_template(
|
||||
"modlog.html",
|
||||
v=v,
|
||||
actions=actions,
|
||||
next_exists=next_exists,
|
||||
page=page
|
||||
),
|
||||
"api":lambda:jsonify({"data":[x.json for x in actions]})
|
||||
}
|
||||
|
||||
@app.route("/log/<aid>", methods=["GET"])
|
||||
@auth_desired
|
||||
def mod_log_item(aid, v):
|
||||
|
||||
action=g.db.query(ModAction).filter_by(id=base36decode(aid)).first()
|
||||
|
||||
if not action:
|
||||
abort(404)
|
||||
|
||||
if request.path != action.permalink:
|
||||
return redirect(action.permalink)
|
||||
|
||||
return render_template("modlog.html",
|
||||
v=v,
|
||||
actions=[action],
|
||||
next_exists=False,
|
||||
page=1,
|
||||
action=action
|
||||
)
|
||||
|
||||
@app.route("/mod/edit_perms", methods=["POST"])
|
||||
@auth_required
|
||||
@validate_formkey
|
||||
def board_mod_perms_change(boardname, board, v):
|
||||
|
||||
user=get_user(request.form.get("username"))
|
||||
|
||||
v_mod=board.has_mod(v)
|
||||
u_mod=board.has_mod_record(user)
|
||||
|
||||
if v_mod.id > u_mod.id:
|
||||
return jsonify({"error":"You can't change perms on badmins above you."}), 403
|
||||
|
||||
#print({x:request.form.get(x) for x in request.form})
|
||||
|
||||
u_mod.perm_full = bool(request.form.get("perm_full" , False))
|
||||
u_mod.perm_access = bool(request.form.get("perm_access" , False))
|
||||
u_mod.perm_appearance = bool(request.form.get("perm_appearance" , False))
|
||||
u_mod.perm_config = bool(request.form.get("perm_config" , False))
|
||||
u_mod.perm_content = bool(request.form.get("perm_content" , False))
|
||||
|
||||
g.db.add(u_mod)
|
||||
g.db.commit()
|
||||
|
||||
ma=ModAction(
|
||||
kind="change_perms" if u_mod.accepted else "change_invite",
|
||||
user_id=v.id,
|
||||
board_id=board.id,
|
||||
target_user_id=user.id,
|
||||
note=u_mod.permchangelist
|
||||
)
|
||||
g.db.add(ma)
|
||||
|
||||
return redirect(f"{board.permalink}/mod/mods")
|
|
@ -39,7 +39,6 @@ def banawardcomment(comment_id, v):
|
|||
kind="exile_user",
|
||||
user_id=v.id,
|
||||
target_user_id=u.id,
|
||||
board_id=1,
|
||||
note=f'reason: "1 day ban award", duration: 1 day'
|
||||
)
|
||||
g.db.add(ma)
|
||||
|
@ -85,16 +84,14 @@ def post_pid_comment_cid(cid, pid=None, anything=None, v=None):
|
|||
except: abort(404)
|
||||
|
||||
post = get_post(pid, v=v)
|
||||
board = post.board
|
||||
|
||||
if post.over_18 and not (v and v.over_18) and not session_over18(comment.board):
|
||||
if post.over_18 and not (v and v.over_18) and not session_over18(1):
|
||||
t = int(time.time())
|
||||
return {'html': lambda: render_template("errors/nsfw.html",
|
||||
v=v,
|
||||
t=t,
|
||||
lo_formkey=make_logged_out_formkey(
|
||||
t),
|
||||
board=comment.board
|
||||
),
|
||||
'api': lambda: {'error': f'This content is not suitable for some users and situations.'}
|
||||
|
||||
|
@ -107,7 +104,7 @@ def post_pid_comment_cid(cid, pid=None, anything=None, v=None):
|
|||
except: context = 0
|
||||
comment_info = comment
|
||||
c = comment
|
||||
while context > 0 and not c.is_top_level:
|
||||
while context > 0 and c.level > 1:
|
||||
|
||||
parent = get_comment(c.parent_comment_id, v=v)
|
||||
|
||||
|
@ -312,12 +309,6 @@ def api_comment(v):
|
|||
return jsonify(
|
||||
{"error": "You can't reply to users who have blocked you, or users you have blocked."}), 403
|
||||
|
||||
# check for archive and ban state
|
||||
post = get_post(parent_id)
|
||||
if post.is_archived or not post.board.can_comment(v):
|
||||
|
||||
return jsonify({"error": "You can't comment on this."}), 403
|
||||
|
||||
# get bot status
|
||||
is_bot = request.headers.get("X-User-Type","")=="Bot"
|
||||
|
||||
|
@ -362,7 +353,6 @@ def api_comment(v):
|
|||
user_id=2317,
|
||||
target_comment_id=comment.id,
|
||||
kind="ban_comment",
|
||||
board_id=comment.post.board_id,
|
||||
note="spam"
|
||||
)
|
||||
g.db.add(ma)
|
||||
|
@ -400,8 +390,6 @@ def api_comment(v):
|
|||
parent_comment_id=parent_comment_id,
|
||||
level=level,
|
||||
over_18=post.over_18 or request.form.get("over_18","")=="true",
|
||||
is_nsfl=post.is_nsfl or request.form.get("is_nsfl","")=="true",
|
||||
original_board_id=parent_post.board_id,
|
||||
is_bot=is_bot,
|
||||
app_id=v.client.application.id if v.client else None,
|
||||
shadowbanned=shadowbanned
|
||||
|
@ -424,21 +412,6 @@ def api_comment(v):
|
|||
with CustomRenderer(post_id=parent_id) as renderer:
|
||||
body_md = renderer.render(mistletoe.Document(body))
|
||||
body_html = sanitize(body_md, linkgen=True)
|
||||
|
||||
# #csam detection
|
||||
# def del_function():
|
||||
# delete_file(name)
|
||||
# c.is_banned=True
|
||||
# g.db.add(c)
|
||||
# g.db.commit()
|
||||
|
||||
# csam_thread=threading.Thread(target=check_csam_url,
|
||||
# args=(f"https://s3.eu-central-1.amazonaws.com/i.ruqqus.ga/{name}",
|
||||
# v,
|
||||
# del_function
|
||||
# )
|
||||
# )
|
||||
# csam_thread.start()
|
||||
|
||||
c_aux = CommentAux(
|
||||
id=c.id,
|
||||
|
@ -462,7 +435,6 @@ def api_comment(v):
|
|||
parent_fullname=c.fullname,
|
||||
parent_comment_id=c.id,
|
||||
level=level+1,
|
||||
original_board_id=1,
|
||||
is_bot=True,
|
||||
)
|
||||
|
||||
|
@ -497,7 +469,6 @@ def api_comment(v):
|
|||
parent_fullname=c.fullname,
|
||||
parent_comment_id=c.id,
|
||||
level=level+1,
|
||||
original_board_id=1,
|
||||
is_bot=True,
|
||||
)
|
||||
|
||||
|
@ -530,7 +501,6 @@ def api_comment(v):
|
|||
parent_fullname=c.fullname,
|
||||
parent_comment_id=c.id,
|
||||
level=level+1,
|
||||
original_board_id=1,
|
||||
is_bot=True,
|
||||
)
|
||||
|
||||
|
@ -558,7 +528,6 @@ def api_comment(v):
|
|||
parent_fullname=c2.fullname,
|
||||
parent_comment_id=c2.id,
|
||||
level=level+2,
|
||||
original_board_id=1,
|
||||
is_bot=True,
|
||||
)
|
||||
|
||||
|
@ -586,7 +555,6 @@ def api_comment(v):
|
|||
parent_fullname=c3.fullname,
|
||||
parent_comment_id=c3.id,
|
||||
level=level+3,
|
||||
original_board_id=1,
|
||||
is_bot=True,
|
||||
)
|
||||
|
||||
|
@ -672,7 +640,6 @@ def api_comment(v):
|
|||
|
||||
# print(f"Content Event: @{v.username} comment {c.base36id}")
|
||||
|
||||
board = g.db.query(Board).first()
|
||||
cache.delete_memoized(comment_idlist)
|
||||
cache.delete_memoized(User.commentlisting, v)
|
||||
|
||||
|
@ -680,7 +647,6 @@ def api_comment(v):
|
|||
v=v,
|
||||
comments=[c],
|
||||
render_replies=False,
|
||||
is_allowed_to_comment=True
|
||||
)}),
|
||||
"api": lambda: c.json
|
||||
}
|
||||
|
@ -835,7 +801,6 @@ def edit_comment(cid, v):
|
|||
parent_fullname=c.fullname,
|
||||
parent_comment_id=c.id,
|
||||
level=c.level+1,
|
||||
original_board_id=1,
|
||||
is_bot=True,
|
||||
)
|
||||
|
||||
|
@ -961,15 +926,12 @@ def embed_comment_cid(cid, pid=None):
|
|||
'api': lambda: {'error': f'Comment {cid} has been removed'}
|
||||
}
|
||||
|
||||
if comment.board.is_banned:
|
||||
abort(410)
|
||||
|
||||
return render_template("embeds/comment.html", c=comment)
|
||||
|
||||
@app.route("/comment_pin/<cid>", methods=["POST"])
|
||||
@auth_required
|
||||
@validate_formkey
|
||||
def mod_toggle_comment_pin(cid, v):
|
||||
def toggle_comment_pin(cid, v):
|
||||
|
||||
comment = get_comment(cid, v=v)
|
||||
|
||||
|
@ -985,7 +947,6 @@ def mod_toggle_comment_pin(cid, v):
|
|||
ma=ModAction(
|
||||
kind="pin_comment" if comment.is_pinned else "unpin_comment",
|
||||
user_id=v.id,
|
||||
board_id=1,
|
||||
target_comment_id=comment.id
|
||||
)
|
||||
g.db.add(ma)
|
||||
|
@ -995,7 +956,6 @@ def mod_toggle_comment_pin(cid, v):
|
|||
v=v,
|
||||
comments=[comment],
|
||||
render_replies=False,
|
||||
is_allowed_to_comment=True
|
||||
)
|
||||
|
||||
html=str(BeautifulSoup(html, features="html.parser").find(id=f"comment-{comment.base36id}-only"))
|
||||
|
|
|
@ -154,24 +154,24 @@ def error_503(e, v):
|
|||
}
|
||||
|
||||
|
||||
@app.route("/allow_nsfw_logged_in/<bid>", methods=["POST"])
|
||||
@app.route("/allow_nsfw_logged_in", methods=["POST"])
|
||||
@auth_required
|
||||
@validate_formkey
|
||||
def allow_nsfw_logged_in(bid, v):
|
||||
def allow_nsfw_logged_in(v):
|
||||
|
||||
cutoff = int(time.time()) + 3600
|
||||
|
||||
if not session.get("over_18", None):
|
||||
session["over_18"] = {}
|
||||
|
||||
session["over_18"][bid] = cutoff
|
||||
session["over_18"][1] = cutoff
|
||||
|
||||
return redirect(request.form.get("redir"))
|
||||
|
||||
|
||||
@app.route("/allow_nsfw_logged_out/<bid>", methods=["POST"])
|
||||
@app.route("/allow_nsfw_logged_out", methods=["POST"])
|
||||
@auth_desired
|
||||
def allow_nsfw_logged_out(bid, v):
|
||||
def allow_nsfw_logged_out(v):
|
||||
|
||||
if v:
|
||||
return redirect('/')
|
||||
|
@ -187,49 +187,10 @@ def allow_nsfw_logged_out(bid, v):
|
|||
session["over_18"] = {}
|
||||
|
||||
cutoff = int(time.time()) + 3600
|
||||
session["over_18"][bid] = cutoff
|
||||
session["over_18"][1] = cutoff
|
||||
|
||||
return redirect(request.form.get("redir"))
|
||||
|
||||
|
||||
@app.route("/allow_nsfl_logged_in/<bid>", methods=["POST"])
|
||||
@auth_required
|
||||
@validate_formkey
|
||||
def allow_nsfl_logged_in(bid, v):
|
||||
|
||||
cutoff = int(time.time()) + 3600
|
||||
|
||||
if not session.get("show_nsfl", None):
|
||||
session["show_nsfl"] = {}
|
||||
|
||||
session["show_nsfl"][bid] = cutoff
|
||||
|
||||
return redirect(request.form.get("redir"))
|
||||
|
||||
|
||||
@app.route("/allow_nsfl_logged_out/<bid>", methods=["POST"])
|
||||
@auth_desired
|
||||
def allow_nsfl_logged_out(bid, v):
|
||||
|
||||
if v:
|
||||
return redirect('/')
|
||||
|
||||
t = int(request.form.get('time'))
|
||||
|
||||
if not validate_logged_out_formkey(t,
|
||||
request.form.get("formkey")
|
||||
):
|
||||
abort(403)
|
||||
|
||||
if not session.get("show_nsfl", None):
|
||||
session["show_nsfl"] = {}
|
||||
|
||||
cutoff = int(time.time()) + 3600
|
||||
session["show_nsfl"][bid] = cutoff
|
||||
|
||||
return redirect(request.form.get("redir"))
|
||||
|
||||
|
||||
@app.route("/error/<error>", methods=["GET"])
|
||||
@auth_desired
|
||||
def error_all_preview(error, v):
|
||||
|
|
|
@ -35,7 +35,6 @@ def feeds_user(sort='hot', t='all'):
|
|||
|
||||
for post in posts:
|
||||
#print("POST IMAGE "+ str( post.is_image ))
|
||||
board_name = f"+{post.board.name}"
|
||||
with tag("entry", ("xml:base", request.url)):
|
||||
with tag("title", type="text"):
|
||||
text(post.title)
|
||||
|
@ -60,8 +59,6 @@ def feeds_user(sort='hot', t='all'):
|
|||
|
||||
doc.stag("link", href=full_link(post.permalink))
|
||||
|
||||
doc.stag("category", term=board_name, label=board_name, schema=full_link("/" + board_name))
|
||||
|
||||
image_url = post.thumb_url or post.embed_url or post.url
|
||||
|
||||
doc.stag("media:thumbnail", url=image_url)
|
||||
|
|
|
@ -427,7 +427,6 @@ def all_comments(v):
|
|||
|
||||
idlist = idlist[0:25]
|
||||
|
||||
board = g.db.query(Board).first()
|
||||
return {"html": lambda: render_template("home_comments.html",
|
||||
v=v,
|
||||
sort=sort,
|
||||
|
|
|
@ -61,7 +61,7 @@ def login_post():
|
|||
if "@" in username:
|
||||
account = g.db.query(User).filter(
|
||||
User.email.ilike(username),
|
||||
User.is_deleted == False).first()
|
||||
User.deleted_utc == False).first()
|
||||
else:
|
||||
account = get_user(username, graceful=True)
|
||||
|
||||
|
@ -69,7 +69,7 @@ def login_post():
|
|||
time.sleep(random.uniform(0, 2))
|
||||
return render_template("login.html", failed=True, i=random_image())
|
||||
|
||||
if account.is_deleted:
|
||||
if account.deleted_utc:
|
||||
time.sleep(random.uniform(0, 2))
|
||||
return render_template("login.html", failed=True, i=random_image())
|
||||
|
||||
|
@ -161,11 +161,9 @@ def logout(v):
|
|||
@no_cors
|
||||
@auth_desired
|
||||
def sign_up_get(v):
|
||||
board = g.db.query(Board).filter_by(id=1).first()
|
||||
if board.disablesignups: return "Signups are disable for the time being.", 403
|
||||
#if disablesignups: return "Signups are disable for the time being.", 403
|
||||
|
||||
if v:
|
||||
return redirect("/")
|
||||
if v: return redirect("/")
|
||||
|
||||
agent = request.headers.get("User-Agent", None)
|
||||
if not agent:
|
||||
|
@ -219,8 +217,7 @@ def sign_up_get(v):
|
|||
@no_cors
|
||||
@auth_desired
|
||||
def sign_up_post(v):
|
||||
board = g.db.query(Board).filter_by(id=1).first()
|
||||
if board.disablesignups: return "Signups are disable for the time being.", 403
|
||||
#if disablesignups: return "Signups are disable for the time being.", 403
|
||||
|
||||
if v:
|
||||
abort(403)
|
||||
|
@ -421,7 +418,7 @@ def post_forgot():
|
|||
user = g.db.query(User).filter(
|
||||
User.username.ilike(username),
|
||||
User.email.ilike(email),
|
||||
User.is_deleted == False).first()
|
||||
User.deleted_utc == False).first()
|
||||
|
||||
if user:
|
||||
# generate url
|
||||
|
|
|
@ -12,7 +12,6 @@ SCOPES = {
|
|||
'update': 'Edit your posts and comments',
|
||||
'delete': 'Delete your posts and comments',
|
||||
'vote': 'Cast votes as you',
|
||||
'guildmaster': 'Perform Badmin actions'
|
||||
}
|
||||
|
||||
|
||||
|
@ -49,9 +48,8 @@ def oauth_authorize_prompt(v):
|
|||
if scope not in SCOPES:
|
||||
return jsonify({"oauth_error": f"The provided scope `{scope}` is not valid."}), 400
|
||||
|
||||
if any(x in scopes for x in ["create", "update",
|
||||
"guildmaster"]) and "identity" not in scopes:
|
||||
return jsonify({"oauth_error": f"`identity` scope required when requesting `create`, `update`, or `guildmaster` scope."}), 400
|
||||
if any(x in scopes for x in ["create", "update"]) and "identity" not in scopes:
|
||||
return jsonify({"oauth_error": f"`identity` scope required when requesting `create` or `update` scope."}), 400
|
||||
|
||||
redirect_uri = request.args.get("redirect_uri")
|
||||
if not redirect_uri:
|
||||
|
@ -112,9 +110,8 @@ def oauth_authorize_post(v):
|
|||
if scope not in SCOPES:
|
||||
return jsonify({"oauth_error": f"The provided scope `{scope}` is not valid."}), 400
|
||||
|
||||
if any(x in scopes for x in ["create", "update",
|
||||
"guildmaster"]) and "identity" not in scopes:
|
||||
return jsonify({"oauth_error": f"`identity` scope required when requesting `create`, `update`, or `guildmaster` scope."}), 400
|
||||
if any(x in scopes for x in ["create", "update"]) and "identity" not in scopes:
|
||||
return jsonify({"oauth_error": f"`identity` scope required when requesting `create` or `update` scope."}), 400
|
||||
|
||||
if not state:
|
||||
return jsonify({'oauth_error': 'state argument required'}), 400
|
||||
|
@ -131,7 +128,6 @@ def oauth_authorize_post(v):
|
|||
scope_update="update" in scopes,
|
||||
scope_delete="delete" in scopes,
|
||||
scope_vote="vote" in scopes,
|
||||
scope_guildmaster="guildmaster" in scopes,
|
||||
refresh_token=secrets.token_urlsafe(128)[0:128] if permanent else None
|
||||
)
|
||||
|
||||
|
|
|
@ -40,7 +40,6 @@ def postbanaward(post_id, v):
|
|||
kind="exile_user",
|
||||
user_id=v.id,
|
||||
target_user_id=u.id,
|
||||
board_id=1,
|
||||
note=f'reason: "1 day ban award", duration: 1 day'
|
||||
)
|
||||
g.db.add(ma)
|
||||
|
@ -69,13 +68,9 @@ def publish(pid, v):
|
|||
@auth_required
|
||||
def submit_get(v):
|
||||
if v and v.is_banned and not v.unban_utc: return render_template("seized.html")
|
||||
|
||||
b = g.db.query(Board).first()
|
||||
|
||||
|
||||
return render_template("submit.html",
|
||||
v=v,
|
||||
b=b
|
||||
)
|
||||
v=v)
|
||||
|
||||
@app.route("/post/<pid>", methods=["GET"])
|
||||
@app.route("/post/<pid>/", methods=["GET"])
|
||||
|
@ -237,15 +232,12 @@ def post_base36id(pid, anything=None, v=None):
|
|||
g.db.add(post)
|
||||
g.db.commit()
|
||||
|
||||
board = post.board
|
||||
|
||||
if post.over_18 and not (v and v.over_18) and not session_over18(board):
|
||||
if post.over_18 and not (v and v.over_18) and not session_over18(1):
|
||||
t = int(time.time())
|
||||
return {"html":lambda:render_template("errors/nsfw.html",
|
||||
v=v,
|
||||
t=t,
|
||||
lo_formkey=make_logged_out_formkey(t),
|
||||
board=post.board
|
||||
|
||||
),
|
||||
"api":lambda:(jsonify({"error":"Must be 18+ to view"}), 451)
|
||||
|
@ -271,9 +263,6 @@ def edit_post(pid, v):
|
|||
if p.is_banned:
|
||||
abort(403)
|
||||
|
||||
if p.board.has_ban(v):
|
||||
abort(403)
|
||||
|
||||
body = request.form.get("body", "")
|
||||
for i in re.finditer('^(https:\/\/.*\.(png|jpg|jpeg|gif))', body, re.MULTILINE): body = body.replace(i.group(1), f'})')
|
||||
body = body.replace("\n", "\n\n")
|
||||
|
@ -346,9 +335,6 @@ def edit_post(pid, v):
|
|||
parent_fullname=p.fullname,
|
||||
level=1,
|
||||
over_18=False,
|
||||
is_nsfl=False,
|
||||
is_offensive=False,
|
||||
original_board_id=1,
|
||||
is_bot=True,
|
||||
app_id=None,
|
||||
creation_region=request.headers.get("cf-ipcountry"),
|
||||
|
@ -600,8 +586,6 @@ def submit_post(v):
|
|||
if repost:
|
||||
return redirect(repost.permalink)
|
||||
|
||||
board = g.db.query(Board).first()
|
||||
|
||||
if not title:
|
||||
return {"html": lambda: (render_template("submit.html",
|
||||
v=v,
|
||||
|
@ -610,22 +594,10 @@ def submit_post(v):
|
|||
url=url,
|
||||
body=request.form.get(
|
||||
"body", ""),
|
||||
b=board
|
||||
), 400),
|
||||
"api": lambda: ({"error": "Please enter a better title"}, 400)
|
||||
}
|
||||
|
||||
# if len(title)<10:
|
||||
# return render_template("submit.html",
|
||||
# v=v,
|
||||
# error="Please enter a better title.",
|
||||
# title=title,
|
||||
# url=url,
|
||||
# body=request.form.get("body",""),
|
||||
# b=board
|
||||
# )
|
||||
|
||||
|
||||
elif len(title) > 500:
|
||||
return {"html": lambda: (render_template("submit.html",
|
||||
v=v,
|
||||
|
@ -634,7 +606,6 @@ def submit_post(v):
|
|||
url=url,
|
||||
body=request.form.get(
|
||||
"body", ""),
|
||||
b=board
|
||||
), 400),
|
||||
"api": lambda: ({"error": "500 character limit for titles"}, 400)
|
||||
}
|
||||
|
@ -649,7 +620,6 @@ def submit_post(v):
|
|||
url=url,
|
||||
body=request.form.get(
|
||||
"body", ""),
|
||||
b=board
|
||||
), 400),
|
||||
"api": lambda: ({"error": "`url` or `body` parameter required."}, 400)
|
||||
}
|
||||
|
@ -677,7 +647,6 @@ def submit_post(v):
|
|||
|
||||
Submission.author_id == v.id,
|
||||
Submission.deleted_utc == 0,
|
||||
Submission.board_id == board.id,
|
||||
SubmissionAux.title == title,
|
||||
SubmissionAux.url == url,
|
||||
SubmissionAux.body == body
|
||||
|
@ -710,7 +679,6 @@ def submit_post(v):
|
|||
url=url,
|
||||
body=request.form.get(
|
||||
"body", ""),
|
||||
b=board
|
||||
), 400),
|
||||
"api": lambda: ({"error": "ToS violation"}, 400)
|
||||
}
|
||||
|
@ -727,65 +695,6 @@ def submit_post(v):
|
|||
|
||||
embed = None
|
||||
|
||||
# board
|
||||
board_name = request.form.get("board", "general")
|
||||
board_name = board_name.lstrip("+")
|
||||
board_name = board_name.strip()
|
||||
|
||||
board = g.db.query(Board).first()
|
||||
|
||||
if not board:
|
||||
|
||||
return {"html": lambda: (render_template("submit.html",
|
||||
v=v,
|
||||
error=f"Please enter a Guild to submit to.",
|
||||
title=title,
|
||||
url=url, body=request.form.get(
|
||||
"body", ""),
|
||||
b=None
|
||||
), 403),
|
||||
"api": lambda: (jsonify({"error": f"403 Forbidden - +{board.name} has been banned."}))
|
||||
}
|
||||
|
||||
if board.is_banned:
|
||||
|
||||
return {"html": lambda: (render_template("submit.html",
|
||||
v=v,
|
||||
error=f"+{board.name} has been banned.",
|
||||
title=title,
|
||||
url=url, body=request.form.get(
|
||||
"body", ""),
|
||||
b=None
|
||||
), 403),
|
||||
"api": lambda: (jsonify({"error": f"403 Forbidden - +{board.name} has been banned."}))
|
||||
}
|
||||
|
||||
if board.has_ban(v):
|
||||
return {"html": lambda: (render_template("submit.html",
|
||||
v=v,
|
||||
error=f"You are exiled from +{board.name}.",
|
||||
title=title,
|
||||
url=url, body=request.form.get(
|
||||
"body", ""),
|
||||
b=None
|
||||
), 403),
|
||||
"api": lambda: (jsonify({"error": f"403 Not Authorized - You are exiled from +{board.name}"}), 403)
|
||||
}
|
||||
|
||||
if (board.restricted_posting or board.is_private) and not (
|
||||
board.can_submit(v)):
|
||||
return {"html": lambda: (render_template("submit.html",
|
||||
v=v,
|
||||
error=f"You are not an approved contributor for +{board.name}.",
|
||||
title=title,
|
||||
url=url,
|
||||
body=request.form.get(
|
||||
"body", ""),
|
||||
b=None
|
||||
), 403),
|
||||
"api": lambda: (jsonify({"error": f"403 Not Authorized - You are not an approved contributor for +{board.name}"}), 403)
|
||||
}
|
||||
|
||||
# similarity check
|
||||
now = int(time.time())
|
||||
cutoff = now - 60 * 60 * 24
|
||||
|
@ -857,7 +766,6 @@ def submit_post(v):
|
|||
user_id=2317,
|
||||
target_submission_id=post.id,
|
||||
kind="ban_post",
|
||||
board_id=post.board_id,
|
||||
note="spam"
|
||||
)
|
||||
g.db.add(ma)
|
||||
|
@ -874,7 +782,6 @@ def submit_post(v):
|
|||
url=url,
|
||||
body=request.form.get(
|
||||
"body", ""),
|
||||
b=board
|
||||
), 400),
|
||||
"api": lambda: ({"error": "10000 character limit for text body."}, 400)
|
||||
}
|
||||
|
@ -888,7 +795,6 @@ def submit_post(v):
|
|||
url=url,
|
||||
body=request.form.get(
|
||||
"body", ""),
|
||||
b=board
|
||||
), 400),
|
||||
"api": lambda: ({"error": "2048 character limit for URLs."}, 400)
|
||||
}
|
||||
|
@ -920,7 +826,6 @@ def submit_post(v):
|
|||
url=url,
|
||||
body=request.form.get(
|
||||
"body", ""),
|
||||
b=board
|
||||
), 403),
|
||||
"api": lambda: ({"error": reason}, 403)
|
||||
}
|
||||
|
@ -961,7 +866,6 @@ def submit_post(v):
|
|||
url=url,
|
||||
body=request.form.get(
|
||||
"body", ""),
|
||||
b=board
|
||||
), 400),
|
||||
"api": lambda: ({"error": f"The link `{badlink.link}` is not allowed. Reason: {badlink.reason}"}, 400)
|
||||
}
|
||||
|
@ -977,11 +881,7 @@ def submit_post(v):
|
|||
private=bool(request.form.get("private","")),
|
||||
author_id=v.id,
|
||||
domain_ref=domain_obj.id if domain_obj else None,
|
||||
board_id=board.id,
|
||||
original_board_id=board.id,
|
||||
over_18=bool(request.form.get("over_18","")),
|
||||
is_nsfl=bool(request.form.get("is_nsfl","")),
|
||||
post_public=not board.is_private,
|
||||
repost_id=repost.id if repost else None,
|
||||
is_offensive=False,
|
||||
app_id=v.client.application.id if v.client else None,
|
||||
|
@ -1037,7 +937,6 @@ def submit_post(v):
|
|||
title=title,
|
||||
body=request.form.get(
|
||||
"body", ""),
|
||||
b=board
|
||||
), 400),
|
||||
"api": lambda: ({"error": f"Image files only"}, 400)
|
||||
}
|
||||
|
@ -1054,7 +953,6 @@ def submit_post(v):
|
|||
# spin off thumbnail generation and csam detection as new threads
|
||||
if (new_post.url or request.files.get('file')) and (v.is_activated or request.headers.get('cf-ipcountry')!="T1"): thumbs(new_post)
|
||||
|
||||
# expire the relevant caches: front page new, board new
|
||||
cache.delete_memoized(frontlist)
|
||||
cache.delete_memoized(User.userpagelisting)
|
||||
g.db.commit()
|
||||
|
@ -1091,9 +989,6 @@ def submit_post(v):
|
|||
parent_fullname=new_post.fullname,
|
||||
level=1,
|
||||
over_18=False,
|
||||
is_nsfl=False,
|
||||
is_offensive=False,
|
||||
original_board_id=1,
|
||||
is_bot=True,
|
||||
app_id=None,
|
||||
creation_region=request.headers.get("cf-ipcountry"),
|
||||
|
@ -1131,9 +1026,6 @@ def submit_post(v):
|
|||
parent_fullname=new_post.fullname,
|
||||
level=1,
|
||||
over_18=False,
|
||||
is_nsfl=False,
|
||||
is_offensive=False,
|
||||
original_board_id=1,
|
||||
is_bot=True,
|
||||
app_id=None,
|
||||
creation_region=request.headers.get("cf-ipcountry")
|
||||
|
@ -1205,7 +1097,7 @@ def embed_post_pid(pid):
|
|||
|
||||
post = get_post(pid)
|
||||
|
||||
if post.is_banned or post.board.is_banned:
|
||||
if post.is_banned:
|
||||
abort(410)
|
||||
|
||||
return render_template("embeds/submission.html", p=post)
|
||||
|
@ -1232,12 +1124,7 @@ def toggle_post_nsfw(pid, v):
|
|||
|
||||
post = get_post(pid)
|
||||
|
||||
mod=post.board.has_mod(v)
|
||||
|
||||
if not post.author_id == v.id and not v.admin_level >= 3 and not mod:
|
||||
abort(403)
|
||||
|
||||
if post.board.over_18 and post.over_18:
|
||||
if not post.author_id == v.id and not v.admin_level >= 3:
|
||||
abort(403)
|
||||
|
||||
post.over_18 = not post.over_18
|
||||
|
@ -1248,7 +1135,6 @@ def toggle_post_nsfw(pid, v):
|
|||
kind="set_nsfw" if post.over_18 else "unset_nsfw",
|
||||
user_id=v.id,
|
||||
target_submission_id=post.id,
|
||||
board_id=post.board.id,
|
||||
)
|
||||
g.db.add(ma)
|
||||
|
||||
|
|
|
@ -55,7 +55,7 @@ def searchlisting(criteria, v=None, page=1, t="None", sort="top", b=None):
|
|||
posts=posts.filter(
|
||||
Submission.author_id==get_user(criteria['author']).id,
|
||||
User.is_private==False,
|
||||
User.is_deleted==False
|
||||
User.deleted_utc==False
|
||||
)
|
||||
|
||||
if 'domain' in criteria:
|
||||
|
|
|
@ -392,16 +392,6 @@ def settings_delete_banner(v):
|
|||
msg="Banner successfully removed.")
|
||||
|
||||
|
||||
@app.route("/settings/toggle_collapse", methods=["POST"])
|
||||
@auth_required
|
||||
@validate_formkey
|
||||
def settings_toggle_collapse(v):
|
||||
|
||||
session["sidebar_collapsed"] = not session.get("sidebar_collapsed", False)
|
||||
|
||||
return "", 204
|
||||
|
||||
|
||||
@app.route("/settings/read_announcement", methods=["POST"])
|
||||
@auth_required
|
||||
@validate_formkey
|
||||
|
|
|
@ -2,6 +2,65 @@ from drama.mail import *
|
|||
from drama.__main__ import app, limiter
|
||||
from drama.helpers.alerts import *
|
||||
|
||||
|
||||
@app.route("/badmins", methods=["GET"])
|
||||
@app.route("/api/vue/admin/mods", methods=["GET"])
|
||||
@app.route("/api/v1/admin/mods", methods=["GET"])
|
||||
@auth_desired
|
||||
@public("read")
|
||||
def badmins(v):
|
||||
badmins = g.db.query(User).filter_by(admin_level=6).all()
|
||||
return {
|
||||
"html":lambda:render_template("mods.html", v=v, badmins=badmins),
|
||||
"api":lambda:jsonify({"data":[x.json for x in badmins]})
|
||||
}
|
||||
|
||||
@app.route("/log", methods=["GET"])
|
||||
@app.route("/api/v1/mod_log", methods=["GET"])
|
||||
@auth_desired
|
||||
@api("read")
|
||||
def log(v):
|
||||
|
||||
page=int(request.args.get("page",1))
|
||||
|
||||
if v and v.admin_level == 6: actions = g.db.query(ModAction).order_by(ModAction.id.desc()).offset(25 * (page - 1)).limit(26).all()
|
||||
else: actions=g.db.query(ModAction).filter(ModAction.kind!="shadowban", ModAction.kind!="unshadowban").order_by(ModAction.id.desc()).offset(25*(page-1)).limit(26).all()
|
||||
actions=[i for i in actions]
|
||||
|
||||
next_exists=len(actions)==26
|
||||
actions=actions[0:25]
|
||||
|
||||
return {
|
||||
"html":lambda:render_template(
|
||||
"modlog.html",
|
||||
v=v,
|
||||
actions=actions,
|
||||
next_exists=next_exists,
|
||||
page=page
|
||||
),
|
||||
"api":lambda:jsonify({"data":[x.json for x in actions]})
|
||||
}
|
||||
|
||||
@app.route("/log/<aid>", methods=["GET"])
|
||||
@auth_desired
|
||||
def log_item(aid, v):
|
||||
|
||||
action=g.db.query(ModAction).filter_by(id=base36decode(aid)).first()
|
||||
|
||||
if not action:
|
||||
abort(404)
|
||||
|
||||
if request.path != action.permalink:
|
||||
return redirect(action.permalink)
|
||||
|
||||
return render_template("modlog.html",
|
||||
v=v,
|
||||
actions=[action],
|
||||
next_exists=False,
|
||||
page=1,
|
||||
action=action
|
||||
)
|
||||
|
||||
@app.route("/sex")
|
||||
def index():
|
||||
return render_template("index.html", **{"greeting": "Hello from Flask!"})
|
||||
|
|
|
@ -264,7 +264,7 @@ def u_username(username, v=None):
|
|||
|
||||
g.db.add(view)
|
||||
|
||||
if u.is_deleted and (not v or v.admin_level < 3):
|
||||
if u.deleted_utc > 0 and (not v or v.admin_level < 3):
|
||||
return {'html': lambda: render_template("userpage_deleted.html",
|
||||
u=u,
|
||||
v=v),
|
||||
|
@ -407,7 +407,6 @@ def u_username_comments(username, v=None):
|
|||
|
||||
is_following = (v and user.has_follower(v))
|
||||
|
||||
board = g.db.query(Board).first()
|
||||
return {"html": lambda: render_template("userpage_comments.html",
|
||||
u=user,
|
||||
v=v,
|
||||
|
|
|
@ -1,8 +1,5 @@
|
|||
{% extends "default.html" %}
|
||||
|
||||
{% block sidebarblock %}{% endblock %}
|
||||
{% block sidebarLeftblock %}{% endblock %}
|
||||
|
||||
{% block title %}
|
||||
<title>Drama</title>
|
||||
<meta name="description" content="Drama Help">
|
||||
|
|
|
@ -1,8 +1,5 @@
|
|||
{% extends "default.html" %}
|
||||
|
||||
{% block sidebarblock %}{% endblock %}
|
||||
{% block sidebarLeftblock %}{% endblock %}
|
||||
|
||||
{% block title %}
|
||||
<title>Drama</title>
|
||||
<meta name="description" content="Drama Help">
|
||||
|
|
|
@ -1,8 +1,5 @@
|
|||
{% extends "default.html" %}
|
||||
|
||||
{% block sidebarblock %}{% endblock %}
|
||||
{% block sidebarLeftblock %}{% endblock %}
|
||||
|
||||
{% block title %}
|
||||
<title>API App Administration</title>
|
||||
<meta name="description" content="Drama Help">
|
||||
|
|
|
@ -1,8 +1,5 @@
|
|||
{% extends "default.html" %}
|
||||
|
||||
{% block sidebarblock %}{% endblock %}
|
||||
{% block sidebarLeftblock %}{% endblock %}
|
||||
|
||||
{% block title %}
|
||||
<title>Drama</title>
|
||||
<meta name="description" content="Drama Help">
|
||||
|
|
|
@ -1,8 +1,5 @@
|
|||
{% extends "default.html" %}
|
||||
|
||||
{% block sidebarblock %}{% endblock %}
|
||||
{% block sidebarLeftblock %}{% endblock %}
|
||||
|
||||
{% block title %}
|
||||
<title>API App Administration</title>
|
||||
<meta name="description" content="Drama Help">
|
||||
|
|
|
@ -6,8 +6,6 @@
|
|||
|
||||
{% block pagetype %}message{% endblock %}
|
||||
|
||||
{% block sidebarblock %}{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
|
||||
{% if error %}
|
||||
|
|
|
@ -1,8 +1,5 @@
|
|||
{% extends "default.html" %}
|
||||
|
||||
{% block sidebarblock %}{% endblock %}
|
||||
{% block sidebarLeftblock %}{% endblock %}
|
||||
|
||||
{% block title %}
|
||||
<title>Drama</title>
|
||||
<meta name="description" content="Drama Help">
|
||||
|
|
|
@ -1,8 +1,5 @@
|
|||
{% extends "default.html" %}
|
||||
|
||||
{% block sidebarblock %}{% endblock %}
|
||||
{% block sidebarLeftblock %}{% endblock %}
|
||||
|
||||
{% block title %}
|
||||
<title>Drama</title>
|
||||
<meta name="description" content="Drama Help">
|
||||
|
|
|
@ -5,7 +5,6 @@
|
|||
{% block banner %}{% endblock %}
|
||||
{% block mobileBanner %}{% endblock %}
|
||||
{% block desktopBanner %}{% endblock %}
|
||||
{% block sidebarLeftblock %}{% endblock %}
|
||||
{% block desktopUserBanner %}{% endblock %}
|
||||
{% block mobileUserBanner %}{% endblock %}
|
||||
|
||||
|
|
|
@ -1,8 +1,5 @@
|
|||
{% extends "default.html" %}
|
||||
|
||||
{% block sidebarblock %}{% endblock %}
|
||||
{% block sidebarLeftblock %}{% endblock %}
|
||||
|
||||
{% block title %}
|
||||
<title>Image Ban</title>
|
||||
<meta name="description" content="Image Ban">
|
||||
|
|
|
@ -5,7 +5,6 @@
|
|||
{% block banner %}{% endblock %}
|
||||
{% block mobileBanner %}{% endblock %}
|
||||
{% block desktopBanner %}{% endblock %}
|
||||
{% block sidebarLeftblock %}{% endblock %}
|
||||
{% block desktopUserBanner %}{% endblock %}
|
||||
{% block mobileUserBanner %}{% endblock %}
|
||||
|
||||
|
@ -41,22 +40,6 @@
|
|||
{% endblock %}
|
||||
|
||||
|
||||
{% block sidebarblock %}
|
||||
<pre></pre>
|
||||
<pre></pre>
|
||||
<div class="sidebar-section sidebar-profile-basic">
|
||||
<div class="body">
|
||||
<pre>
|
||||
|
||||
|
||||
|
||||
</pre>
|
||||
<h5 class="h6 d-inline-block mb-0" style="color:black">Image Posts</h5>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<!-- Post filters bar visible only on medium devices or larger-->
|
||||
|
||||
|
|
|
@ -1,8 +1,5 @@
|
|||
{% extends "default.html" %}
|
||||
|
||||
{% block sidebarblock %}{% endblock %}
|
||||
{% block sidebarLeftblock %}{% endblock %}
|
||||
|
||||
{% block title %}
|
||||
<title>Purge Image</title>
|
||||
<meta name="description" content="Purge Image">
|
||||
|
|
|
@ -1,8 +1,5 @@
|
|||
{% extends "default.html" %}
|
||||
|
||||
{% block sidebarblock %}{% endblock %}
|
||||
{% block sidebarLeftblock %}{% endblock %}
|
||||
|
||||
{% block title %}
|
||||
<title>Drama</title>
|
||||
<meta name="description" content="Drama Help">
|
||||
|
|
|
@ -6,14 +6,4 @@
|
|||
{% include "user_listing.html" %}
|
||||
{% endblock %}
|
||||
|
||||
{% block sidebarblock %}
|
||||
<div class="sidebar-section sidebar-about">
|
||||
<div class="title">All Users</div>
|
||||
<div class="body">
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
||||
{% block navbar %}{% endblock %}
|
||||
|
||||
{% block sidebar %}{% endblock %}
|
||||
{% block navbar %}{% endblock %}
|
|
@ -1,8 +1,5 @@
|
|||
{% extends "default.html" %}
|
||||
|
||||
{% block sidebarblock %}{% endblock %}
|
||||
{% block sidebarLeftblock %}{% endblock %}
|
||||
|
||||
{% block title %}
|
||||
<title>Drama</title>
|
||||
<meta name="description" content="Drama Help">
|
||||
|
|
34
drama/templates/badmins.html
Normal file
34
drama/templates/badmins.html
Normal file
|
@ -0,0 +1,34 @@
|
|||
{% extends "settings2.html" %}
|
||||
|
||||
{% block pagetitle %}Badmins{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
|
||||
<div class="row justify-content-around">
|
||||
|
||||
<div class="card mb-5">
|
||||
<table class="table table-hover rounded mb-0">
|
||||
<thead class="thead-dark">
|
||||
<tr>
|
||||
<th scope="col">User</th>
|
||||
<th scope="col">Badmin Since</th>
|
||||
<th scope="col"></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody class="text-muted">
|
||||
{% for badmin in badmins %}
|
||||
<tr style="font-size:12.5px">
|
||||
<td>
|
||||
<a href="{{badmin.permalink}}">
|
||||
<img src="{{badmin.profile_url}}" class="profile-pic-20 align-top mr-2">@{{badmin.username}}</a>
|
||||
</td>
|
||||
</tr>
|
||||
{% else %}
|
||||
<td>There are no badmins.</td>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{% endblock %}
|
|
@ -1,4 +1,4 @@
|
|||
{% extends "guild_settings.html" %}
|
||||
{% extends "settings2.html" %}
|
||||
|
||||
{% block content %}
|
||||
<table class="table table-striped mb-5">
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
{% extends "guild_settings.html" %}
|
||||
{% extends "settings2.html" %}
|
||||
|
||||
{% block pagetitle %}Blocks{% endblock %}
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
{% extends "guild_settings.html" %}
|
||||
{% extends "settings2.html" %}
|
||||
|
||||
{% block pagetitle %}Changelog{% endblock %}
|
||||
|
||||
|
|
|
@ -85,7 +85,7 @@
|
|||
{% if c.parent_submission %}
|
||||
{% if c.author_id==v.id and c.child_comments and is_notification_page%}
|
||||
<span class="font-weight-bold">Comment {{'Replies' if (c.child_comments | length)>1 else 'Reply'}}: <a href="{{c.post.permalink}}">{{c.post.title | safe}}</a></span>
|
||||
{% elif c.post.author_id==v.id and c.is_top_level and is_notification_page%}
|
||||
{% elif c.post.author_id==v.id and c.level == 1 and is_notification_page%}
|
||||
<span class="font-weight-bold">Post Reply: <a href="{{c.post.permalink}}">{{c.post.title | safe}}</a></span>
|
||||
{% elif is_notification_page and c.parent_submission in v.subscribed_idlist() %}
|
||||
<span class="font-weight-bold">Subscribed Thread: <a href="{{c.post.permalink}}">{{c.post.title | safe}}</a></span>
|
||||
|
@ -116,7 +116,6 @@
|
|||
{% if c.banaward %} <i class="fas fa-gavel text-danger" data-toggle="tooltip" data-placement="bottom" title="" data-original-title="Given the 1-day ban award by @{{c.banaward}}"></i> {% endif %}
|
||||
{% if c.active_flags %} <a class="btn btn-primary" style="padding:1px 5px; font-size:10px;" href="javascript:void(0)" onclick="document.getElementById('flaggers-{{c.id}}').classList.toggle('d-none')">{{c.active_flags}} Reports</a> {% endif %}
|
||||
{% if c.over_18 %}<span class="badge badge-danger text-small-extra mr-1">+18</span> {% endif %}
|
||||
{% if c.is_nsfl %}<span class="badge text-black border-danger border-1 text-small-extra">nsfl</span> {% endif %}
|
||||
{% if v and v.admin_level==6 and c.author.shadowbanned %}<i class="fas fa-user-times text-admin" data-toggle="tooltip" data-placement="bottom" title="Shadowbanned user"></i> {% endif %}
|
||||
{% if c.is_pinned %}<i class="text-admin fas fa-thumbtack fa-rotate--45" data-toggle="tooltip" data-placement="bottom" title="" data-original-title="Pinned comment"></i> {% endif %}
|
||||
{% if c.distinguish_level %}<i class="fas fa-broom text-admin" data-toggle="tooltip" data-placement="bottom" title="" data-original-title="Drama Badmin, speaking officially"></i> {% endif %}
|
||||
|
@ -125,7 +124,7 @@
|
|||
{% if c.is_blocking %}<i class="fas fa-user-minus text-warning" data-toggle="tooltip" data-placement="bottom" title="" data-original-title="You're blocking this user, but you can see this comment because {{'it\'s an admin comment' if c.distinguish_level else 'you\'re an admin'}}."></i> {% endif %}
|
||||
{% if c.is_blocked %}<i class="fas fa-user-minus text-danger" data-toggle="tooltip" data-placement="bottom" title="" data-original-title="This user is blocking you, but you can see this comment because {{'it\'s an admin comment' if c.distinguish_level else 'you\'re an admin'}}."></i> {% endif %}
|
||||
|
||||
{% if c.author.is_deleted %}[deleted account]{% else %}<a {% if c.author.animatedname %}class="{% if c.author.patron %}patron{% else %}leaderboard{% endif %}"{% endif %} style="color:#{{c.author.namecolor}}; font-size:12px; font-weight:bold;" href="/@{{c.author.username}}"><img src="{{ c.author.profile_url }}" class="profile-pic-25 mr-2"/>{{c.author.username}}</a>{% if c.author.customtitle %} <bdi style="color: #{{c.author.titlecolor}}"> {{c.author.customtitle | safe}}</bdi>{% endif %}{% endif %}
|
||||
{% if c.author.deleted_utc > 0 %}[deleted account]{% else %}<a {% if c.author.animatedname %}class="{% if c.author.patron %}patron{% else %}leaderboard{% endif %}"{% endif %} style="color:#{{c.author.namecolor}}; font-size:12px; font-weight:bold;" href="/@{{c.author.username}}"><img src="{{ c.author.profile_url }}" class="profile-pic-25 mr-2"/>{{c.author.username}}</a>{% if c.author.customtitle %} <bdi style="color: #{{c.author.titlecolor}}"> {{c.author.customtitle | safe}}</bdi>{% endif %}{% endif %}
|
||||
|
||||
<span id="timestamp-{{c.id}}" data-toggle="tooltip" data-placement="bottom" title="" class="time-stamp"> {{c.age_string}}</span>
|
||||
{% if c.edited_utc %}
|
||||
|
@ -163,7 +162,7 @@
|
|||
</div>
|
||||
|
||||
{% if c.parent_submission %}
|
||||
{% if v and v.id==c.author_id and (standalone or is_allowed_to_comment) %}
|
||||
{% if v and v.id==c.author_id %}
|
||||
<div id="comment-edit-{{c.base36id}}" class="d-none comment-write collapsed child">
|
||||
<form id="comment-edit-form-{{c.base36id}}" action="/edit_comment/{{c.base36id}}" method="post" class="input-group" enctype="multipart/form-data">
|
||||
<input type="hidden" name="formkey" value="{{v.formkey}}">
|
||||
|
@ -257,10 +256,8 @@
|
|||
{% endif %}
|
||||
|
||||
{% if v %}
|
||||
{% if standalone or is_allowed_to_comment %}
|
||||
<li class="list-inline-item text-muted"><a href="javascript:void(0)" onclick="document.getElementById('reply-to-{{c.base36id}}').classList.remove('d-none')"><i class="fas fa-reply"
|
||||
aria-hidden="true"></i><span class="d-none d-md-inline-block">Reply</span></a></li>
|
||||
{% endif %}
|
||||
|
||||
{% endif %}
|
||||
<li class="list-inline-item text-muted d-none d-md-inline-block"><a href="{{c.permalink}}?context=99#context"{% if c.author.is_private %} rel="nofollow"{% endif %}><i class="fas fa-book-open"></i>Context</a></li>
|
||||
|
@ -280,7 +277,7 @@
|
|||
<div class="dropdown-menu border-0 shadow" aria-labelledby="dropdownMoreLink">
|
||||
{% if not (v and v.id==c.author_id) %}
|
||||
{% if v %}
|
||||
<a class="dropdown-item" href="javascript:void(0)" data-toggle="modal" data-target="#reportCommentModal" onclick="report_commentModal('{{c.base36id}}','{{c.author.username if not c.author.is_deleted else '[is_deleted]'}}',)"><i class="fas fa-flag fa-fw"></i>Report</a>
|
||||
<a class="dropdown-item" href="javascript:void(0)" data-toggle="modal" data-target="#reportCommentModal" onclick="report_commentModal('{{c.base36id}}','{{c.author.username if not c.author.deleted_utc > 0 else '[deleted_utc]'}}',)"><i class="fas fa-flag fa-fw"></i>Report</a>
|
||||
{% else %}
|
||||
<a class="dropdown-item" href="javascript:void(0)" data-toggle="modal" data-target="#reportCommentModal" onclick=""><i class="fas fa-flag fa-fw"></i>Flag</a>
|
||||
{% endif %}
|
||||
|
@ -332,12 +329,12 @@
|
|||
|
||||
{% if v and c.post and (v.admin_level == 6 or v.id == c.post.author_id) %}
|
||||
<div class="dropdown-divider"></div>
|
||||
{% if c.is_top_level %}
|
||||
{% if c.level == 1 %}
|
||||
<a class="dropdown-item text-info" id="pin-comment-{{c.base36id}}" href="javascript:void(0)" data-dismiss="modal" data-target="#actionsModal-{{c.base36id}}" onclick="post('/comment_pin/{{c.base36id}}', function(){window.location.reload(true);})"><i class="fas fa-thumbtack fa-rotate--45 fa-fw text-info"></i>{{"Unpin" if c.is_pinned else "Pin"}}</a>
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
{% if v and c.post and v.admin_level == 6 %}
|
||||
{% if v.id!=c.author_id and not c.author.is_deleted and c.original_board_id==c.post.board_id %}
|
||||
{% if v.id!=c.author_id %}
|
||||
{% if c.author.is_banned %}
|
||||
<a class="dropdown-item text-danger" id="unexile-comment-{{c.base36id}}" href="javascript:void(0)" onclick="post_toast('/api/unban_user/{{c.author_id}}?toast=1')"><i class="fas fa-user-minus fa-fw text-danger"></i>Unban user</a>
|
||||
{% else %}
|
||||
|
@ -474,7 +471,7 @@
|
|||
<li class="list-group-item"><a href="{{c.permalink}}?context=5#context"{% if c.author.is_private %} rel="nofollow"{% endif %}><i class="fas fa-dna"></i>Context</a></li>
|
||||
|
||||
{% if not (v and v.id==c.author_id) %}
|
||||
<li class="list-group-item"><a href="javascript:void(0)" data-toggle="modal" data-dismiss="modal" data-target="#reportCommentModal" onclick="report_commentModal('{{c.base36id}}','{{c.author.username if not c.author.is_deleted else '[is_deleted]'}}')" class="d-block"><i class="fas fa-flag"></i>Report</a></li>
|
||||
<li class="list-group-item"><a href="javascript:void(0)" data-toggle="modal" data-dismiss="modal" data-target="#reportCommentModal" onclick="report_commentModal('{{c.base36id}}','{{c.author.username if not c.author.deleted_utc > 0 else '[deleted_utc]'}}')" class="d-block"><i class="fas fa-flag"></i>Report</a></li>
|
||||
{% endif %}
|
||||
|
||||
{% if v and c.parent_submission and c.author_id==v.id %}
|
||||
|
@ -518,13 +515,13 @@
|
|||
{% endif %}
|
||||
|
||||
{% if v and c.post and (v.admin_level == 6 or v.id == c.post.author_id) %}
|
||||
{% if c.is_top_level %}
|
||||
{% if c.level == 1 %}
|
||||
<li class="list-group-item"><a class="d-block text-info" id="pin-comment-{{c.base36id}}" href="javascript:void(0)" data-dismiss="modal" data-target="#actionsModal-{{c.base36id}}" onclick="post('/comment_pin/{{c.base36id}}', function(){window.location.reload(true);})"><i class="fas fa-thumbtack fa-rotate--45 text-info"></i>{{'Unpin' if c.is_pinned else 'Pin'}}</a>
|
||||
</li>
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
{% if v and c.post and v.admin_level == 6 %}
|
||||
{% if c.author_id != v.id and not c.author.is_deleted and c.original_board_id==c.post.board_id %}
|
||||
{% if c.author_id != v.id and not c.author.deleted_utc > 0 %}
|
||||
{% if c.author.is_banned %}
|
||||
<li class="list-group-item"><a class="d-block text-danger" id="unexile-comment2-{{c.base36id}}" href="javascript:void(0)" onclick="post_toast('/api/unban_user/{{c.author_id}}?toast=1')"><i class="fas fa-user-minus fa-fw text-danger"></i>Unban user</a></li>
|
||||
{% else %}
|
||||
|
|
|
@ -5,8 +5,6 @@
|
|||
<meta name="description" content="Contact Drama Admins">
|
||||
{% endblock %}
|
||||
|
||||
<!-- Left Sidebar -->
|
||||
|
||||
|
||||
{% block content %}
|
||||
|
||||
|
|
|
@ -264,7 +264,7 @@
|
|||
|
||||
// Flag Submission
|
||||
|
||||
report_postModal = function(id, author, board) {
|
||||
report_postModal = function(id, author) {
|
||||
|
||||
document.getElementById("post-author").textContent = author;
|
||||
|
||||
|
@ -461,11 +461,11 @@
|
|||
|
||||
}
|
||||
|
||||
herald_comment=function(bid,cid){
|
||||
herald_comment=function(cid){
|
||||
|
||||
|
||||
var xhr = new XMLHttpRequest();
|
||||
xhr.open("post", "/mod/distinguish_comment/"+bid+'/'+cid);
|
||||
xhr.open("post", "/admin/distinguish_comment/"+cid);
|
||||
|
||||
var form = new FormData();
|
||||
|
||||
|
@ -1005,11 +1005,6 @@
|
|||
<div class="container">
|
||||
<div class="row justify-content-around" id="main-content-row">
|
||||
|
||||
{% block leftSidebar %}
|
||||
{% block leftSidebarBlock %}
|
||||
{% endblock %}
|
||||
{% endblock %}
|
||||
|
||||
<div class="col h-100 {% block customPadding %}{% if not '/message' in request.path %}custom-gutters{% endif %}{% endblock %}" id="main-content-col">
|
||||
|
||||
{% block desktopUserBanner %}
|
||||
|
@ -1045,9 +1040,6 @@
|
|||
{% block reportCommentModal %}
|
||||
{% endblock %}
|
||||
|
||||
{% block guildModal %}
|
||||
{% endblock %}
|
||||
|
||||
{% block GIFtoast %}
|
||||
{% endblock %}
|
||||
|
||||
|
|
|
@ -59,15 +59,6 @@
|
|||
|
||||
<li class="list-inline-item d-none d-md-inline-block mr-2">
|
||||
<span id="comment-{{c.base36id}}-score-none"class="d-none text-black">{{score}}</span> </li>
|
||||
|
||||
{% if not c.board.downvotes_disabled %}
|
||||
|
||||
|
||||
|
||||
<li id="comment-{{c.base36id}}-down" class="list-inline-item arrow-down d-none d-md-inline-block">
|
||||
</li>
|
||||
|
||||
{% endif %}
|
||||
<li class="list-inline-item text-muted d-none d-md-inline-block"><a href="javascript:void(0);" role="button" class="copy-link" data-clipboard-text="{{c.permalink | full_link}}"><i class="fas fa-link"></i><span>Copy link</span></a>
|
||||
</li>
|
||||
<li class="list-inline-item d-none d-md-inline-block">
|
||||
|
|
|
@ -1,6 +1,3 @@
|
|||
{% extends "default.html" %}
|
||||
|
||||
{% block sidebarLeftblock %}{% endblock %}
|
||||
{% block sidebar %}{% endblock %}
|
||||
|
||||
{% block customPadding %}{% endblock %}
|
|
@ -1,37 +0,0 @@
|
|||
{% extends "home.html" %}
|
||||
|
||||
{% block sidebarLeftblock %}
|
||||
|
||||
<div class="sidebar-section sidebar-dashboard">
|
||||
<div class="title">Dashboard</div>
|
||||
<div class="body">
|
||||
<ul class="no-bullets dashboard-list pl-0">
|
||||
<li class="dashboard-item">
|
||||
<a class="dashboard-link" href="/"><i class="fas fa-home-alt fa-width-rem"></i>Home</a>
|
||||
</li>
|
||||
<li class="dashboard-item">
|
||||
<a class="dashboard-link" href="/guilds"><i class="fas fa-chess-rook fa-width-rem"></i>Guilds</a>
|
||||
</li>
|
||||
<li class="dashboard-item">
|
||||
<a class="dashboard-link active" href="/subscriptions"><i class="fas fa-heart fa-width-rem"></i>Subscriptions</a>
|
||||
</li>
|
||||
<li class="dashboard-item">
|
||||
<a class="dashboard-link" href="/browse"><i class="fas fa-binoculars fa-width-rem"></i>Browse</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{% endblock %}
|
||||
|
||||
{% block sidebarblock %}
|
||||
<div class="sidebar-section sidebar-about">
|
||||
<div class="body text-primary text-center">
|
||||
<i class="fad fa-user-friends" style="font-size: 4rem;"></i>
|
||||
</div>
|
||||
<div class="title">User Subscriptions</div>
|
||||
<div class="body">
|
||||
<p>The users you are subscribed to.</p>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
|
@ -1,7 +1,7 @@
|
|||
<!-- Badmin Ban user Modal -->
|
||||
<div class="modal fade" id="guildmasterBanModal" tabindex="-1" role="dialog" aria-labelledby="guildmasterBanModalTitle" aria-hidden="true">
|
||||
<div class="modal-dialog modal-dialog-centered" role="document">
|
||||
<form action="/mod/exile/{{b.base36id}}" method="post">
|
||||
<form action="/admin/exile/{{b.base36id}}" method="post">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<h5 class="modal-title">Ban user from +{{b.name}}</h5>
|
||||
|
|
|
@ -1,14 +0,0 @@
|
|||
<div class="modal fade show" id="gmInvitationModal" tabindex="-1" role="dialog" aria-labelledby="gmInvitationModalTitle" aria-hidden="true">
|
||||
<div class="modal-dialog modal-dialog-centered" role="document">
|
||||
<div class="modal-content">
|
||||
<div class="modal-body text-center">
|
||||
<div class="py-4">
|
||||
<i class="fad fa-crown text-warning" style="font-size: 3.5rem;"></i>
|
||||
</div>
|
||||
<p>You've been invited to be an admin.</p>
|
||||
<a class="btn btn-primary btn-block" href="javascript:void(0)" onclick="post('/mod/accept/{{b.base36id}}', callback=function(){window.location.reload(true)})">Accept Invitation</a>
|
||||
<button type="button" class="btn btn-link text-muted mt-2" data-dismiss="modal">Ignore</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
|
@ -1,89 +0,0 @@
|
|||
{% set board = b if b else p.board %}
|
||||
|
||||
<div class="modal fade" id="guildDetailsModal" tabindex="-1" role="dialog" aria-labelledby="guildDetailsModalLabel" aria-hidden="true">
|
||||
<div class="modal-dialog modal-dialog-centered" role="document">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header position-relative border-0" style="background-image: url({{board.banner_url}}); height: 100px; overflow: hidden; object-fit: cover; background-size: cover;">
|
||||
<div class="white-overlay position-absolute w-100 h-100" style="left: 0; top: 0; background-color: rgba(255, 255, 255, 0); background-image: linear-gradient(180deg, #cfcfcf00 25%, #cfcfcf 100%);"></div>
|
||||
<div style="z-index: 1" class="d-flex align-items-center my-auto">
|
||||
<img src="{{board.profile_url}}" class="profile-pic-65 bg-white mr-3"><h5 class="modal-title h4">+{{board.name}}
|
||||
{% if board.over_18 %}
|
||||
<span class="badge badge-danger text-small ml-2" data-toggle="tooltip" data-placement="bottom" title="This guild contains adult content">+18</span>
|
||||
{% endif %}
|
||||
</h5>
|
||||
</div>
|
||||
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
|
||||
<span aria-hidden="true"><i class="far fa-times"></i></span>
|
||||
</button>
|
||||
</div>
|
||||
<div class="modal-body p-0">
|
||||
<div class="d-flex justify-content-between align-items-center border-bottom p-3">
|
||||
|
||||
<div class="">
|
||||
<div class="font-weight-bold text-small text-uppercase text-muted mb-1" style="letter-spacing: 0.025rem;">Founded</div>
|
||||
<div data-toggle="tooltip" data-placement="bottom" title="{{board.created_date}}">{{board.age_string}}</div>
|
||||
</div>
|
||||
|
||||
<div class="">
|
||||
<div class="font-weight-bold text-small text-uppercase text-muted mb-1" style="letter-spacing: 0.025rem;">Badmins</div>
|
||||
<div>{{board.mods_count}}</div>
|
||||
</div>
|
||||
|
||||
<div class="">
|
||||
<div class="font-weight-bold text-small text-uppercase text-muted mb-1" style="letter-spacing: 0.025rem;">Members</div>
|
||||
<div>{{board.subscriber_count}}</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<div class="p-3">
|
||||
|
||||
<div class="h6">About</div>
|
||||
|
||||
{{board.description_html | safe}}
|
||||
|
||||
</div>
|
||||
|
||||
<!-- hide rules thingy
|
||||
<div class="p-3">
|
||||
|
||||
<div class="h6 text-danger">Guild rules</div>
|
||||
|
||||
<ol class="pl-0 mb-0">
|
||||
<li>
|
||||
<span class="h6">Comply with US law</span>
|
||||
<p style="padding: 0 0 0 22px;">Do not post copyrighted material that you are not authorized to distribute. Do not post anything not legal to publish within, or export from, the United States of America.
|
||||
</p>
|
||||
</li>
|
||||
<li>
|
||||
<span class="text-black font-weight-bold">Do not harass other users</span>
|
||||
<p style="padding: 0 0 0 22px;">
|
||||
Do not harass or threaten others on Drama. You are not allowed to share or publish personal information, either yours or another person.
|
||||
</p>
|
||||
</li>
|
||||
<li>
|
||||
<span class="text-black font-weight-bold">No inciting violence</span>
|
||||
<p style="padding: 0 0 0 22px;">
|
||||
No incitement, planning or execution of unlawful or violent activity. This does not include the exercise of human rights that may be considered unlawful in a user's home country but protected in the United States.
|
||||
</p>
|
||||
</li>
|
||||
<li>
|
||||
<span class="text-black font-weight-bold">Check for duplicates</span>
|
||||
<p style="padding: 0 0 0 22px;">
|
||||
Nobody likes reposts. Please make sure the content you're posting hasn't been posted on Drama before.
|
||||
</p>
|
||||
</li>
|
||||
</ol>
|
||||
|
||||
</div>
|
||||
|
||||
-->
|
||||
|
||||
</div>
|
||||
|
||||
<div class="modal-footer" style="background-color: transparent; background-image: linear-gradient(180deg, #cfcfcf00 25%, #cfcfcf 100%);">
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
|
@ -18,7 +18,7 @@
|
|||
<a class="mobile-nav-icon d-block d-md-none" href="/admin"><i class="fas fa-crown align-middle text-gray-500"></i></a>
|
||||
{% endif %}
|
||||
{% if v %}
|
||||
<a class="mobile-nav-icon d-block d-md-none" href="/submit{{'?guild='+b.name if b else ''}}"><i class="fas fa-feather-alt align-middle text-gray-500"></i></a>
|
||||
<a class="mobile-nav-icon d-block d-md-none" href="/submit"><i class="fas fa-feather-alt align-middle text-gray-500"></i></a>
|
||||
{% else %}
|
||||
<a class="mobile-nav-icon d-block d-md-none" href="/login"><i class="fas fa-feather-alt align-middle text-gray-500"></i></a>
|
||||
{% endif %}
|
||||
|
|
|
@ -4,8 +4,6 @@
|
|||
<title>{{title}}</title>
|
||||
{% endblock %}
|
||||
|
||||
{% block sidebar %}{% endblock %}
|
||||
|
||||
{% block pagetype %}message{% endblock %}
|
||||
|
||||
{% block customPadding %}{% endblock %}
|
||||
|
|
|
@ -2,15 +2,4 @@
|
|||
|
||||
{% block maincontent %}
|
||||
{% include "user_listing.html" %}
|
||||
{% endblock %}
|
||||
|
||||
{% block sidebarblock %}
|
||||
<div class="sidebar-section sidebar-about">
|
||||
<div class="title">Your Followed Users</div>
|
||||
<div class="body">
|
||||
<p>These are the users you follow.</p>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
||||
{% block sidebar %}{% endblock %}
|
||||
{% endblock %}
|
|
@ -1,4 +1,4 @@
|
|||
{% extends "guild_settings.html" %}
|
||||
{% extends "settings2.html" %}
|
||||
|
||||
{% block pagetitle %}Moderation Log{% endblock %}
|
||||
|
||||
|
@ -39,7 +39,7 @@
|
|||
</span>
|
||||
<div class="text-muted pl-3">
|
||||
<div>
|
||||
{% if not ma.user.is_deleted %}
|
||||
{% if not ma.user.deleted_utc > 0 %}
|
||||
<a href="{{ma.user.permalink}}" class="font-weight-bold text-black" target="_self">@{{ma.user.username}}</a>
|
||||
{% else %}
|
||||
[deleted user]
|
||||
|
|
|
@ -1,338 +0,0 @@
|
|||
{% extends "guild_settings.html" %}
|
||||
|
||||
{% block pagetitle %}Badmins{% endblock %}
|
||||
|
||||
{% block scripts %}
|
||||
<script>
|
||||
// Invite user to mod
|
||||
function invite_mod_to_guild(boardid) {
|
||||
|
||||
var inviteForm = document.getElementById("invite-form");
|
||||
|
||||
var inviteError = document.getElementById("toast-error-message");
|
||||
|
||||
var usernameField = document.getElementById("invite-username");
|
||||
|
||||
var isValidUsername = usernameField.checkValidity();
|
||||
|
||||
username = usernameField.value;
|
||||
|
||||
if (isValidUsername) {
|
||||
|
||||
var xhr = new XMLHttpRequest();
|
||||
xhr.open("post", "/mod/invite_mod");
|
||||
xhr.withCredentials=true;
|
||||
f=new FormData();
|
||||
f.append("username", username);
|
||||
f.append("formkey", formkey());
|
||||
xhr.onload=function(){
|
||||
if (xhr.status==204) {
|
||||
window.location.reload(true);
|
||||
}
|
||||
else {
|
||||
$('#toast-invite-error').toast('dispose');
|
||||
$('#toast-invite-error').toast('show');
|
||||
inviteError.textContent = JSON.parse(xhr.response)["error"];
|
||||
}
|
||||
}
|
||||
xhr.send(f)
|
||||
}
|
||||
|
||||
}
|
||||
// Badmin Step Down Function
|
||||
step_downModal = function(mod) {
|
||||
document.getElementById("stepDownButton").onclick = function() {
|
||||
this.innerHTML='<span class="spinner-border spinner-border-sm mr-2" role="status" aria-hidden="true"></span>Stepping down';
|
||||
this.disabled = true;
|
||||
post('/mod/{{b.base36id}}/remove/' + mod,
|
||||
callback = function() {
|
||||
location.reload();
|
||||
}
|
||||
)
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
{% if b.has_invite(v) %}
|
||||
<script>
|
||||
// Badmin Invitation Modal
|
||||
$(window).on('load', function(){
|
||||
$('#gmInvitationModal').modal('show');
|
||||
});
|
||||
</script>
|
||||
{% endif %}
|
||||
|
||||
{% endblock %}
|
||||
|
||||
<!-- tabs container -->
|
||||
|
||||
{% block content %}
|
||||
|
||||
<div class="row justify-content-around">
|
||||
|
||||
<div class="col h-100">
|
||||
|
||||
{% if request.args.get('error') or error %}
|
||||
<div class="alert alert-danger alert-dismissible fade show my-3" role="alert">
|
||||
<i class="fas fa-exclamation-circle my-auto"></i>
|
||||
<span>
|
||||
{{error if error else request.args.get('error')}}
|
||||
</span>
|
||||
<button type="button" class="close" data-dismiss="alert" aria-label="Close">
|
||||
<span aria-hidden="true"><i class="far fa-times"></i></span>
|
||||
</button>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
{% if request.args.get('msg') or msg %}
|
||||
<div class="alert alert-success alert-dismissible fade show my-3" role="alert">
|
||||
<i class="fas fa-check-circle my-auto" aria-hidden="true"></i>
|
||||
<span>
|
||||
{{msg if msg else request.args.get('msg')}}
|
||||
</span>
|
||||
<button type="button" class="close" data-dismiss="alert" aria-label="Close">
|
||||
<span aria-hidden="true"><i class="far fa-times"></i></span>
|
||||
</button>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
<div class="row">
|
||||
|
||||
<div class="col" style="padding:0">
|
||||
|
||||
<div class="settings">
|
||||
|
||||
<div class="d-md-flex justify-content-between mb-3">
|
||||
|
||||
<div>
|
||||
<h1>Badmins</h1>
|
||||
</div>
|
||||
|
||||
<div class="mt-auto">
|
||||
{% if me %}
|
||||
<a href="javascript:void(0)" class="btn btn-outline-primary mr-2" data-toggle="modal" data-target="#stepDownModal" onclick="step_downModal('{{v.username}}')">Resign</a>
|
||||
{% endif %}
|
||||
{% if me and me.perm_full %}
|
||||
<a href="javascript:void(0)" class="btn btn-primary" data-toggle="modal" data-target="#badminInviteModal"><i class="fas fa-plus mr-2"></i>Add badmin</a>
|
||||
{% endif %}
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="card mb-5">
|
||||
<table class="table table-hover rounded mb-0">
|
||||
<thead class="thead-dark">
|
||||
<tr>
|
||||
<th scope="col">User</th>
|
||||
<th scope="col">Badmin Since</th>
|
||||
<th scope="col"></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody class="text-muted">
|
||||
|
||||
{% for mod in b.mods_list %}
|
||||
<tr style="font-size:12.5px">
|
||||
<td>
|
||||
<a href="{{mod.user.permalink}}">
|
||||
<img src="{{mod.user.profile_url}}" class="profile-pic-20 align-top mr-2">@{{mod.user.username}}</a>
|
||||
</td>
|
||||
<td>{{mod.created_date}}</td>
|
||||
|
||||
<td>
|
||||
{% if me and me.id < mod.id %}
|
||||
<div class="dropdown float-right dropdown-actions">
|
||||
<a href="#" role="button" id="dropdownMoreLink" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false" style="line-height: 0;">
|
||||
<i class="fas fa-ellipsis-h text-muted"></i>
|
||||
</a>
|
||||
<div class="dropdown-menu border-0 shadow dropdown-menu-right mt-2" aria-labelledby="dropdownMoreLink" x-placement="bottom-end" style="position: absolute; will-change: transform; top: 0px; left: 0px; transform: translate3d(21px, 18px, 0px);">
|
||||
<a class="dropdown-item" href="javascript:void(0)" onclick="post('/mod/{{b.base36id}}/remove/{{mod.user.username}}', callback=function(){window.location.reload(true)})"><i class="fas fa-trash-alt"></i>Remove badmin</a>
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
{% else %}
|
||||
<td>There are no badmins.</td>
|
||||
{% endfor %}
|
||||
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
<h2 class="h5" name="guild_name">Pending</h2>
|
||||
|
||||
<p class="text-small text-muted">These users have been invited to be badmins.</p>
|
||||
|
||||
<div class="card mb-5">
|
||||
<table class="table table-hover rounded mb-0">
|
||||
<thead class="thead-dark">
|
||||
<tr>
|
||||
<th scope="col">User</th>
|
||||
<th scope="col">Invited On</th>
|
||||
<th scope="col"></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody class="text-muted">
|
||||
|
||||
{% for m in b.mod_invites %}
|
||||
<tr>
|
||||
<td>
|
||||
<a href="{{m.user.permalink}}">
|
||||
<img src="{{m.user.profile_url}}" class="profile-pic-20 align-top mr-2">@{{m.user.username}}</a>
|
||||
</td>
|
||||
<td>{{m.created_date}}</td>
|
||||
<td>
|
||||
<div class="dropdown float-right dropdown-actions">
|
||||
<a href="#" role="button" id="dropdownMoreLink" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false" style="line-height: 0;">
|
||||
<i class="fas fa-ellipsis-h text-muted"></i>
|
||||
</a>
|
||||
<div class="dropdown-menu border-0 shadow dropdown-menu-right mt-2" aria-labelledby="dropdownMoreLink" x-placement="bottom-end" style="position: absolute; will-change: transform; top: 0px; left: 0px; transform: translate3d(21px, 18px, 0px);">
|
||||
<a class="dropdown-item text-danger" href="javascript:void(0)" onclick="post('/mod/{{b.base36id}}/rescind/{{m.user.username}}', callback=function(){window.location.reload(true)})"><i class="fas fa-times text-danger fa-fw"></i>Cancel invite</a>
|
||||
</div>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
{% else %}
|
||||
<td>There are no badmin invitations.</td>
|
||||
{% endfor %}
|
||||
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<!-- Badmin Invite User Modal -->
|
||||
<div class="modal fade" id="badminInviteModal" tabindex="-1" role="dialog" aria-labelledby="badminInviteModalTitle" aria-hidden="true">
|
||||
<div class="modal-dialog modal-dialog-centered" role="document">
|
||||
<form action="/mod/invite_mod" id="invite-form" method="post" onsubmit="return false;">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<h5 class="modal-title">Invite user to be badmin</h5>
|
||||
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
|
||||
<span aria-hidden="true"><i class="far fa-times"></i></span>
|
||||
</button>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<p style="padding-left:15px"> Users invited will need to accept their invite. They will receive a notification shortly after you invite them.</p>
|
||||
<input type="hidden" name="formkey" value="{{v.formkey}}">
|
||||
<input type="text" name="username" placeholder="enter username" id="invite-username" class="form-control" maxlength=25 required>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-link text-muted" data-dismiss="modal">Cancel</button>
|
||||
<button type="button" class="btn btn-primary" id="inviteUserButton" onclick="invite_mod_to_guild('{{b.base36id}}')">Invite user</button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Badmin Step Down Modal -->
|
||||
<div class="modal fade" id="stepDownModal" tabindex="-1" role="dialog" aria-labelledby="stepDownModalTitle" aria-hidden="true">
|
||||
<div class="modal-dialog modal-dialog-centered" role="document">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<h5 class="modal-title">Step down as badmin</h5>
|
||||
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
|
||||
<span aria-hidden="true"><i class="far fa-times"></i></span>
|
||||
</button>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<p>If you step down as badmin, you will lose full permissions to moderate this guild. This action cannot be undone.</p>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-link text-muted" data-dismiss="modal">Cancel</button>
|
||||
<button class="btn btn-danger" onclick="post('/mod/{{b.base36id}}/step_down', callback=function(){window.location.reload(true)})">Step down</button>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Badmin Perms Edit Modal -->
|
||||
<div class="modal fade" id="editPermsModal" tabindex="-1" role="dialog" aria-labelledby="stepDownModalTitle" aria-hidden="true">
|
||||
<div class="modal-dialog modal-dialog-centered" role="document">
|
||||
<div class="modal-content">
|
||||
<form action="/+{{b.name}}/mod/edit_perms" method="post">
|
||||
<div class="modal-header">
|
||||
<h5 class="modal-title">Edit badmin permissions on @<span id="permedit-user"></span></h5>
|
||||
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
|
||||
<span aria-hidden="true"><i class="far fa-times"></i></span>
|
||||
</button>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<input name="formkey" type="hidden" value="{{v.formkey}}">
|
||||
<input id="edit-perm-username" name="username" type="hidden" value="">
|
||||
|
||||
<div class="form-group">
|
||||
<label class="custom-control custom-checkbox" for="check-perm-full">
|
||||
<input type="checkbox" id="check-perm-full" class="custom-control-input perm-box" onchange="permfull()" data-perm="full" name="perm_full" value="full">
|
||||
<span class="custom-control-label">full</span>
|
||||
</label>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="custom-control custom-checkbox" for="check-perm-access">
|
||||
<input type="checkbox" id="check-perm-access" class="custom-control-input perm-box" onchange="permother()" data-perm="access" name="perm_access" value="access">
|
||||
<span class="custom-control-label">access</span>
|
||||
</label>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="custom-control custom-checkbox" for="check-perm-appearance">
|
||||
<input type="checkbox" id="check-perm-appearance" class="custom-control-input perm-box" onchange="permother()" data-perm="appearance" name="perm_appearance" value="appearance">
|
||||
<span class="custom-control-label">appearance</span>
|
||||
</label>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="custom-control custom-checkbox" for="check-perm-config">
|
||||
<input type="checkbox" id="check-perm-config" class="custom-control-input perm-box" onchange="permother()" data-perm="config" name="perm_config" value="config">
|
||||
<span class="custom-control-label">config</span>
|
||||
</label>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="custom-control custom-checkbox" for="check-perm-content">
|
||||
<input type="checkbox" id="check-perm-content" class="custom-control-input perm-box" onchange="permother()" data-perm="content" name="perm_content" value="content">
|
||||
<span class="custom-control-label">content</span>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-link text-muted" data-dismiss="modal">Cancel</button>
|
||||
<input type="submit" class="btn btn-danger" value="Save Changes">
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{% endblock %}
|
||||
|
||||
{% block errorToasts %}
|
||||
|
||||
<div class="toast error" id="toast-invite-error" role="alert" aria-live="assertive" aria-atomic="true" data-animation="true" data-autohide="true" data-delay="5000">
|
||||
<div class="toast-body text-center">
|
||||
<i class="fas fa-exclamation-circle text-danger mr-2"></i><span id="toast-error-message">Error. Please try again.</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{% endblock %}
|
||||
|
||||
{% block invitationModal %}
|
||||
{% if b.has_invite(v) %}
|
||||
{% include "gm_invitation_modal.html" %}
|
||||
{% endif %}
|
||||
{% endblock %}
|
|
@ -34,7 +34,7 @@ Send your user to `https://rdrama.net/oauth/authorize`, with the following URL p
|
|||
* `client_id` - Your application's Client ID
|
||||
* `redirect_uri` - The redirect URI (or one of the URIs) specified in your application information. Must not use HTTP unless using localhost (use HTTPS instead).
|
||||
* `state` - This is your own anti-cross-site-forgery token. We don't do anything with this, except give it to the user to pass back to you later. You are responsible for generating and validating the state token.
|
||||
* `scope` - A comma-separated list of permission scopes that you are requesting. Valid scopes are: `identity`, `create`, `read`, `update`, `delete`, `vote`, and `guildmaster`.
|
||||
* `scope` - A comma-separated list of permission scopes that you are requesting. Valid scopes are: `identity`, `create`, `read`, `update`, `delete` and `vote`.
|
||||
* `permanent` - optional. Set to `true` if you are requesting indefinite access. Omit if not.
|
||||
|
||||
If done correctly, the user will see that your application wants to access their Drama account, and be prompted to approve or deny the request.
|
||||
|
|
|
@ -9,7 +9,6 @@
|
|||
{% block listinglength %}{{users | length}}{% endblock %}
|
||||
|
||||
{% block pagenav %}
|
||||
{% if boards %}
|
||||
<nav aria-label="Page navigation">
|
||||
<ul class="pagination pagination-sm mb-0">
|
||||
<li class="page-item{% if page==1 %} disabled{% endif %}">
|
||||
|
@ -22,5 +21,4 @@
|
|||
</li>
|
||||
</ul>
|
||||
</nav>
|
||||
{% endif %}
|
||||
{% endblock %}
|
||||
|
|
|
@ -20,7 +20,7 @@
|
|||
{% endif %}
|
||||
|
||||
|
||||
<div id="post-{{p.base36id}}" class="card{% if p.is_banned %} banned{% endif %}{% if p.deleted_utc > 0 %} deleted{% endif %}{% if p.stickied %} stickied{% endif %}{% if voted==1 %} upvoted{% elif voted==-1 %} downvoted{% endif %}{% if p.over_18 %} nsfw{% endif %}{% if p.is_nsfl %} nsfl {% endif %}">
|
||||
<div id="post-{{p.base36id}}" class="card{% if p.is_banned %} banned{% endif %}{% if p.deleted_utc > 0 %} deleted{% endif %}{% if p.stickied %} stickied{% endif %}{% if voted==1 %} upvoted{% elif voted==-1 %} downvoted{% endif %}{% if p.over_18 %} nsfw{% endif %}">
|
||||
|
||||
<div class="d-flex flex-row-reverse flex-md-row flex-nowrap justify-content-end">
|
||||
|
||||
|
@ -137,7 +137,7 @@
|
|||
{% if p.private %}<span class="badge border-warning border-1 text-small-extra">unlisted</span>{% endif %}
|
||||
{% if p.is_repost %} <span class="badge border-warning border-1 text-small-extra"><a class="text-warning" href="{{p.reposts.permalink}}">repost</a></span>{% endif %}
|
||||
{% if p.active_flags %}<a class="btn btn-primary" href="javascript:void(0)" style="padding:1px 5px; font-size:10px;" onclick="document.getElementById('flaggers-{{p.id}}').classList.toggle('d-none')">{{p.active_flags}} Reports</a>{% endif %}
|
||||
{% if p.author.is_deleted %}[deleted account]{% else %} <a {% if p.author.animatedname %}class="{% if p.author.patron %}patron{% else %}leaderboard{% endif %}"{% endif %} href="{{p.author.permalink}}" style="color: #{{p.author.namecolor}}; font-weight: bold;" class="user-name"><img src="{{ p.author.profile_url }}" class="profile-pic-25 mr-2"/>{{p.author.username}}</a>{% if p.author.customtitle %}<bdi style="color: #{{p.author.titlecolor}}"> {{p.author.customtitle | safe}}</bdi>{% endif %}{% endif %}
|
||||
{% if p.author.deleted_utc > 0 %}[deleted account]{% else %} <a {% if p.author.animatedname %}class="{% if p.author.patron %}patron{% else %}leaderboard{% endif %}"{% endif %} href="{{p.author.permalink}}" style="color: #{{p.author.namecolor}}; font-weight: bold;" class="user-name"><img src="{{ p.author.profile_url }}" class="profile-pic-25 mr-2"/>{{p.author.username}}</a>{% if p.author.customtitle %}<bdi style="color: #{{p.author.titlecolor}}"> {{p.author.customtitle | safe}}</bdi>{% endif %}{% endif %}
|
||||
<span data-toggle="tooltip" data-placement="bottom" id="timestamp-{{p.id}}" title=""> {{p.age_string}}</span>
|
||||
|
||||
({% if p.realurl(v) %}<a href="/search/posts/?q=domain%3A{{p.domain}}&sort=new&t=all" target="_blank">{{p.domain}}</a>{% else %}text post{% endif %})
|
||||
|
@ -191,12 +191,12 @@
|
|||
{% endif %}
|
||||
|
||||
{% if not (v and v.id==p.author_id) %}
|
||||
<li class="list-inline-item"><a href="javascript:void(0)" data-toggle="modal" data-dismiss="modal" data-target="#reportPostModal" onclick="report_postModal('{{p.base36id}}', '{{p.author.username}}','{{p.board.name}}')"><i class="fas fa-flag"></i>Report</a></li>
|
||||
<li class="list-inline-item"><a href="javascript:void(0)" data-toggle="modal" data-dismiss="modal" data-target="#reportPostModal" onclick="report_postModal('{{p.base36id}}', '{{p.author.username}}')"><i class="fas fa-flag"></i>Report</a></li>
|
||||
{% endif %}
|
||||
|
||||
{% if v and v.id==p.author_id %}
|
||||
<li class="list-inline-item"><a href="javascript:void(0)" onclick="post('/api/pin/{{p.base36id}}', function(){window.location.reload(true);})"><i class="fas fa-thumbtack"></i>{% if p.is_pinned %}Unpin from your profile{% else %}Pin to your profile{% endif %}</a></li>
|
||||
{% if p.is_deleted %}
|
||||
{% if p.deleted_utc > 0 %}
|
||||
<li class="list-inline-item"><a href="javascript:void(0)" onclick="post('/undelete_post/{{p.base36id}}', function(){window.location.reload(true);})"><i class="fas fa-trash-alt"></i>Undelete</a></li>
|
||||
{% else %}
|
||||
<li class="list-inline-item"><a href="javascript:void(0)" data-toggle="modal" data-dismiss="modal" data-target="#deletePostModal" onclick="delete_postModal('{{p.base36id}}')"><i class="fas fa-trash-alt"></i>Delete</a></li>
|
||||
|
@ -375,11 +375,11 @@
|
|||
{% endif %}
|
||||
|
||||
{% if not (v and v.id==p.author_id) %}
|
||||
<button class="btn btn-link btn-block btn-lg text-left text-muted" data-toggle="modal" data-dismiss="modal" data-target="#reportPostModal" onclick="report_postModal('{{p.base36id}}','{{'@'+p.author.username if not p.author.is_deleted else '[deleted account]'}}','{{p.board.name}}')" class="d-block"><i class="far fa-flag text-center text-muted mr-3"></i>Report</button>
|
||||
<button class="btn btn-link btn-block btn-lg text-left text-muted" data-toggle="modal" data-dismiss="modal" data-target="#reportPostModal" onclick="report_postModal('{{p.base36id}}','{{'@'+p.author.username if not p.author.deleted_utc > 0 else '[deleted account]'}}')" class="d-block"><i class="far fa-flag text-center text-muted mr-3"></i>Report</button>
|
||||
{% endif %}
|
||||
{% if v and v.id==p.author_id %}
|
||||
<button class="btn btn-link btn-block btn-lg text-info text-left" id="pin-post-{{p.base36id}}" href="javascript:void(0)" onclick="post('/api/pin/{{p.base36id}}',callback=function(){window.location.reload(true);})"><i class="fas fa-thumbtack text-center text-muted mr-3"></i>{% if p.is_pinned %}Unpin from your profile{% else %}Pin to your profile{% endif %}</button>
|
||||
{% if p.is_deleted %}
|
||||
{% if p.deleted_utc > 0 %}
|
||||
<button class="btn btn-link btn-block btn-lg text-left text-muted" href="javascript:void(0)" onclick="post('/undelete_post/{{p.base36id}}', function(){window.location.reload(true);})"><i class="far fa-trash-alt text-center text-muted mr-3"></i>Undelete</button>
|
||||
{% else %}
|
||||
<button class="btn btn-link btn-block btn-lg text-left text-muted" data-toggle="modal" data-dismiss="modal" data-target="#deletePostModal" onclick="delete_postModal('{{p.base36id}}')"><i class="far fa-trash-alt text-center text-muted mr-3"></i>Delete</button>
|
||||
|
@ -387,9 +387,7 @@
|
|||
{% endif %}
|
||||
|
||||
{% if v and (v.id==p.author_id or v.admin_level>=3) %}
|
||||
{% if not p.board.over_18 %}
|
||||
<button class="btn btn-link btn-block btn-lg text-left text-muted" onclick="post('/api/toggle_post_nsfw/{{p.base36id}}', function(){window.location.reload(true);})"><i class="far fa-eye-evil text-center text-muted mr-3"></i>Toggle +18</button>
|
||||
{% endif %}
|
||||
|
||||
{% endif %}
|
||||
{% if v %}
|
||||
|
@ -443,7 +441,7 @@
|
|||
|
||||
{% else %}
|
||||
|
||||
{% if request.path.endswith('/mod/queue') %}
|
||||
{% if request.path.endswith('/admin/queue') %}
|
||||
|
||||
<div class="row no-gutters">
|
||||
<div class="col">
|
||||
|
@ -460,7 +458,7 @@
|
|||
<div class="text-center py-7">
|
||||
<div class="h4 p-2">+{{b.name}} is barren and needs posts!</div>
|
||||
{% if v and b and b.can_submit(v) %}
|
||||
<div class="p-2"><a href="/submit?guild={{b.name}}" class="btn btn-primary">Be the first to post</a></div>
|
||||
<div class="p-2"><a href="/submit" class="btn btn-primary">Be the first to post</a></div>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -166,21 +166,14 @@
|
|||
|
||||
if (nothingFocused) {
|
||||
|
||||
if (document.getElementById('guild-name-reference')) {
|
||||
var guild = document.getElementById('guild-name-reference').innerText;
|
||||
}
|
||||
|
||||
var clipText = event.clipboardData.getData('Text');
|
||||
|
||||
var url = new RegExp('^(?:[a-z]+:)?//', 'i');
|
||||
|
||||
if (url.test(clipText) && window.location.pathname !== '/submit' && guild == undefined) {
|
||||
if (url.test(clipText) && window.location.pathname !== '/submit') {
|
||||
window.location.href = '/submit?url=' + clipText;
|
||||
}
|
||||
else if (url.test(clipText) && window.location.pathname !== '/submit' && guild !== undefined) {
|
||||
window.location.href = '/submit?url=' + clipText + '&guild=' + guild;
|
||||
}
|
||||
else if (url.test(clipText) && window.location.pathname == '/submit' && guild == undefined) {
|
||||
else if (url.test(clipText) && window.location.pathname == '/submit') {
|
||||
|
||||
document.getElementById("post-URL").value = clipText;
|
||||
|
||||
|
|
|
@ -31,9 +31,6 @@
|
|||
<meta name="description" content="Username reserved for: {{u.reserved}}">
|
||||
{% endblock %}
|
||||
|
||||
{% block sidebar %}
|
||||
{% endblock %}
|
||||
|
||||
{% block adminpanel %}{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
|
|
1491
schema.sql
1491
schema.sql
File diff suppressed because it is too large
Load diff
2156
snappy.txt
2156
snappy.txt
File diff suppressed because one or more lines are too long
Loading…
Add table
Add a link
Reference in a new issue