2021-09-06 19:58:04 +00:00
import time
2021-07-21 01:12:26 +00:00
from urllib . parse import urlparse
import mistletoe
import urllib . parse
import gevent
2021-09-06 22:22:57 +00:00
import traceback
2021-07-21 01:12:26 +00:00
2021-08-04 15:35:10 +00:00
from files . helpers . wrappers import *
from files . helpers . sanitize import *
from files . helpers . filters import *
from files . helpers . markdown import *
from files . helpers . session import *
from files . helpers . thumbs import *
from files . helpers . alerts import send_notification
from files . helpers . discord import send_message
2021-08-21 11:06:28 +00:00
from files . helpers . const import *
2021-08-04 15:35:10 +00:00
from files . classes import *
2021-07-21 01:12:26 +00:00
from flask import *
from io import BytesIO
2021-08-04 15:35:10 +00:00
from files . __main__ import app , limiter , cache
2021-07-21 01:12:26 +00:00
from PIL import Image as PILimage
2021-08-11 17:01:19 +00:00
from . front import frontlist , changeloglist
2021-07-21 01:12:26 +00:00
2021-09-11 23:40:58 +00:00
2021-08-05 14:41:32 +00:00
site = environ . get ( " DOMAIN " ) . strip ( )
2021-08-02 14:27:20 +00:00
with open ( " snappy.txt " , " r " ) as f : snappyquotes = f . read ( ) . split ( " { [para]} " )
2021-07-21 01:12:26 +00:00
2021-09-11 23:40:58 +00:00
@app.post ( " /toggle_club/<pid> " )
@auth_required
def toggle_club ( pid , v ) :
post = get_post ( pid )
2021-09-13 17:28:37 +00:00
if ( post . author_id != v . id or v . club_banned ) and not v . admin_level > = 3 : abort ( 403 )
2021-09-11 23:40:58 +00:00
post . club = not post . club
g . db . add ( post )
if post . author_id != v . id :
ma = ModAction (
kind = " club " if post . club else " unclub " ,
user_id = v . id ,
target_submission_id = post . id ,
)
g . db . add ( ma )
if post . club : return { " message " : " Post has been marked as +150-coins only! " }
else : return { " message " : " Post has been unmarked as +150-coins only! " }
2021-07-31 04:48:47 +00:00
@app.post ( " /publish/<pid> " )
2021-08-22 20:31:12 +00:00
@auth_required
2021-07-21 01:12:26 +00:00
@validate_formkey
def publish ( pid , v ) :
post = get_post ( pid )
if not post . author_id == v . id : abort ( 403 )
post . private = False
g . db . add ( post )
2021-07-28 11:00:15 +00:00
2021-08-18 00:32:36 +00:00
cache . delete_memoized ( frontlist )
2021-07-30 09:42:17 +00:00
2021-09-08 11:05:31 +00:00
return { " message " : " Post published! " }
2021-07-21 01:12:26 +00:00
2021-07-27 22:31:28 +00:00
@app.get ( " /submit " )
2021-07-21 01:12:26 +00:00
@auth_required
def submit_get ( v ) :
2021-08-23 17:48:55 +00:00
2021-07-25 21:59:20 +00:00
2021-07-21 01:12:26 +00:00
return render_template ( " submit.html " ,
2021-07-25 21:59:20 +00:00
v = v )
2021-07-21 01:12:26 +00:00
2021-07-27 22:31:28 +00:00
@app.get ( " /post/<pid> " )
@app.get ( " /post/<pid>/<anything> " )
2021-08-13 01:38:51 +00:00
@app.get ( " /logged_out/post/<pid> " )
2021-08-13 02:55:52 +00:00
@app.get ( " /logged_out/post/<pid>/<anything> " )
2021-07-21 01:12:26 +00:00
@auth_desired
2021-07-30 05:31:38 +00:00
def post_id ( pid , anything = None , v = None ) :
2021-08-13 01:38:51 +00:00
2021-09-13 17:10:03 +00:00
if not v and not request . path . startswith ( ' /logged_out ' ) and not request . headers . get ( " Authorization " ) : return redirect ( f " /logged_out/post/ { pid } " )
2021-08-13 01:38:51 +00:00
2021-09-13 17:10:03 +00:00
if v and request . full_path . startswith ( ' /logged_out ' ) : v = None
2021-08-13 01:55:23 +00:00
2021-07-21 01:12:26 +00:00
try : pid = int ( pid )
except Exception as e : pass
if v : defaultsortingcomments = v . defaultsortingcomments
else : defaultsortingcomments = " top "
sort = request . args . get ( " sort " , defaultsortingcomments )
2021-07-25 14:23:53 +00:00
2021-07-30 06:04:34 +00:00
try : pid = int ( pid )
2021-07-31 06:59:14 +00:00
except :
try : pid = int ( pid , 36 )
except : abort ( 404 )
2021-07-25 14:23:53 +00:00
post = get_post ( pid , v = v )
2021-09-13 21:43:34 +00:00
if post . club and not ( v and v . paid_dues ) : abort ( 403 )
2021-09-11 23:40:58 +00:00
2021-07-25 14:23:53 +00:00
if v :
votes = g . db . query ( CommentVote ) . filter_by ( user_id = v . id ) . subquery ( )
blocking = v . blocking . subquery ( )
blocked = v . blocked . subquery ( )
2021-08-06 12:44:24 +00:00
comments = g . db . query (
2021-07-25 14:23:53 +00:00
Comment ,
votes . c . vote_type ,
blocking . c . id ,
blocked . c . id ,
)
if v . admin_level > = 4 :
2021-08-06 12:44:24 +00:00
comments = comments . options ( joinedload ( Comment . oauth_app ) )
2021-07-25 14:23:53 +00:00
2021-08-06 12:44:24 +00:00
comments = comments . filter (
2021-07-25 14:23:53 +00:00
Comment . parent_submission == post . id
) . join (
votes ,
votes . c . comment_id == Comment . id ,
isouter = True
) . join (
blocking ,
blocking . c . target_id == Comment . author_id ,
isouter = True
) . join (
blocked ,
blocked . c . user_id == Comment . author_id ,
isouter = True
)
if sort == " top " :
2021-08-06 12:44:24 +00:00
comments = sorted ( comments . all ( ) , key = lambda x : x [ 0 ] . score , reverse = True )
2021-07-25 14:23:53 +00:00
elif sort == " bottom " :
2021-08-06 12:44:24 +00:00
comments = sorted ( comments . all ( ) , key = lambda x : x [ 0 ] . score )
2021-07-25 14:23:53 +00:00
elif sort == " new " :
2021-08-06 12:44:24 +00:00
comments = comments . order_by ( Comment . created_utc . desc ( ) ) . all ( )
2021-07-25 14:23:53 +00:00
elif sort == " old " :
2021-08-06 12:44:24 +00:00
comments = comments . order_by ( Comment . created_utc . asc ( ) ) . all ( )
2021-07-25 14:23:53 +00:00
elif sort == " controversial " :
2021-08-06 12:44:24 +00:00
comments = sorted ( comments . all ( ) , key = lambda x : x [ 0 ] . score_disputed , reverse = True )
2021-07-25 14:23:53 +00:00
elif sort == " random " :
2021-08-06 12:44:24 +00:00
c = comments . all ( )
2021-07-25 14:23:53 +00:00
comments = random . sample ( c , k = len ( c ) )
else :
abort ( 422 )
output = [ ]
for c in comments :
comment = c [ 0 ]
if comment . author and comment . author . shadowbanned and not ( v and v . id == comment . author_id ) : continue
2021-08-07 23:03:15 +00:00
comment . voted = c [ 1 ] or 0
2021-09-09 14:15:27 +00:00
comment . _is_blocking = c [ 2 ] or 0
comment . _is_blocked = c [ 3 ] or 0
2021-07-25 14:23:53 +00:00
output . append ( comment )
2021-08-07 23:01:07 +00:00
post . preloaded_comments = output
2021-07-25 14:23:53 +00:00
else :
2021-08-06 12:44:24 +00:00
comments = g . db . query (
2021-07-25 14:23:53 +00:00
Comment
) . filter (
Comment . parent_submission == post . id
)
if sort == " top " :
2021-08-06 12:44:24 +00:00
comments = sorted ( comments . all ( ) , key = lambda x : x . score , reverse = True )
2021-07-25 14:23:53 +00:00
elif sort == " bottom " :
2021-08-06 12:44:24 +00:00
comments = sorted ( comments . all ( ) , key = lambda x : x . score )
2021-07-25 14:23:53 +00:00
elif sort == " new " :
2021-08-06 12:44:24 +00:00
comments = comments . order_by ( Comment . created_utc . desc ( ) ) . all ( )
2021-07-25 14:23:53 +00:00
elif sort == " old " :
2021-08-06 12:44:24 +00:00
comments = comments . order_by ( Comment . created_utc . asc ( ) ) . all ( )
2021-07-25 14:23:53 +00:00
elif sort == " controversial " :
2021-08-06 12:44:24 +00:00
comments = sorted ( comments . all ( ) , key = lambda x : x . score_disputed , reverse = True )
2021-07-25 14:23:53 +00:00
elif sort == " random " :
2021-08-06 12:44:24 +00:00
c = comments . all ( )
2021-07-25 14:23:53 +00:00
comments = random . sample ( c , k = len ( c ) )
else :
abort ( 422 )
2021-08-28 11:32:52 +00:00
if random . random ( ) < 0.02 :
2021-07-25 14:23:53 +00:00
for comment in comments :
if comment . author and comment . author . shadowbanned :
2021-09-02 19:24:50 +00:00
rand = random . randint ( 5 , 20 )
if comment . score > rand : continue
2021-07-25 14:23:53 +00:00
rand = random . randint ( 500 , 1400 )
vote = CommentVote ( user_id = rand ,
2021-09-02 19:24:50 +00:00
vote_type = random . choice ( [ - 1 , 1 , 1 , 1 , 1 ] ) ,
2021-07-25 14:23:53 +00:00
comment_id = comment . id )
g . db . add ( vote )
try : g . db . flush ( )
except : g . db . rollback ( )
2021-07-26 17:00:29 +00:00
comment . upvotes = g . db . query ( CommentVote ) . filter_by ( comment_id = comment . id , vote_type = 1 ) . count ( )
comment . downvotes = g . db . query ( CommentVote ) . filter_by ( comment_id = comment . id , vote_type = - 1 ) . count ( )
2021-07-25 14:23:53 +00:00
g . db . add ( comment )
2021-08-07 23:01:07 +00:00
post . preloaded_comments = [ x for x in comments if not ( x . author and x . author . shadowbanned ) or ( v and v . id == x . author_id ) ]
2021-07-25 14:23:53 +00:00
2021-09-10 05:22:41 +00:00
if not v or v . highlightcomments :
last_view_utc = session . get ( str ( post . id ) )
if last_view_utc : last_view_utc = int ( last_view_utc )
session [ str ( post . id ) ] = int ( time . time ( ) )
keys = [ ]
for key , val in session . items ( ) :
if type ( val ) is int and key not in [ ' login_nonce ' , ' user_id ' ] :
if time . time ( ) - val > 86400 : keys . append ( key )
for key in keys : session . pop ( key )
2021-09-10 05:09:40 +00:00
2021-07-21 01:12:26 +00:00
post . views + = 1
g . db . add ( post )
2021-07-26 17:53:54 +00:00
if isinstance ( session . get ( ' over_18 ' , 0 ) , dict ) : session [ " over_18 " ] = 0
2021-07-26 17:47:52 +00:00
if post . over_18 and not ( v and v . over_18 ) and not session . get ( ' over_18 ' , 0 ) > = int ( time . time ( ) ) :
2021-07-31 05:28:05 +00:00
if request . headers . get ( " Authorization " ) : return { " error " : " Must be 18+ to view " } , 451
else : return render_template ( " errors/nsfw.html " , v = v )
2021-07-21 01:12:26 +00:00
post . tree_comments ( )
2021-07-31 05:59:25 +00:00
if request . headers . get ( " Authorization " ) : return post . json
2021-09-10 05:29:34 +00:00
else :
if not v or v . highlightcomments : return post . rendered_page ( v = v , last_view_utc = last_view_utc , sort = sort )
else : return post . rendered_page ( v = v , sort = sort )
2021-07-31 05:59:25 +00:00
2021-07-21 01:12:26 +00:00
2021-07-27 22:31:28 +00:00
@app.post ( " /edit_post/<pid> " )
2021-08-22 20:31:12 +00:00
@auth_required
2021-07-21 01:12:26 +00:00
@validate_formkey
def edit_post ( pid , v ) :
p = get_post ( pid )
2021-09-13 11:27:13 +00:00
if not p . author_id == v . id : abort ( 403 )
2021-07-21 01:12:26 +00:00
2021-09-13 11:27:13 +00:00
title = request . form . get ( " title " )
2021-07-21 01:12:26 +00:00
body = request . form . get ( " body " , " " )
2021-09-01 20:43:59 +00:00
2021-09-13 11:27:13 +00:00
if title != p . title :
p . title = title
p . title_html = filter_title ( title )
if body != p . body :
for i in re . finditer ( ' ^(https: \ / \ /.* \ .(png|jpg|jpeg|gif|PNG|JPG|JPEG|GIF|9999)) ' , body , re . MULTILINE ) : body = body . replace ( i . group ( 1 ) , f ' ![]( { i . group ( 1 ) } ) ' )
2021-09-13 11:45:03 +00:00
body_md = CustomRenderer ( ) . render ( mistletoe . Document ( body ) )
2021-09-13 11:27:13 +00:00
body_html = sanitize ( body_md )
# Run safety filter
bans = filter_comment_html ( body_html )
if bans :
ban = bans [ 0 ]
reason = f " Remove the { ban . domain } link from your post and try again. "
if ban . reason :
reason + = f " { ban . reason } "
#auto ban for digitally malicious content
if any ( [ x . reason == 4 for x in bans ] ) :
v . ban ( days = 30 , reason = " Digitally malicious content is not allowed. " )
abort ( 403 )
return { " error " : reason } , 403
# check spam
soup = BeautifulSoup ( body_html , features = " html.parser " )
links = [ x [ ' href ' ] for x in soup . find_all ( ' a ' ) if x . get ( ' href ' ) ]
for link in links :
parse_link = urlparse ( link )
check_url = ParseResult ( scheme = " https " ,
netloc = parse_link . netloc ,
path = parse_link . path ,
params = parse_link . params ,
query = parse_link . query ,
fragment = ' ' )
check_url = urlunparse ( check_url )
badlink = g . db . query ( BadLink ) . filter (
literal ( check_url ) . contains (
BadLink . link ) ) . first ( )
if badlink :
if badlink . autoban :
text = " Your account has been suspended for 1 day for the following reason: \n \n > Too much spam! "
send_notification ( NOTIFICATIONS_ACCOUNT , v , text )
v . ban ( days = 1 , reason = " spam " )
return redirect ( ' /notifications ' )
else :
return { " error " : f " The link ` { badlink . link } ` is not allowed. Reason: { badlink . reason } " }
p . body = body
p . body_html = body_html
if " rdrama " in request . host and " ivermectin " in body_html . lower ( ) :
p . is_banned = True
p . ban_reason = " ToS Violation "
g . db . add ( p )
c_jannied = Comment ( author_id = AUTOJANNY_ACCOUNT ,
parent_submission = p . id ,
level = 1 ,
over_18 = False ,
is_bot = True ,
app_id = None ,
is_pinned = True ,
distinguish_level = 6
)
g . db . add ( c_jannied )
g . db . flush ( )
body = VAXX_MSG . format ( username = v . username )
2021-09-13 11:54:20 +00:00
body_md = CustomRenderer ( ) . render ( mistletoe . Document ( body ) )
2021-09-13 11:27:13 +00:00
body_jannied_html = sanitize ( body_md )
c_aux = CommentAux (
id = c_jannied . id ,
body_html = body_jannied_html ,
body = body
2021-09-01 20:43:59 +00:00
)
2021-09-13 11:27:13 +00:00
g . db . add ( c_aux )
g . db . flush ( )
n = Notification ( comment_id = c_jannied . id , user_id = v . id )
g . db . add ( n )
2021-09-01 20:43:59 +00:00
2021-09-13 11:27:13 +00:00
if v . agendaposter and " trans lives matter " not in body_html . lower ( ) :
2021-09-01 20:43:59 +00:00
2021-09-13 11:27:13 +00:00
p . is_banned = True
p . ban_reason = " ToS Violation "
2021-09-01 20:43:59 +00:00
2021-09-13 11:27:13 +00:00
g . db . add ( p )
2021-09-01 20:43:59 +00:00
2021-09-13 11:27:13 +00:00
c_jannied = Comment ( author_id = AUTOJANNY_ACCOUNT ,
parent_submission = p . id ,
level = 1 ,
over_18 = False ,
is_bot = True ,
app_id = None ,
is_pinned = True ,
distinguish_level = 6
)
2021-09-01 20:43:59 +00:00
2021-09-13 11:27:13 +00:00
g . db . add ( c_jannied )
g . db . flush ( )
2021-07-21 21:36:35 +00:00
2021-09-13 11:27:13 +00:00
body = AGENDAPOSTER_MSG . format ( username = v . username )
2021-07-21 21:36:35 +00:00
2021-09-13 11:54:20 +00:00
body_md = CustomRenderer ( ) . render ( mistletoe . Document ( body ) )
2021-07-21 21:36:35 +00:00
2021-09-13 11:27:13 +00:00
body_jannied_html = sanitize ( body_md )
c_aux = CommentAux (
id = c_jannied . id ,
body_html = body_jannied_html ,
body = body
2021-07-21 21:36:35 +00:00
)
2021-09-13 11:27:13 +00:00
g . db . add ( c_aux )
g . db . flush ( )
n = Notification ( comment_id = c_jannied . id , user_id = v . id )
g . db . add ( n )
2021-07-21 21:36:35 +00:00
2021-09-13 11:27:13 +00:00
notify_users = set ( )
soup = BeautifulSoup ( body_html , features = " html.parser " )
for mention in soup . find_all ( " a " , href = re . compile ( " ^/@( \ w+) " ) ) :
username = mention [ " href " ] . split ( " @ " ) [ 1 ]
user = g . db . query ( User ) . filter_by ( username = username ) . first ( )
if user and not v . any_block_exists ( user ) and user . id != v . id : notify_users . add ( user )
for x in notify_users : send_notification ( NOTIFICATIONS_ACCOUNT , x , f " @ { v . username } has mentioned you: https:// { site } { p . permalink } " )
2021-07-21 21:36:35 +00:00
2021-09-13 11:27:13 +00:00
if title != p . title or body != p . body :
if int ( time . time ( ) ) - p . created_utc > 60 * 3 : p . edited_utc = int ( time . time ( ) )
g . db . add ( p )
2021-07-21 01:12:26 +00:00
return redirect ( p . permalink )
2021-07-28 03:55:47 +00:00
@app.get ( " /submit/title " )
2021-07-21 01:12:26 +00:00
@limiter.limit ( " 6/minute " )
2021-08-22 20:31:12 +00:00
@auth_required
2021-07-21 01:12:26 +00:00
def get_post_title ( v ) :
url = request . args . get ( " url " , None )
if not url :
return abort ( 400 )
#mimic chrome browser agent
headers = { " User-Agent " : f " Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/89.0.4389.72 Safari/537.36 " }
try :
x = requests . get ( url , headers = headers )
except BaseException :
2021-07-31 05:28:05 +00:00
return { " error " : " Could not reach page " } , 400
2021-07-21 01:12:26 +00:00
if not x . status_code == 200 :
2021-07-31 05:28:05 +00:00
return { " error " : f " Page returned { x . status_code } " } , x . status_code
2021-07-21 01:12:26 +00:00
try :
soup = BeautifulSoup ( x . content , ' html.parser ' )
data = { " url " : url ,
" title " : soup . find ( ' title ' ) . string
}
2021-07-31 05:28:05 +00:00
return data
2021-07-21 01:12:26 +00:00
except BaseException :
2021-07-31 05:28:05 +00:00
return { " error " : f " Could not find a title " } , 400
2021-07-21 01:12:26 +00:00
def thumbs ( new_post ) :
2021-07-30 05:31:38 +00:00
pid = new_post . id
2021-07-21 01:12:26 +00:00
post = get_post ( pid , graceful = True , session = g . db )
if not post :
# account for possible follower lag
time . sleep ( 60 )
post = get_post ( pid , session = g . db )
fetch_url = post . url
#get the content
#mimic chrome browser agent
headers = { " User-Agent " : " Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/89.0.4389.72 Safari/537.36 " }
try :
x = requests . get ( fetch_url , headers = headers )
except :
return False , " Unable to connect to source "
if x . status_code != 200 :
return False , f " Source returned status { x . status_code } . "
#if content is image, stick with that. Otherwise, parse html.
if x . headers . get ( " Content-Type " , " " ) . startswith ( " text/html " ) :
#parse html, find image, load image
soup = BeautifulSoup ( x . content , ' html.parser ' )
#parse html
#create list of urls to check
thumb_candidate_urls = [ ]
#iterate through desired meta tags
meta_tags = [
" twitter:image " ,
" og:image " ,
" thumbnail "
]
for tag_name in meta_tags :
tag = soup . find (
' meta ' ,
attrs = {
" name " : tag_name ,
" content " : True
}
)
if not tag :
tag = soup . find (
' meta ' ,
attrs = {
' property ' : tag_name ,
' content ' : True
}
)
if tag :
thumb_candidate_urls . append ( expand_url ( post . url , tag [ ' content ' ] ) )
#parse html doc for <img> elements
for tag in soup . find_all ( " img " , attrs = { ' src ' : True } ) :
thumb_candidate_urls . append ( expand_url ( post . url , tag [ ' src ' ] ) )
#now we have a list of candidate urls to try
for url in thumb_candidate_urls :
try :
image_req = requests . get ( url , headers = headers )
except :
continue
if image_req . status_code > = 400 :
continue
if not image_req . headers . get ( " Content-Type " , " " ) . startswith ( " image/ " ) :
continue
if image_req . headers . get ( " Content-Type " , " " ) . startswith ( " image/svg " ) :
continue
image = PILimage . open ( BytesIO ( image_req . content ) )
if image . width < 30 or image . height < 30 :
continue
break
else :
#getting here means we are out of candidate urls (or there never were any)
return False , " No usable images "
elif x . headers . get ( " Content-Type " , " " ) . startswith ( " image/ " ) :
#image is originally loaded fetch_url
image_req = x
image = PILimage . open ( BytesIO ( x . content ) )
else :
print ( f ' Unknown content type { x . headers . get ( " Content-Type " ) } ' )
return False , f ' Unknown content type { x . headers . get ( " Content-Type " ) } for submitted content '
2021-09-13 22:47:13 +00:00
if ' pcmemes.net ' in request . host :
with open ( " image.webp " , " wb " ) as file :
for chunk in image_req . iter_content ( 1024 ) :
file . write ( chunk )
post . thumburl = upload_ibb ( resize = True )
else :
with open ( " image.png " , " wb " ) as file :
for chunk in image_req . iter_content ( 1024 ) :
file . write ( chunk )
post . thumburl = upload_imgur ( filepath = " image.png " , resize = True )
2021-09-02 14:06:28 +00:00
2021-07-21 01:12:26 +00:00
g . db . add ( post )
def archiveorg ( url ) :
try : requests . get ( f ' https://web.archive.org/save/ { url } ' , headers = { ' User-Agent ' : ' Mozilla/4.0 (compatible; MSIE 5.5; Windows NT) ' } , timeout = 100 )
except Exception as e : print ( e )
2021-08-17 21:43:49 +00:00
def filter_title ( title ) :
title = title . strip ( )
title = title . replace ( " \n " , " " )
title = title . replace ( " \r " , " " )
title = title . replace ( " \t " , " " )
# sanitize title
title = bleach . clean ( title , tags = [ ] )
for i in re . finditer ( ' :(. { 1,30}?): ' , title ) :
2021-09-13 15:58:52 +00:00
if path . isfile ( f ' ./files/assets/images/emojis/ { i . group ( 1 ) } .webp ' ) :
title = title . replace ( f ' : { i . group ( 1 ) } : ' , f ' <img loading= " lazy " data-toggle= " tooltip " title= " { i . group ( 1 ) } " delay= " 0 " height=20 src= " https:// { site } /assets/images/emojis/ { i . group ( 1 ) } .webp " <span> ' )
2021-08-17 21:43:49 +00:00
return title
2021-09-06 19:58:04 +00:00
IMGUR_KEY = environ . get ( " IMGUR_KEY " , " " ) . strip ( )
2021-09-09 14:11:44 +00:00
def check_processing_thread ( v , post , link , db ) :
2021-09-08 19:51:22 +00:00
2021-09-09 14:11:44 +00:00
image_id = link . split ( ' / ' ) [ - 1 ] . rstrip ( ' .mp4 ' )
headers = { " Authorization " : f " Client-ID { IMGUR_KEY } " }
2021-09-08 19:51:22 +00:00
2021-09-09 14:11:44 +00:00
while True :
# break on error to prevent zombie threads
try :
time . sleep ( 15 )
2021-09-08 19:51:22 +00:00
2021-09-09 14:11:44 +00:00
req = requests . get ( f " https://api.imgur.com/3/image/ { image_id } " , headers = headers )
2021-09-08 19:51:22 +00:00
2021-09-09 14:11:44 +00:00
status = req . json ( ) [ ' data ' ] [ ' processing ' ] [ ' status ' ]
if status == ' completed ' :
post . processing = False
db . add ( post )
2021-09-08 19:51:22 +00:00
2021-09-09 14:11:44 +00:00
send_notification (
NOTIFICATIONS_ACCOUNT ,
v ,
f " Your video has finished processing and your [post](/post/ { post . id } ) is now live. " ,
db = db
)
2021-09-08 19:51:22 +00:00
2021-09-09 14:11:44 +00:00
db . commit ( )
break
# just in case
elif status == ' failed ' :
print ( f " video upload for post { post . id } failed " )
break
except Exception as e :
traceback . print_exc ( )
print ( " retard. aborting thread " )
break
2021-09-06 19:58:04 +00:00
2021-07-28 03:55:47 +00:00
@app.post ( " /submit " )
2021-07-21 01:12:26 +00:00
@limiter.limit ( " 6/minute " )
@is_not_banned
@validate_formkey
def submit_post ( v ) :
2021-08-19 12:46:22 +00:00
title = request . form . get ( " title " , " " )
2021-07-21 01:12:26 +00:00
url = request . form . get ( " url " , " " )
2021-08-19 16:13:10 +00:00
2021-07-21 01:12:26 +00:00
if url :
2021-09-13 17:42:12 +00:00
if " /i.imgur.com/ " in url : url = url . replace ( " .png " , " .webp " ) . replace ( " .jpg " , " .webp " ) . replace ( " .jpeg " , " .webp " )
elif " /media.giphy.com/ " in url or " /c.tenor.com/ " in url : url = url . replace ( " .gif " , " .webp " )
elif " /i.ibb.com/ " in url : url = url . replace ( " .png " , " .webp " ) . replace ( " .jpg " , " .webp " ) . replace ( " .jpeg " , " .webp " ) . replace ( " .gif " , " .webp " )
2021-08-26 13:52:40 +00:00
for rd in [ " https://reddit.com/ " , " https://new.reddit.com/ " , " https://www.reddit.com/ " , " https://redd.it/ " ] :
url = url . replace ( rd , " https://old.reddit.com/ " )
url = url . replace ( " https://mobile.twitter.com " , " https://twitter.com " )
if url . startswith ( " https://streamable.com/ " ) and not url . startswith ( " https://streamable.com/e/ " ) :
url = url . replace ( " https://streamable.com/ " , " https://streamable.com/e/ " )
2021-09-01 11:31:47 +00:00
if " i.imgur.com " in url and " _d. " not in url :
2021-09-01 11:31:35 +00:00
url = url . replace ( " .png " , " _d.png " ) . replace ( " .jpg " , " _d.jpg " ) . replace ( " .jpeg " , " _d.jpeg " )
if " _d. " in url : url + = " ?maxwidth=9999 "
2021-08-26 13:52:40 +00:00
2021-07-21 01:12:26 +00:00
repost = g . db . query ( Submission ) . join ( Submission . submission_aux ) . filter (
SubmissionAux . url . ilike ( url ) ,
Submission . deleted_utc == 0 ,
Submission . is_banned == False
) . first ( )
else :
repost = None
if repost :
return redirect ( repost . permalink )
if not title :
2021-07-31 05:28:05 +00:00
if request . headers . get ( " Authorization " ) : return { " error " : " Please enter a better title " } , 400
else : return render_template ( " submit.html " , v = v , error = " Please enter a better title. " , title = title , url = url , body = request . form . get ( " body " , " " ) ) , 400
2021-07-21 01:12:26 +00:00
elif len ( title ) > 500 :
2021-07-31 05:28:05 +00:00
if request . headers . get ( " Authorization " ) : return { " error " : " 500 character limit for titles " } , 400
2021-08-02 07:37:46 +00:00
else : render_template ( " submit.html " , v = v , error = " 500 character limit for titles. " , title = title [ : 500 ] , url = url , body = request . form . get ( " body " , " " ) ) , 400
2021-07-31 05:28:05 +00:00
2021-07-21 01:12:26 +00:00
parsed_url = urlparse ( url )
if not ( parsed_url . scheme and parsed_url . netloc ) and not request . form . get (
" body " ) and not request . files . get ( " file " , None ) :
2021-07-31 05:28:05 +00:00
if request . headers . get ( " Authorization " ) : return { " error " : " `url` or `body` parameter required. " } , 400
else : return render_template ( " submit.html " , v = v , error = " Please enter a url or some text. " , title = title , url = url , body = request . form . get ( " body " , " " ) ) , 400
2021-07-21 01:12:26 +00:00
# Force https for submitted urls
if request . form . get ( " url " ) :
new_url = ParseResult ( scheme = " https " ,
netloc = parsed_url . netloc ,
path = parsed_url . path ,
params = parsed_url . params ,
query = parsed_url . query ,
fragment = parsed_url . fragment )
url = urlunparse ( new_url )
else :
url = " "
body = request . form . get ( " body " , " " )
# check for duplicate
dup = g . db . query ( Submission ) . join ( Submission . submission_aux ) . filter (
Submission . author_id == v . id ,
Submission . deleted_utc == 0 ,
SubmissionAux . title == title ,
SubmissionAux . url == url ,
SubmissionAux . body == body
) . first ( )
if dup :
return redirect ( dup . permalink )
# check for domain specific rules
parsed_url = urlparse ( url )
domain = parsed_url . netloc
# check ban status
domain_obj = get_domain ( domain )
2021-08-01 04:24:46 +00:00
if domain_obj :
if domain_obj . reason == 4 :
v . ban ( days = 30 , reason = " Digitally malicious content " )
elif domain_obj . reason == 7 :
v . ban ( reason = " Sexualizing minors " )
2021-07-21 01:12:26 +00:00
2021-08-01 04:24:46 +00:00
if request . headers . get ( " Authorization " ) : return { " error " : " ToS violation " } , 400
else : return render_template ( " submit.html " , v = v , error = " ToS Violation " , title = title , url = url , body = request . form . get ( " body " , " " ) ) , 400
if " twitter.com " in domain :
2021-08-05 14:42:56 +00:00
try : embed = requests . get ( " https://publish.twitter.com/oembed " , params = { " url " : url , " omit_script " : " t " } ) . json ( ) [ " html " ]
2021-08-05 14:44:22 +00:00
except : embed = None
2021-08-05 14:42:56 +00:00
2021-08-01 04:24:46 +00:00
elif " youtu " in domain :
2021-09-06 19:54:41 +00:00
try : yt_id = re . match ( re . compile ( " ^.*(youtu.be \ /|v \ /|u \ / \ w \ /|embed \ /|watch \ ?v=|shorts \ /| \ &v=)([^# \ & \ ?]*).* " ) , url ) . group ( 2 )
except : embed = None
2021-08-01 04:24:46 +00:00
if not yt_id or len ( yt_id ) != 11 : embed = None
else :
params = parse_qs ( urlparse ( url ) . query )
t = params . get ( ' t ' , params . get ( ' start ' , [ 0 ] ) ) [ 0 ]
if t : embed = f " https://youtube.com/embed/ { yt_id } ?start= { t } "
else : embed = f " https://youtube.com/embed/ { yt_id } "
2021-08-21 12:51:19 +00:00
elif app . config [ ' SERVER_NAME ' ] in domain and " /post/ " in url and " context " not in url :
2021-08-13 02:35:17 +00:00
id = url . split ( " /post/ " ) [ 1 ]
if " / " in id : id = id . split ( " / " ) [ 0 ]
embed = id
2021-08-01 04:24:46 +00:00
else : embed = None
2021-07-21 01:12:26 +00:00
# similarity check
now = int ( time . time ( ) )
cutoff = now - 60 * 60 * 24
similar_posts = g . db . query ( Submission ) . options (
lazyload ( ' * ' )
) . join (
Submission . submission_aux
) . filter (
#or_(
# and_(
Submission . author_id == v . id ,
SubmissionAux . title . op ( ' <-> ' ) ( title ) < app . config [ " SPAM_SIMILARITY_THRESHOLD " ] ,
Submission . created_utc > cutoff
# ),
# and_(
# SubmissionAux.title.op('<->')(title) < app.config["SPAM_SIMILARITY_THRESHOLD"]/2,
# Submission.created_utc > cutoff
# )
#)
) . all ( )
if url :
similar_urls = g . db . query ( Submission ) . options (
lazyload ( ' * ' )
) . join (
Submission . submission_aux
) . filter (
#or_(
# and_(
Submission . author_id == v . id ,
SubmissionAux . url . op ( ' <-> ' ) ( url ) < app . config [ " SPAM_URL_SIMILARITY_THRESHOLD " ] ,
Submission . created_utc > cutoff
# ),
# and_(
# SubmissionAux.url.op('<->')(url) < app.config["SPAM_URL_SIMILARITY_THRESHOLD"]/2,
# Submission.created_utc > cutoff
# )
#)
) . all ( )
else :
similar_urls = [ ]
threshold = app . config [ " SPAM_SIMILAR_COUNT_THRESHOLD " ]
if v . age > = ( 60 * 60 * 24 * 7 ) :
threshold * = 3
elif v . age > = ( 60 * 60 * 24 ) :
threshold * = 2
if max ( len ( similar_urls ) , len ( similar_posts ) ) > = threshold :
2021-08-04 16:00:57 +00:00
text = " Your account has been suspended for 1 day for the following reason: \n \n > Too much spam! "
2021-08-21 11:06:28 +00:00
send_notification ( NOTIFICATIONS_ACCOUNT , v , text )
2021-07-21 01:12:26 +00:00
v . ban ( reason = " Spamming. " ,
days = 1 )
for alt in v . alts :
if not alt . is_suspended :
2021-07-30 08:37:21 +00:00
alt . ban ( reason = " Spamming. " , days = 1 )
2021-07-21 01:12:26 +00:00
for post in similar_posts + similar_urls :
post . is_banned = True
post . is_pinned = False
post . ban_reason = " Automatic spam removal. This happened because the post ' s creator submitted too much similar content too quickly. "
g . db . add ( post )
ma = ModAction (
2021-08-21 11:06:28 +00:00
user_id = AUTOJANNY_ACCOUNT ,
2021-07-21 01:12:26 +00:00
target_submission_id = post . id ,
kind = " ban_post " ,
note = " spam "
)
g . db . add ( ma )
return redirect ( " /notifications " )
# catch too-long body
if len ( str ( body ) ) > 10000 :
2021-07-31 05:28:05 +00:00
if request . headers . get ( " Authorization " ) : return { " error " : " 10000 character limit for text body. " } , 400
else : return render_template ( " submit.html " , v = v , error = " 10000 character limit for text body. " , title = title , url = url , body = request . form . get ( " body " , " " ) ) , 400
2021-07-21 01:12:26 +00:00
if len ( url ) > 2048 :
2021-07-31 05:28:05 +00:00
if request . headers . get ( " Authorization " ) : return { " error " : " 2048 character limit for URLs. " } , 400
else : return render_template ( " submit.html " , v = v , error = " 2048 character limit for URLs. " , title = title , url = url , body = request . form . get ( " body " , " " ) ) , 400
2021-07-21 01:12:26 +00:00
# render text
2021-08-19 05:54:40 +00:00
for i in re . finditer ( ' ^(https: \ / \ /.* \ .(png|jpg|jpeg|gif|PNG|JPG|JPEG|GIF|9999)) ' , body , re . MULTILINE ) : body = body . replace ( i . group ( 1 ) , f ' ![]( { i . group ( 1 ) } ) ' )
2021-09-03 17:09:42 +00:00
body = body . replace ( " \n " , " \n \n " ) . replace ( " \n \n \n \n \n \n " , " \n \n " ) . replace ( " \n \n \n \n " , " \n \n " ) . replace ( " \n \n \n " , " \n \n " )
2021-09-13 11:45:03 +00:00
body_md = CustomRenderer ( ) . render ( mistletoe . Document ( body ) )
2021-08-21 12:57:16 +00:00
body_html = sanitize ( body_md )
2021-07-21 01:12:26 +00:00
# Run safety filter
bans = filter_comment_html ( body_html )
if bans :
ban = bans [ 0 ]
reason = f " Remove the { ban . domain } link from your post and try again. "
if ban . reason :
2021-08-03 12:20:40 +00:00
reason + = f " { ban . reason } "
2021-07-21 01:12:26 +00:00
#auto ban for digitally malicious content
if any ( [ x . reason == 4 for x in bans ] ) :
v . ban ( days = 30 , reason = " Digitally malicious content is not allowed. " )
abort ( 403 )
2021-07-31 05:28:05 +00:00
if request . headers . get ( " Authorization " ) : return { " error " : reason } , 403
else : return render_template ( " submit.html " , v = v , error = reason , title = title , url = url , body = request . form . get ( " body " , " " ) ) , 403
2021-07-21 01:12:26 +00:00
# check spam
soup = BeautifulSoup ( body_html , features = " html.parser " )
links = [ x [ ' href ' ] for x in soup . find_all ( ' a ' ) if x . get ( ' href ' ) ]
if url :
links = [ url ] + links
for link in links :
parse_link = urlparse ( link )
check_url = ParseResult ( scheme = " https " ,
netloc = parse_link . netloc ,
path = parse_link . path ,
params = parse_link . params ,
query = parse_link . query ,
fragment = ' ' )
check_url = urlunparse ( check_url )
badlink = g . db . query ( BadLink ) . filter (
literal ( check_url ) . contains (
BadLink . link ) ) . first ( )
if badlink :
if badlink . autoban :
2021-08-04 16:00:57 +00:00
text = " Your account has been suspended for 1 day for the following reason: \n \n > Too much spam! "
2021-08-21 11:06:28 +00:00
send_notification ( NOTIFICATIONS_ACCOUNT , v , text )
2021-07-21 01:12:26 +00:00
v . ban ( days = 1 , reason = " spam " )
return redirect ( ' /notifications ' )
else :
2021-07-31 05:28:05 +00:00
if request . headers . get ( " Authorization " ) : return { " error " : f " The link ` { badlink . link } ` is not allowed. Reason: { badlink . reason } " } , 400
else : return render_template ( " submit.html " , v = v , error = f " The link ` { badlink . link } ` is not allowed. Reason: { badlink . reason } . " , title = title , url = url , body = request . form . get ( " body " , " " ) ) , 400
2021-07-21 01:12:26 +00:00
# check for embeddable video
domain = parsed_url . netloc
new_post = Submission (
private = bool ( request . form . get ( " private " , " " ) ) ,
2021-09-11 23:40:58 +00:00
club = bool ( request . form . get ( " club " , " " ) ) ,
2021-07-21 01:12:26 +00:00
author_id = v . id ,
over_18 = bool ( request . form . get ( " over_18 " , " " ) ) ,
2021-08-03 17:33:13 +00:00
app_id = v . client . application . id if v . client else None ,
2021-07-21 01:12:26 +00:00
is_bot = request . headers . get ( " X-User-Type " , " " ) . lower ( ) == " bot "
)
g . db . add ( new_post )
g . db . flush ( )
2021-08-15 03:17:45 +00:00
2021-07-21 01:12:26 +00:00
new_post_aux = SubmissionAux ( id = new_post . id ,
url = url ,
body = body ,
body_html = body_html ,
embed_url = embed ,
title = title ,
2021-08-19 12:46:22 +00:00
title_html = filter_title ( title )
2021-07-21 01:12:26 +00:00
)
g . db . add ( new_post_aux )
g . db . flush ( )
vote = Vote ( user_id = v . id ,
vote_type = 1 ,
submission_id = new_post . id
)
g . db . add ( vote )
g . db . flush ( )
g . db . refresh ( new_post )
# check for uploaded image
2021-07-31 09:00:56 +00:00
if request . files . get ( ' file ' ) and request . headers . get ( " cf-ipcountry " ) != " T1 " :
2021-07-21 01:12:26 +00:00
#check file size
if request . content_length > 16 * 1024 * 1024 :
g . db . rollback ( )
abort ( 413 )
file = request . files [ ' file ' ]
2021-09-05 16:53:18 +00:00
#if not file.content_type.startswith('image/'):
# if request.headers.get("Authorization"): return {"error": f"Image files only"}, 400
# else: return render_template("submit.html", v=v, error=f"Image files only.", title=title, body=request.form.get("body", "")), 400
if not file . content_type . startswith ( ( ' image/ ' , ' video/ ' ) ) :
if request . headers . get ( " Authorization " ) : return { " error " : f " File type not allowed " } , 400
else : return render_template ( " submit.html " , v = v , error = f " File type not allowed. " , title = title , body = request . form . get ( " body " , " " ) ) , 400
if file . content_type . startswith ( ' video/ ' ) and v . coins < app . config [ " VIDEO_COIN_REQUIREMENT " ] and v . admin_level < 1 :
if request . headers . get ( " Authorization " ) :
return {
" error " : f " You need at least { app . config [ ' VIDEO_COIN_REQUIREMENT ' ] } coins to upload videos "
2021-09-06 20:56:55 +00:00
} , 403
2021-09-05 16:53:18 +00:00
else :
return render_template (
" submit.html " ,
v = v ,
error = f " You need at least { app . config [ ' VIDEO_COIN_REQUIREMENT ' ] } coins to upload videos. " ,
title = title ,
body = request . form . get ( " body " , " " )
2021-09-06 20:56:55 +00:00
) , 403
2021-09-05 16:53:18 +00:00
2021-09-10 03:03:37 +00:00
if file . content_type . startswith ( ' image/ ' ) :
2021-09-13 17:03:46 +00:00
if ' pcmemes.net ' in request . host : new_post . url = upload_ibb ( file = file )
2021-09-13 16:35:26 +00:00
else : new_post . url = upload_imgur ( file = file )
2021-09-05 16:53:18 +00:00
else :
2021-09-10 03:03:37 +00:00
try :
post_url = upload_video ( file )
if not post_url . endswith ( ' .mp4 ' ) :
post_url + = ' mp4 '
new_post . url = post_url
new_post . processing = True
gevent . spawn ( check_processing_thread , v . id , new_post , post_url , g . db )
except UploadException as e :
if request . headers . get ( " Authorization " ) :
return {
" error " : str ( e ) ,
} , 400
else :
return render_template (
" submit.html " ,
v = v ,
error = str ( e ) ,
title = title ,
body = request . form . get ( " body " , " " )
) , 400
2021-09-02 14:06:28 +00:00
2021-07-21 01:12:26 +00:00
g . db . add ( new_post )
g . db . add ( new_post . submission_aux )
2021-08-11 17:01:19 +00:00
g . db . flush ( )
2021-07-21 01:12:26 +00:00
2021-08-13 01:29:21 +00:00
# spin off thumbnail generation and csam detection as new threads
2021-07-21 01:12:26 +00:00
if ( new_post . url or request . files . get ( ' file ' ) ) and ( v . is_activated or request . headers . get ( ' cf-ipcountry ' ) != " T1 " ) : thumbs ( new_post )
notify_users = set ( )
soup = BeautifulSoup ( body_html , features = " html.parser " )
for mention in soup . find_all ( " a " , href = re . compile ( " ^/@( \ w+) " ) ) :
username = mention [ " href " ] . split ( " @ " ) [ 1 ]
user = g . db . query ( User ) . filter_by ( username = username ) . first ( )
if user and not v . any_block_exists ( user ) and user . id != v . id : notify_users . add ( user )
2021-08-21 11:06:28 +00:00
for x in notify_users : send_notification ( NOTIFICATIONS_ACCOUNT , x , f " @ { v . username } has mentioned you: https:// { site } { new_post . permalink } " )
2021-07-21 01:12:26 +00:00
if not new_post . private :
for follow in v . followers :
user = get_account ( follow . user_id )
2021-08-21 11:06:28 +00:00
send_notification ( AUTOJANNY_ACCOUNT , user , f " @ { v . username } has made a new post: [ { title } ](https:// { site } { new_post . permalink } ) " )
2021-07-21 01:12:26 +00:00
g . db . add ( new_post )
2021-08-11 17:01:19 +00:00
g . db . flush ( )
2021-07-21 01:12:26 +00:00
2021-09-01 20:51:47 +00:00
2021-09-02 00:03:44 +00:00
if " rdrama " in request . host and " ivermectin " in new_post_aux . body_html . lower ( ) :
2021-09-01 20:51:47 +00:00
new_post . is_banned = True
new_post . ban_reason = " ToS Violation "
g . db . add ( new_post )
c_jannied = Comment ( author_id = AUTOJANNY_ACCOUNT ,
parent_submission = new_post . id ,
level = 1 ,
over_18 = False ,
is_bot = True ,
app_id = None ,
is_pinned = True ,
distinguish_level = 6
)
g . db . add ( c_jannied )
g . db . flush ( )
body = VAXX_MSG . format ( username = v . username )
2021-09-13 11:54:20 +00:00
body_md = CustomRenderer ( ) . render ( mistletoe . Document ( body ) )
2021-09-01 20:51:47 +00:00
body_jannied_html = sanitize ( body_md )
c_aux = CommentAux (
id = c_jannied . id ,
body_html = body_jannied_html ,
body = body
)
g . db . add ( c_aux )
g . db . flush ( )
n = Notification ( comment_id = c_jannied . id , user_id = v . id )
g . db . add ( n )
2021-07-21 21:36:35 +00:00
if v . agendaposter and " trans lives matter " not in new_post_aux . body_html . lower ( ) :
new_post . is_banned = True
new_post . ban_reason = " ToS Violation "
g . db . add ( new_post )
2021-08-21 11:06:28 +00:00
c_jannied = Comment ( author_id = AUTOJANNY_ACCOUNT ,
2021-07-21 21:36:35 +00:00
parent_submission = new_post . id ,
level = 1 ,
2021-07-21 23:32:40 +00:00
over_18 = False ,
2021-07-21 21:36:35 +00:00
is_bot = True ,
2021-07-21 23:32:40 +00:00
app_id = None ,
is_pinned = True ,
distinguish_level = 6
)
2021-07-21 21:36:35 +00:00
g . db . add ( c_jannied )
g . db . flush ( )
2021-08-21 11:06:28 +00:00
body = AGENDAPOSTER_MSG . format ( username = v . username )
2021-07-21 21:36:35 +00:00
2021-09-13 11:54:20 +00:00
body_md = CustomRenderer ( ) . render ( mistletoe . Document ( body ) )
2021-07-21 21:36:35 +00:00
body_jannied_html = sanitize ( body_md )
c_aux = CommentAux (
id = c_jannied . id ,
body_html = body_jannied_html ,
body = body
)
g . db . add ( c_aux )
g . db . flush ( )
n = Notification ( comment_id = c_jannied . id , user_id = v . id )
g . db . add ( n )
2021-09-05 14:59:49 +00:00
if " rdrama " in request . host or ( new_post . url and not " weebzone " in request . host and not " marsey.tech " in request . host ) :
2021-08-27 22:10:03 +00:00
c = Comment ( author_id = 261 ,
distinguish_level = 6 ,
parent_submission = new_post . id ,
level = 1 ,
over_18 = False ,
is_bot = True ,
app_id = None ,
)
2021-07-21 01:12:26 +00:00
2021-08-27 22:10:03 +00:00
g . db . add ( c )
g . db . flush ( )
2021-07-21 01:12:26 +00:00
2021-08-27 22:10:03 +00:00
new_post . comment_count = 1
g . db . add ( new_post )
2021-08-22 19:33:06 +00:00
2021-08-27 22:10:03 +00:00
if " rdrama " in request . host :
2021-09-01 11:55:15 +00:00
if v . id == 995 :
if random . random ( ) < 0.02 : body = " i love you carp "
else : body = " fuck off carp "
elif v . id == 3833 :
if random . random ( ) < 0.5 : body = " wow, this lawlzpost sucks! "
else : body = " wow, a good lawlzpost for once! "
2021-08-27 22:10:03 +00:00
else : body = random . choice ( snappyquotes )
body + = " \n \n --- \n \n "
else : body = " "
if new_post . url :
body + = f " Snapshots: \n \n * [reveddit.com](https://reveddit.com/ { new_post . url } ) \n * [archive.org](https://web.archive.org/ { new_post . url } ) \n * [archive.ph](https://archive.ph/?url= { urllib . parse . quote ( new_post . url ) } &run=1) (click to archive) "
gevent . spawn ( archiveorg , new_post . url )
2021-09-13 11:54:20 +00:00
body_md = CustomRenderer ( ) . render ( mistletoe . Document ( body ) )
2021-08-27 22:10:03 +00:00
body_html = sanitize ( body_md )
c_aux = CommentAux (
id = c . id ,
body_html = body_html ,
body = body
)
g . db . add ( c_aux )
g . db . flush ( )
n = Notification ( comment_id = c . id , user_id = v . id )
g . db . add ( n )
g . db . flush ( )
2021-07-23 13:47:25 +00:00
2021-07-28 03:55:47 +00:00
v . post_count = v . submissions . filter_by ( is_banned = False , deleted_utc = 0 ) . count ( )
g . db . add ( v )
2021-07-30 09:42:17 +00:00
2021-08-11 17:06:56 +00:00
cache . delete_memoized ( User . userpagelisting , v )
2021-08-18 00:32:36 +00:00
cache . delete_memoized ( frontlist )
2021-08-24 17:49:47 +00:00
if " [changelog] " in new_post . title or " (changelog) " in new_post . title :
2021-08-19 06:14:17 +00:00
send_message ( f " https:// { site } { new_post . permalink } " )
cache . delete_memoized ( changeloglist )
2021-07-30 09:42:17 +00:00
2021-07-31 05:28:05 +00:00
if request . headers . get ( " Authorization " ) : return new_post . json
else : return redirect ( new_post . permalink )
2021-07-21 01:12:26 +00:00
2021-07-27 22:31:28 +00:00
@app.post ( " /delete_post/<pid> " )
2021-07-21 01:12:26 +00:00
@auth_required
@validate_formkey
def delete_post_pid ( pid , v ) :
post = get_post ( pid )
if not post . author_id == v . id :
abort ( 403 )
post . deleted_utc = int ( time . time ( ) )
post . is_pinned = False
post . stickied = False
g . db . add ( post )
2021-08-18 00:32:36 +00:00
cache . delete_memoized ( frontlist )
2021-07-21 01:12:26 +00:00
2021-09-08 11:05:31 +00:00
return { " message " : " Post deleted! " }
2021-07-21 01:12:26 +00:00
2021-07-27 22:31:28 +00:00
@app.post ( " /undelete_post/<pid> " )
2021-07-21 01:12:26 +00:00
@auth_required
@validate_formkey
def undelete_post_pid ( pid , v ) :
post = get_post ( pid )
if not post . author_id == v . id : abort ( 403 )
post . deleted_utc = 0
g . db . add ( post )
2021-07-30 09:42:17 +00:00
2021-08-18 00:32:36 +00:00
cache . delete_memoized ( frontlist )
2021-07-30 09:42:17 +00:00
2021-09-08 11:05:31 +00:00
return { " message " : " Post undeleted! " }
2021-07-21 01:12:26 +00:00
2021-07-31 04:48:47 +00:00
@app.post ( " /toggle_comment_nsfw/<cid> " )
2021-08-22 20:31:12 +00:00
@auth_required
2021-07-21 01:12:26 +00:00
@validate_formkey
def toggle_comment_nsfw ( cid , v ) :
2021-07-30 05:31:38 +00:00
comment = g . db . query ( Comment ) . filter_by ( id = cid ) . first ( )
2021-07-21 01:12:26 +00:00
if not comment . author_id == v . id and not v . admin_level > = 3 : abort ( 403 )
comment . over_18 = not comment . over_18
g . db . add ( comment )
2021-09-08 11:05:31 +00:00
g . db . flush ( )
if comment . over_18 : return { " message " : " Comment has been marked as +18! " }
else : return { " message " : " Comment has been unmarked as +18! " }
2021-07-21 01:12:26 +00:00
2021-07-31 04:48:47 +00:00
@app.post ( " /toggle_post_nsfw/<pid> " )
2021-08-22 20:31:12 +00:00
@auth_required
2021-07-21 01:12:26 +00:00
@validate_formkey
def toggle_post_nsfw ( pid , v ) :
post = get_post ( pid )
2021-07-25 21:59:20 +00:00
if not post . author_id == v . id and not v . admin_level > = 3 :
2021-07-21 01:12:26 +00:00
abort ( 403 )
post . over_18 = not post . over_18
g . db . add ( post )
if post . author_id != v . id :
ma = ModAction (
kind = " set_nsfw " if post . over_18 else " unset_nsfw " ,
user_id = v . id ,
target_submission_id = post . id ,
)
g . db . add ( ma )
2021-09-08 11:05:31 +00:00
g . db . flush ( )
if post . over_18 : return { " message " : " Post has been marked as +18! " }
else : return { " message " : " Post has been unmarked as +18! " }
2021-07-21 01:12:26 +00:00
2021-07-27 22:31:28 +00:00
@app.post ( " /save_post/<pid> " )
2021-07-21 01:12:26 +00:00
@auth_required
@validate_formkey
def save_post ( pid , v ) :
post = get_post ( pid )
new_save = SaveRelationship ( user_id = v . id , submission_id = post . id , type = 1 )
g . db . add ( new_save )
try : g . db . flush ( )
2021-07-28 05:04:30 +00:00
except : g . db . rollback ( )
2021-07-21 01:12:26 +00:00
2021-09-08 11:05:31 +00:00
return { " message " : " Post saved! " }
2021-07-21 01:12:26 +00:00
2021-07-27 22:31:28 +00:00
@app.post ( " /unsave_post/<pid> " )
2021-07-21 01:12:26 +00:00
@auth_required
@validate_formkey
def unsave_post ( pid , v ) :
post = get_post ( pid )
save = g . db . query ( SaveRelationship ) . filter_by ( user_id = v . id , submission_id = post . id , type = 1 ) . first ( )
2021-08-11 18:30:25 +00:00
if save : g . db . delete ( save )
2021-07-21 01:12:26 +00:00
2021-09-08 11:05:31 +00:00
return { " message " : " Post unsaved! " }