Merge branch 'master' into docs
commit
2e1d2cb774
|
@ -3528,6 +3528,11 @@ small, .small {
|
|||
.post-meta::-webkit-scrollbar {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.ghost-post .post-meta {
|
||||
height: 30px;
|
||||
}
|
||||
|
||||
.sub-flair {
|
||||
padding: 3px 5px 2px 5px;
|
||||
border-radius: 5px;
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -873,6 +873,24 @@ class User(Base):
|
|||
def userblocks(self):
|
||||
return [x[0] for x in g.db.query(UserBlock.target_id).filter_by(user_id=self.id).all()]
|
||||
|
||||
def get_relationship_count(self, relationship_cls):
|
||||
# TODO: deduplicate (see routes/users.py)
|
||||
if relationship_cls in [SaveRelationship, Subscription]:
|
||||
query = relationship_cls.submission_id
|
||||
join = relationship_cls.post
|
||||
cls = Submission
|
||||
elif relationship_cls is CommentSaveRelationship:
|
||||
query = relationship_cls.comment_id
|
||||
join = relationship_cls.comment
|
||||
cls = Comment
|
||||
else:
|
||||
raise TypeError("Relationships supported is SaveRelationship, Subscription, CommentSaveRelationship")
|
||||
|
||||
query = g.db.query(query).join(join).filter(relationship_cls.user_id == self.id)
|
||||
if not self.admin_level >= PERMS['POST_COMMENT_MODERATION']:
|
||||
query = query.filter(cls.is_banned == False, cls.deleted_utc == 0)
|
||||
return query.count()
|
||||
|
||||
@property
|
||||
@lazy
|
||||
def saved_idlist(self):
|
||||
|
@ -895,17 +913,17 @@ class User(Base):
|
|||
@property
|
||||
@lazy
|
||||
def saved_count(self):
|
||||
return g.db.query(SaveRelationship).filter_by(user_id=self.id).count()
|
||||
return self.get_relationship_count(SaveRelationship)
|
||||
|
||||
@property
|
||||
@lazy
|
||||
def saved_comment_count(self):
|
||||
return g.db.query(CommentSaveRelationship).filter_by(user_id=self.id).count()
|
||||
return self.get_relationship_count(CommentSaveRelationship)
|
||||
|
||||
@property
|
||||
@lazy
|
||||
def subscribed_count(self):
|
||||
return g.db.query(Subscription).filter_by(user_id=self.id).count()
|
||||
return self.get_relationship_count(Subscription)
|
||||
|
||||
@property
|
||||
@lazy
|
||||
|
|
|
@ -145,6 +145,7 @@ if SITE_NAME == 'rDrama':
|
|||
"kys ": "keep yourself safe ",
|
||||
"republican": 'republiKKKan',
|
||||
"america": 'ameriKKKa',
|
||||
"it's almost as if": "I'm a retard but",
|
||||
}
|
||||
SLURS.update(RDRAMA_SLURS)
|
||||
|
||||
|
@ -153,7 +154,6 @@ PROFANITIES = {
|
|||
'fuck': 'frick',
|
||||
' ass ': ' butt ',
|
||||
'shitting': 'pooping',
|
||||
'lmao': 'lmbo',
|
||||
'damn': 'darn',
|
||||
'bastard': 'fatherless child',
|
||||
'bitch': 'b-word',
|
||||
|
@ -436,6 +436,7 @@ MODMAIL_ID = 2
|
|||
|
||||
POLL_THREAD = 0
|
||||
POLL_BET_COINS = 200
|
||||
POLL_MAX_OPTIONS = 10
|
||||
WELCOME_MSG = f"Welcome to {SITE_NAME}!"
|
||||
|
||||
LOTTERY_TICKET_COST = 12
|
||||
|
@ -1398,6 +1399,7 @@ NOTIFIED_USERS = {
|
|||
'snakes': SNAKES_ID,
|
||||
'sneks': SNAKES_ID,
|
||||
'snekky': SNAKES_ID,
|
||||
'snekchad': SNAKES_ID,
|
||||
'jc': JUSTCOOL_ID,
|
||||
'justcool': JUSTCOOL_ID,
|
||||
'geese': GEESE_ID,
|
||||
|
|
|
@ -2,7 +2,7 @@ from typing import Callable, Iterable, List, Optional, Union
|
|||
|
||||
from flask import *
|
||||
from sqlalchemy import and_, any_, or_
|
||||
from sqlalchemy.orm import joinedload, selectinload
|
||||
from sqlalchemy.orm import joinedload, selectinload, Query
|
||||
|
||||
from files.classes import Comment, CommentVote, Hat, Sub, Submission, User, UserBlock, Vote
|
||||
from files.helpers.const import AUTOJANNY_ID
|
||||
|
@ -145,7 +145,7 @@ def get_post(i:Union[str, int], v:Optional[User]=None, graceful=False) -> Option
|
|||
return x
|
||||
|
||||
|
||||
def get_posts(pids:Iterable[int], v:Optional[User]=None, eager:bool=False) -> List[Submission]:
|
||||
def get_posts(pids:Iterable[int], v:Optional[User]=None, eager:bool=False, extra:Optional[Callable[[Query], Query]]=None) -> List[Submission]:
|
||||
if not pids: return []
|
||||
|
||||
if v:
|
||||
|
@ -178,6 +178,8 @@ def get_posts(pids:Iterable[int], v:Optional[User]=None, eager:bool=False) -> Li
|
|||
else:
|
||||
query = g.db.query(Submission).filter(Submission.id.in_(pids))
|
||||
|
||||
if extra: query = extra(query)
|
||||
|
||||
if eager:
|
||||
query = query.options(
|
||||
selectinload(Submission.author).options(
|
||||
|
@ -276,12 +278,14 @@ def add_vote_and_block_props(target:Union[Submission, Comment], v:Optional[User]
|
|||
target = add_block_props(target, v)
|
||||
return add_vote_props(target, v, vote_cls)
|
||||
|
||||
def get_comments(cids:Iterable[int], v:Optional[User]=None) -> List[Comment]:
|
||||
def get_comments(cids:Iterable[int], v:Optional[User]=None, extra:Optional[Callable[[Query], Query]]=None) -> List[Comment]:
|
||||
if not cids: return []
|
||||
if v:
|
||||
output = get_comments_v_properties(v, True, None, Comment.id.in_(cids))[1]
|
||||
output = get_comments_v_properties(v, True, None, Comment.id.in_(cids))[1] # TODO: support 'extra' for get_comments_v_properties
|
||||
else:
|
||||
output = g.db.query(Comment).join(Comment.author).filter(User.shadowbanned == None, Comment.id.in_(cids)).all()
|
||||
output = g.db.query(Comment).join(Comment.author)
|
||||
if extra: output = extra(output)
|
||||
output = output.filter(User.shadowbanned == None, Comment.id.in_(cids)).all()
|
||||
return sorted(output, key=lambda x: cids.index(x.id))
|
||||
|
||||
def get_comments_v_properties(v:User, include_shadowbanned=True, should_keep_func:Optional[Callable[[Comment], bool]]=None, *criterion):
|
||||
|
|
|
@ -133,12 +133,12 @@ def comment(v):
|
|||
abort(403, "You can't reply to users who have blocked you or users that you have blocked.")
|
||||
|
||||
options = []
|
||||
for i in poll_regex.finditer(body):
|
||||
for i in list(poll_regex.finditer(body))[:POLL_MAX_OPTIONS]:
|
||||
options.append(i.group(1))
|
||||
body = body.replace(i.group(0), "")
|
||||
|
||||
choices = []
|
||||
for i in choice_regex.finditer(body):
|
||||
for i in list(choice_regex.finditer(body))[:POLL_MAX_OPTIONS]:
|
||||
choices.append(i.group(1))
|
||||
body = body.replace(i.group(0), "")
|
||||
|
||||
|
@ -391,7 +391,7 @@ def edit_comment(cid, v):
|
|||
elif v.bird and len(body) > 140:
|
||||
abort(403, "You have to type less than 140 characters!")
|
||||
|
||||
for i in poll_regex.finditer(body):
|
||||
for i in list(poll_regex.finditer(body))[:POLL_MAX_OPTIONS]:
|
||||
body = body.replace(i.group(0), "")
|
||||
body_html = filter_emojis_only(i.group(1))
|
||||
if len(body_html) > 500: abort(400, "Poll option too long!")
|
||||
|
@ -402,7 +402,7 @@ def edit_comment(cid, v):
|
|||
)
|
||||
g.db.add(option)
|
||||
|
||||
for i in choice_regex.finditer(body):
|
||||
for i in list(choice_regex.finditer(body))[:POLL_MAX_OPTIONS]:
|
||||
body = body.replace(i.group(0), "")
|
||||
body_html = filter_emojis_only(i.group(1))
|
||||
if len(body_html) > 500: abort(400, "Poll option too long!")
|
||||
|
|
|
@ -151,7 +151,7 @@ def logout(v):
|
|||
@auth_desired
|
||||
def sign_up_get(v):
|
||||
if not get_setting('Signups'):
|
||||
return {"error": "New account registration is currently closed. Please come back later."}, 403
|
||||
abort(403, "New account registration is currently closed. Please come back later.")
|
||||
|
||||
if v: return redirect(SITE_FULL)
|
||||
|
||||
|
@ -201,7 +201,7 @@ def sign_up_get(v):
|
|||
@auth_desired
|
||||
def sign_up_post(v):
|
||||
if not get_setting('Signups'):
|
||||
return {"error": "New account registration is currently closed. Please come back later."}, 403
|
||||
abort(403, "New account registration is currently closed. Please come back later.")
|
||||
|
||||
if v: abort(403)
|
||||
|
||||
|
|
|
@ -360,7 +360,7 @@ def edit_post(pid, v):
|
|||
)
|
||||
g.db.add(bet)
|
||||
|
||||
for i in poll_regex.finditer(body):
|
||||
for i in list(poll_regex.finditer(body))[:10]:
|
||||
body = body.replace(i.group(0), "")
|
||||
body_html = filter_emojis_only(i.group(1))
|
||||
if len(body_html) > 500: abort(400, "Poll option too long!")
|
||||
|
@ -371,7 +371,7 @@ def edit_post(pid, v):
|
|||
)
|
||||
g.db.add(option)
|
||||
|
||||
for i in choice_regex.finditer(body):
|
||||
for i in list(choice_regex.finditer(body))[:10]:
|
||||
body = body.replace(i.group(0), "")
|
||||
body_html = filter_emojis_only(i.group(1))
|
||||
if len(body_html) > 500: abort(400, "Poll option too long!")
|
||||
|
@ -754,12 +754,12 @@ def submit_post(v, sub=None):
|
|||
body = body.replace(i.group(0), "")
|
||||
|
||||
options = []
|
||||
for i in poll_regex.finditer(body):
|
||||
for i in list(poll_regex.finditer(body))[:10]:
|
||||
options.append(i.group(1))
|
||||
body = body.replace(i.group(0), "")
|
||||
|
||||
choices = []
|
||||
for i in choice_regex.finditer(body):
|
||||
for i in list(choice_regex.finditer(body))[:10]:
|
||||
choices.append(i.group(1))
|
||||
body = body.replace(i.group(0), "")
|
||||
|
||||
|
@ -1075,6 +1075,7 @@ extensions = IMAGE_FORMATS + VIDEO_FORMATS + AUDIO_FORMATS
|
|||
@ratelimit_user("3/minute")
|
||||
@auth_required
|
||||
def get_post_title(v):
|
||||
POST_TITLE_TIMEOUT = 5
|
||||
url = request.values.get("url")
|
||||
if not url or '\\' in url: abort(400)
|
||||
url = url.strip()
|
||||
|
@ -1084,7 +1085,8 @@ def get_post_title(v):
|
|||
if any((checking_url.endswith(f'.{x}') for x in extensions)):
|
||||
abort(400)
|
||||
|
||||
try: x = requests.get(url, headers=titleheaders, timeout=5, proxies=proxies)
|
||||
try:
|
||||
x = gevent.with_timeout(POST_TITLE_TIMEOUT, requests.get, url, headers=titleheaders, timeout=POST_TITLE_TIMEOUT, proxies=proxies)
|
||||
except: abort(400)
|
||||
|
||||
content_type = x.headers.get("Content-Type")
|
||||
|
|
|
@ -235,9 +235,7 @@ def submit_contact(v):
|
|||
execute_blackjack(v, new_comment, new_comment.body_html, 'modmail')
|
||||
new_comment.top_comment_id = new_comment.id
|
||||
|
||||
admins = g.db.query(User).filter(User.admin_level >= PERMS['NOTIFICATIONS_MODMAIL'])
|
||||
if SITE == 'watchpeopledie.tv':
|
||||
admins = admins.filter(User.id != AEVANN_ID)
|
||||
admins = g.db.query(User).filter(User.admin_level >= PERMS['NOTIFICATIONS_MODMAIL'], User.id != AEVANN_ID)
|
||||
|
||||
for admin in admins.all():
|
||||
notif = Notification(comment_id=new_comment.id, user_id=admin.id)
|
||||
|
|
|
@ -550,9 +550,7 @@ def messagereply(v):
|
|||
top_comment = c.top_comment(g.db)
|
||||
|
||||
if top_comment.sentto == MODMAIL_ID:
|
||||
admins = g.db.query(User.id).filter(User.admin_level >= PERMS['NOTIFICATIONS_MODMAIL'], User.id != v.id)
|
||||
if SITE == 'watchpeopledie.tv':
|
||||
admins = admins.filter(User.id != AEVANN_ID)
|
||||
admins = g.db.query(User.id).filter(User.admin_level >= PERMS['NOTIFICATIONS_MODMAIL'], User.id != v.id, User.id != AEVANN_ID)
|
||||
|
||||
admins = [x[0] for x in admins.all()]
|
||||
|
||||
|
@ -937,7 +935,6 @@ def user_profile_name(username):
|
|||
return redirect(x.profile_url)
|
||||
|
||||
def get_saves_and_subscribes(v, template, relationship_cls, page:int, standalone=False):
|
||||
PAGE_SIZE = 25
|
||||
if relationship_cls in [SaveRelationship, Subscription]:
|
||||
query = relationship_cls.submission_id
|
||||
join = relationship_cls.post
|
||||
|
@ -951,12 +948,18 @@ def get_saves_and_subscribes(v, template, relationship_cls, page:int, standalone
|
|||
ids = [x[0] for x in g.db.query(query).join(join).filter(relationship_cls.user_id == v.id).order_by(cls.created_utc.desc()).offset(PAGE_SIZE * (page - 1)).limit(PAGE_SIZE + 1).all()]
|
||||
next_exists = len(ids) > PAGE_SIZE
|
||||
ids = ids[:PAGE_SIZE]
|
||||
|
||||
extra = None
|
||||
if not v.admin_level >= PERMS['POST_COMMENT_MODERATION']:
|
||||
extra = lambda q:q.filter(cls.is_banned == False, cls.deleted_utc == 0)
|
||||
|
||||
if cls is Submission:
|
||||
listing = get_posts(ids, v=v, eager=True)
|
||||
listing = get_posts(ids, v=v, eager=True, extra=extra)
|
||||
elif cls is Comment:
|
||||
listing = get_comments(ids, v=v)
|
||||
listing = get_comments(ids, v=v, extra=extra)
|
||||
else:
|
||||
raise TypeError("Only supports Submissions and Comments. This is probably the result of a bug with *this* function")
|
||||
|
||||
if v.client: return {"data": [x.json(g.db) for x in listing]}
|
||||
return render_template(template, u=v, v=v, listing=listing, page=page, next_exists=next_exists, standalone=standalone)
|
||||
|
||||
|
|
|
@ -18,6 +18,7 @@ def session_init():
|
|||
session["session_id"] = secrets.token_hex(49)
|
||||
|
||||
def calc_users(v):
|
||||
if g.is_api_or_xhr: return
|
||||
loggedin = cache.get(f'{SITE}_loggedin') or {}
|
||||
loggedout = cache.get(f'{SITE}_loggedout') or {}
|
||||
timestamp = int(time.time())
|
||||
|
|
|
@ -78,7 +78,7 @@
|
|||
<div id="post-root" class="col-12">
|
||||
|
||||
<div class="card border-0 mt-3 {% if p.stickied %}stickied{% endif %} {% if voted==1 %}upvoted{% elif voted==-1 %} downvoted{% endif %}">
|
||||
<div id="post-{{p.id}}" class="actual-post {% if p.is_banned %}banned{% endif %} {% if p.deleted_utc %}deleted {% endif %} {% if p.award_count('tilt', v) %}p-3{% endif %} {% if p.award_count('glowie', v) %}glow{% endif %} d-flex flex-row-reverse flex-nowrap justify-content-end">
|
||||
<div id="post-{{p.id}}" class="actual-post {% if p.ghost %}ghost-post{% endif %} {% if p.is_banned %}banned{% endif %} {% if p.deleted_utc %}deleted {% endif %} {% if p.award_count('tilt', v) %}p-3{% endif %} {% if p.award_count('glowie', v) %}glow{% endif %} d-flex flex-row-reverse flex-nowrap justify-content-end">
|
||||
|
||||
{% if not p.is_image and p.thumb_url and not p.embed_url %}
|
||||
<div class="card-header bg-transparent border-0 d-none d-md-flex flex-row flex-nowrap pl-3 p-0">
|
||||
|
|
|
@ -45,7 +45,7 @@
|
|||
</div>
|
||||
{% endif %}
|
||||
|
||||
<div id="post-{{p.id}}" class="actual-post {% if p.unread %}unread{% else %}card{% endif %} {% if p.is_banned %} banned{% endif %}{% if p.deleted_utc %} deleted{% endif %}{% if p.stickied %} stickied{% endif %}{% if voted==1 %} upvoted{% elif voted==-1 %} downvoted{% endif %}{% if p.over_18 %} nsfw{% endif %}">
|
||||
<div id="post-{{p.id}}" class="actual-post {% if p.ghost %}ghost-post{% endif %} {% if p.unread %}unread{% else %}card{% endif %} {% if p.is_banned %} banned{% endif %}{% if p.deleted_utc %} deleted{% endif %}{% if p.stickied %} stickied{% endif %}{% if voted==1 %} upvoted{% elif voted==-1 %} downvoted{% endif %}{% if p.over_18 %} nsfw{% endif %}">
|
||||
|
||||
<div class="d-flex flex-row-reverse flex-md-row flex-nowrap" style="align-items:flex-start">
|
||||
<div class="voting my-2 d-none d-md-flex pr-2">
|
||||
|
|
|
@ -105,7 +105,7 @@
|
|||
</div>
|
||||
<div class="col text-right">
|
||||
{% if error %}<span class="text-danger text-large mr-2">{{error | safe}}</span>{% endif %}
|
||||
<button type="submit" class="btn btn-primary" id="create_button" type="submit" onclick="disable(this)" disabled>Post</button>
|
||||
<button type="submit" class="btn btn-primary" id="create_button" type="submit" onclick="disable(this)">Post</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
52
run_tests.py
52
run_tests.py
|
@ -1,52 +0,0 @@
|
|||
#!/usr/bin/python3
|
||||
|
||||
import subprocess
|
||||
import sys
|
||||
|
||||
# we want to leave the container in whatever state it currently is, so check to see if it's running
|
||||
docker_inspect = subprocess.run([
|
||||
"docker",
|
||||
"container",
|
||||
"inspect",
|
||||
"-f", "{{.State.Status}}",
|
||||
"rDrama",
|
||||
],
|
||||
capture_output = True,
|
||||
).stdout.decode("utf-8").strip()
|
||||
|
||||
was_running = docker_inspect == "running"
|
||||
|
||||
# update containers, just in case they're out of date
|
||||
if was_running:
|
||||
print("Updating containers . . .", flush=True)
|
||||
else:
|
||||
print("Starting containers . . .", flush=True)
|
||||
subprocess.run([
|
||||
"docker-compose",
|
||||
"up",
|
||||
"--build",
|
||||
"-d",
|
||||
],
|
||||
check = True,
|
||||
)
|
||||
|
||||
# run the test
|
||||
print("Running test . . .", flush=True)
|
||||
result = subprocess.run([
|
||||
"docker",
|
||||
"exec",
|
||||
"rDrama",
|
||||
"bash", "-c", "cd service && python3 -m pytest -s"
|
||||
])
|
||||
|
||||
if not was_running:
|
||||
# shut down, if we weren't running in the first place
|
||||
print("Shutting down containers . . .", flush=True)
|
||||
subprocess.run([
|
||||
"docker-compose",
|
||||
"stop",
|
||||
],
|
||||
check = True,
|
||||
)
|
||||
|
||||
sys.exit(result.returncode)
|
|
@ -2993,7 +2993,7 @@ https://media.giphy.com/media/3oz8xLd9DJq2l2VFtu/giphy.webp
|
|||
{[para]}
|
||||
Rape
|
||||
{[para]}
|
||||
Here is the Contributors listing for the github project: https://github.com/Aevann1/rDrama
|
||||
Here is the Contributors listing for the github project: https://fsdfsd.net/rDrama/rDrama/activity
|
||||
|
||||
That list shows CarpathianFlorist as a contributor. CarpathianFlorist is a Racially Motivated Violent Extremist - a White Identity Extremist - who was involved in /r/MillionDollarExtreme and its many hundreds of spinoffs and descendants. I've collected dozens of his Reddit accts.
|
||||
|
||||
|
@ -3173,4 +3173,4 @@ Normies can't understand the thrill of pinning the Weasel. Night spent chasing a
|
|||
{[para]}
|
||||
I am the “office manager” of AHS. I’ve spent the past three years keeping spreadsheets and have inboxes full of ticket closures, and have written reports characterizing the response accuracy of Reddit AEO.
|
||||
|
||||
Would you like to escalate and mansplain my field of expertise to me more?
|
||||
Would you like to escalate and mansplain my field of expertise to me more?
|
||||
|
|
Loading…
Reference in New Issue