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 . 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-09-23 23:22:15 +00:00
from files . __main__ import app , limiter , cache , db_session
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-17 15:44:00 +00:00
if post . author_id != v . id or not v . paid_dues : 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 )
2021-09-16 17:02:58 +00:00
g . db . commit ( )
2021-09-21 19:07:12 +00:00
if post . club : return { " message " : " Post has been marked as club-only! " }
else : return { " message " : " Post has been unmarked as club-only! " }
2021-09-11 23:40:58 +00:00
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-20 13:11:10 +00:00
for follow in v . followers :
user = get_account ( follow . user_id )
send_notification ( AUTOJANNY_ACCOUNT , user , f " @ { v . username } has made a new post: [ { post . title } ](https:// { site } { post . permalink } ) " )
2021-09-16 17:02:58 +00:00
g . db . commit ( )
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-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-24 20:08:40 +00:00
if not v and not request . path . startswith ( ' /logged_out ' ) and not request . headers . get ( " Authorization " ) : return redirect ( f " /logged_out { request . full_path } " )
2021-08-13 01:38:51 +00:00
2021-10-01 20:11:44 +00:00
if v and request . 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 "
2021-09-19 13:11:34 +00:00
sort = request . values . 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 :
2021-09-17 12:07:17 +00:00
votes = g . db . query ( CommentVote ) . options ( lazyload ( ' * ' ) ) . filter_by ( user_id = v . id ) . subquery ( )
2021-07-25 14:23:53 +00:00
2021-09-17 12:07:17 +00:00
blocking = v . blocking . subquery ( )
2021-07-25 14:23:53 +00:00
2021-09-17 12:07:17 +00:00
blocked = v . blocked . subquery ( )
2021-07-25 14:23:53 +00:00
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 ,
)
2021-09-16 09:56:50 +00:00
2021-09-16 10:06:05 +00:00
if not ( v and v . shadowbanned ) and not ( v and v . admin_level == 6 ) :
2021-09-30 19:40:33 +00:00
shadowbanned = [ x [ 0 ] for x in g . db . query ( User . id ) . options ( lazyload ( ' * ' ) ) . filter ( User . shadowbanned != None ) . all ( ) ]
2021-09-16 10:06:55 +00:00
comments = comments . filter ( Comment . author_id . notin_ ( shadowbanned ) )
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
)
2021-09-23 19:16:44 +00:00
if sort == " new " :
comments = comments . order_by ( Comment . created_utc . desc ( ) )
2021-07-25 14:23:53 +00:00
elif sort == " old " :
2021-09-23 19:16:44 +00:00
comments = comments . order_by ( Comment . created_utc . asc ( ) )
2021-07-25 14:23:53 +00:00
elif sort == " controversial " :
2021-09-23 19:20:47 +00:00
comments = comments . order_by ( - 1 * Comment . upvotes * ( Comment . downvotes + 1 ) )
2021-09-23 19:16:44 +00:00
elif sort == " top " :
comments = comments . order_by ( Comment . downvotes - Comment . upvotes )
elif sort == " bottom " :
comments = comments . order_by ( Comment . upvotes - Comment . downvotes )
2021-07-25 14:23:53 +00:00
output = [ ]
2021-09-23 19:16:44 +00:00
for c in comments . all ( ) :
2021-07-25 14:23:53 +00:00
comment = c [ 0 ]
2021-08-07 23:03:15 +00:00
comment . voted = c [ 1 ] or 0
2021-09-22 18:36:03 +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-09-30 19:40:33 +00:00
shadowbanned = [ x [ 0 ] for x in g . db . query ( User . id ) . options ( lazyload ( ' * ' ) ) . filter ( User . shadowbanned != None ) . all ( ) ]
2021-09-17 20:51:18 +00:00
comments = g . db . query ( Comment ) . filter ( Comment . parent_submission == post . id , Comment . author_id . notin_ ( shadowbanned ) )
2021-07-25 14:23:53 +00:00
2021-09-23 19:16:44 +00:00
if sort == " new " :
comments = comments . order_by ( Comment . created_utc . desc ( ) )
2021-07-25 14:23:53 +00:00
elif sort == " old " :
2021-09-23 19:16:44 +00:00
comments = comments . order_by ( Comment . created_utc . asc ( ) )
2021-07-25 14:23:53 +00:00
elif sort == " controversial " :
2021-09-23 19:20:47 +00:00
comments = comments . order_by ( - 1 * Comment . upvotes * ( Comment . downvotes + 1 ) )
2021-09-23 19:16:44 +00:00
elif sort == " top " :
comments = comments . order_by ( Comment . downvotes - Comment . upvotes )
elif sort == " bottom " :
comments = comments . order_by ( Comment . upvotes - Comment . downvotes )
post . preloaded_comments = comments . all ( )
2021-07-25 14:23:53 +00:00
2021-09-17 09:43:50 +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-09-17 09:43:50 +00:00
g . db . commit ( )
2021-07-31 05:59:25 +00:00
if request . headers . get ( " Authorization " ) : return post . json
2021-09-29 16:50:52 +00:00
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-19 13:11:34 +00:00
title = request . values . get ( " title " )
body = request . values . 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 :
2021-09-17 15:52:00 +00:00
for i in re . finditer ( ' ^(https: \ / \ /.* \ .(png|jpg|jpeg|gif|webp|PNG|JPG|JPEG|GIF|WEBP|9999)) ' , body , re . MULTILINE ) :
2021-09-15 12:43:46 +00:00
if " wikipedia " not in i . group ( 1 ) : 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 )
2021-09-17 08:29:05 +00:00
badlink = g . db . query ( BadLink ) . options ( lazyload ( ' * ' ) ) . filter (
2021-09-13 11:27:13 +00:00
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 )
2021-09-24 02:21:41 +00:00
body = VAXX_MSG . format ( username = v . username )
body_md = CustomRenderer ( ) . render ( mistletoe . Document ( body ) )
body_jannied_html = sanitize ( body_md )
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 ,
2021-09-24 02:21:41 +00:00
distinguish_level = 6 ,
body_html = body_jannied_html ,
body = body
2021-09-13 11:27:13 +00:00
)
g . db . add ( c_jannied )
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-24 02:21:41 +00:00
body = AGENDAPOSTER_MSG . format ( username = v . username )
body_md = CustomRenderer ( ) . render ( mistletoe . Document ( body ) )
body_jannied_html = sanitize ( body_md )
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 ,
2021-09-24 02:21:41 +00:00
distinguish_level = 6 ,
body_html = body_jannied_html ,
body = body
2021-09-13 11:27:13 +00:00
)
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
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 ]
2021-09-17 08:29:05 +00:00
user = g . db . query ( User ) . options ( lazyload ( ' * ' ) ) . filter_by ( username = username ) . first ( )
2021-09-13 11:27:13 +00:00
if user and not v . any_block_exists ( user ) and user . id != v . id : notify_users . add ( user )
2021-09-27 21:46:35 +00:00
message = f " @ { v . username } has mentioned you: https:// { site } { p . permalink } "
for x in notify_users :
2021-09-27 21:55:36 +00:00
existing = g . db . query ( Comment ) . options ( lazyload ( ' * ' ) ) . filter ( Comment . author_id == NOTIFICATIONS_ACCOUNT , Comment . body == message , Comment . notifiedto == x . id ) . first ( )
2021-09-27 21:46:35 +00:00
if not existing : send_notification ( NOTIFICATIONS_ACCOUNT , x , message )
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
2021-09-16 17:02:58 +00:00
g . db . commit ( )
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 ) :
2021-09-19 13:11:34 +00:00
url = request . values . get ( " url " , None )
2021-09-27 20:26:34 +00:00
if not url : return abort ( 400 )
2021-07-21 01:12:26 +00:00
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 " }
2021-09-29 19:02:55 +00:00
try : x = requests . get ( url , headers = headers , timeout = 5 )
2021-09-27 20:26:34 +00:00
except BaseException : return { " error " : " Could not reach page " } , 400
2021-07-21 01:12:26 +00:00
2021-09-27 20:26:34 +00:00
if not x . status_code == 200 : 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 ' )
2021-09-27 20:26:34 +00:00
return { " url " : url , " title " : soup . find ( ' title ' ) . string }
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 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-29 15:42:28 +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-bs-toggle= " tooltip " title= " { i . group ( 1 ) } " delay= " 0 " height=20 src= " https:// { site } /assets/images/emojis/ { i . group ( 1 ) } .webp " > ' )
2021-08-17 21:43:49 +00:00
return title
2021-09-06 19:58:04 +00:00
2021-09-23 23:22:15 +00:00
def thumbnail_thread ( pid ) :
2021-09-30 19:17:16 +00:00
def expand_url ( post_url , fragment_url ) :
# convert src into full url
if fragment_url . startswith ( " https:// " ) :
return fragment_url
elif fragment_url . startswith ( " http:// " ) :
return f " https:// { fragment_url . split ( ' http:// ' ) [ 1 ] } "
elif fragment_url . startswith ( ' // ' ) :
return f " https: { fragment_url } "
elif fragment_url . startswith ( ' / ' ) :
parsed_url = urlparse ( post_url )
return f " https:// { parsed_url . netloc } { fragment_url } "
else :
2021-10-02 12:52:31 +00:00
return f " { post_url } { ' / ' if not post_url . endswith ( ' / ' ) else ' ' } { fragment_url } "
2021-09-30 19:17:16 +00:00
2021-09-23 23:22:15 +00:00
db = db_session ( )
2021-09-23 23:24:23 +00:00
post = db . query ( Submission ) . filter_by ( id = pid ) . first ( )
2021-09-24 02:23:45 +00:00
if not post :
time . sleep ( 5 )
post = db . query ( Submission ) . filter_by ( id = pid ) . first ( )
2021-09-15 17:11:15 +00:00
2021-09-23 23:22:15 +00:00
fetch_url = post . url
2021-09-15 17:11:15 +00:00
#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 :
2021-09-23 23:22:15 +00:00
db . close ( )
2021-09-23 23:30:09 +00:00
return
2021-09-15 17:11:15 +00:00
if x . status_code != 200 :
2021-09-23 23:22:15 +00:00
db . close ( )
2021-09-23 23:30:09 +00:00
return
2021-09-23 23:22:15 +00:00
2021-09-15 17:11:15 +00:00
#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 = [
2021-09-23 23:22:15 +00:00
" ruqqus:thumbnail " ,
2021-09-15 17:11:15 +00:00
" 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)
2021-09-23 23:22:15 +00:00
db . close ( )
2021-09-23 23:30:09 +00:00
return
2021-09-15 17:11:15 +00:00
elif x . headers . get ( " Content-Type " , " " ) . startswith ( " image/ " ) :
#image is originally loaded fetch_url
image_req = x
image = PILimage . open ( BytesIO ( x . content ) )
else :
2021-09-23 23:22:15 +00:00
db . close ( )
2021-09-23 23:30:09 +00:00
return
2021-09-15 17:11:15 +00:00
2021-09-23 23:25:21 +00:00
with open ( " image.webp " , " wb " ) as file :
2021-09-15 17:11:15 +00:00
for chunk in image_req . iter_content ( 1024 ) :
file . write ( chunk )
2021-09-23 23:22:15 +00:00
post . thumburl = upload_ibb ( resize = True )
db . add ( post )
db . commit ( )
db . close ( )
2021-09-23 23:30:09 +00:00
return
2021-09-06 19:58:04 +00:00
2021-09-23 23:30:50 +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-09-21 21:54:44 +00:00
if request . content_length > 16 * 1024 * 1024 : abort ( 413 )
2021-07-21 01:12:26 +00:00
2021-09-19 13:11:34 +00:00
title = request . values . get ( " title " , " " )
url = request . values . 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-24 02:02:25 +00:00
repost = g . db . query ( Submission ) . options ( lazyload ( ' * ' ) ) . filter (
2021-09-24 02:00:11 +00:00
Submission . url . ilike ( url ) ,
2021-07-21 01:12:26 +00:00
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
2021-09-19 13:11:34 +00:00
else : return render_template ( " submit.html " , v = v , error = " Please enter a better title. " , title = title , url = url , body = request . values . get ( " body " , " " ) ) , 400
2021-07-31 05:28:05 +00:00
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-09-19 13:11:34 +00:00
else : render_template ( " submit.html " , v = v , error = " 500 character limit for titles. " , title = title [ : 500 ] , url = url , body = request . values . get ( " body " , " " ) ) , 400
2021-07-31 05:28:05 +00:00
2021-07-21 01:12:26 +00:00
parsed_url = urlparse ( url )
2021-09-19 13:11:34 +00:00
if not ( parsed_url . scheme and parsed_url . netloc ) and not request . values . get (
2021-07-21 01:12:26 +00:00
" 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
2021-09-19 13:11:34 +00:00
else : return render_template ( " submit.html " , v = v , error = " Please enter a url or some text. " , title = title , url = url , body = request . values . get ( " body " , " " ) ) , 400
2021-07-31 05:28:05 +00:00
2021-07-21 01:12:26 +00:00
# Force https for submitted urls
2021-09-19 13:11:34 +00:00
if request . values . get ( " url " ) :
2021-07-21 01:12:26 +00:00
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 = " "
2021-09-19 13:11:34 +00:00
body = request . values . get ( " body " , " " )
2021-07-21 01:12:26 +00:00
# check for duplicate
2021-09-24 02:02:25 +00:00
dup = g . db . query ( Submission ) . options ( lazyload ( ' * ' ) ) . filter (
2021-07-21 01:12:26 +00:00
Submission . author_id == v . id ,
Submission . deleted_utc == 0 ,
2021-09-24 02:00:11 +00:00
Submission . title == title ,
Submission . url == url ,
Submission . body == body
2021-07-21 01:12:26 +00:00
) . 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
2021-09-19 13:11:34 +00:00
else : return render_template ( " submit.html " , v = v , error = " ToS Violation " , title = title , url = url , body = request . values . get ( " body " , " " ) ) , 400
2021-08-01 04:24:46 +00:00
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-21 19:06:02 +00:00
try :
yt_id = re . match ( re . compile ( " ^.*(youtu.be \ /|v \ /|u \ / \ w \ /|embed \ /|watch \ ?v=|shorts \ /| \ &v=)([^# \ & \ ?]*).* " ) , url ) . group ( 2 )
2021-08-01 04:24:46 +00:00
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-09-21 19:06:02 +00:00
except : embed = None
2021-08-01 04:24:46 +00:00
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 ( ' * ' )
) . filter (
#or_(
# and_(
Submission . author_id == v . id ,
2021-09-24 02:00:11 +00:00
Submission . title . op ( ' <-> ' ) ( title ) < app . config [ " SPAM_SIMILARITY_THRESHOLD " ] ,
2021-07-21 01:12:26 +00:00
Submission . created_utc > cutoff
# ),
# and_(
2021-09-24 02:00:11 +00:00
# Submission.title.op('<->')(title) < app.config["SPAM_SIMILARITY_THRESHOLD"]/2,
2021-07-21 01:12:26 +00:00
# Submission.created_utc > cutoff
# )
#)
) . all ( )
if url :
similar_urls = g . db . query ( Submission ) . options (
lazyload ( ' * ' )
) . filter (
#or_(
# and_(
Submission . author_id == v . id ,
2021-09-24 02:00:11 +00:00
Submission . url . op ( ' <-> ' ) ( url ) < app . config [ " SPAM_URL_SIMILARITY_THRESHOLD " ] ,
2021-07-21 01:12:26 +00:00
Submission . created_utc > cutoff
# ),
# and_(
2021-09-24 02:00:11 +00:00
# Submission.url.op('<->')(url) < app.config["SPAM_URL_SIMILARITY_THRESHOLD"]/2,
2021-07-21 01:12:26 +00:00
# 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
2021-09-19 13:11:34 +00:00
else : return render_template ( " submit.html " , v = v , error = " 10000 character limit for text body. " , title = title , url = url , body = request . values . 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
2021-09-19 13:11:34 +00:00
else : return render_template ( " submit.html " , v = v , error = " 2048 character limit for URLs. " , title = title , url = url , body = request . values . get ( " body " , " " ) ) , 400
2021-07-21 01:12:26 +00:00
# render text
2021-09-17 15:52:00 +00:00
for i in re . finditer ( ' ^(https: \ / \ /.* \ .(png|jpg|jpeg|gif|webp|PNG|JPG|JPEG|GIF|WEBP|9999)) ' , body , re . MULTILINE ) :
2021-09-15 12:43:46 +00:00
if " wikipedia " not in i . group ( 1 ) : body = body . replace ( i . group ( 1 ) , f ' ![]( { i . group ( 1 ) } ) ' )
2021-09-22 22:27:09 +00:00
body = re . sub ( ' ([^ \n ]) \n ([^ \n ]) ' , r ' \ 1 \ n \ n \ 2 ' , body )
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
2021-09-24 19:41:08 +00:00
if len ( body_html ) > 20000 : abort ( 400 )
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
2021-09-19 13:11:34 +00:00
else : return render_template ( " submit.html " , v = v , error = reason , title = title , url = url , body = request . values . 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 )
2021-09-17 08:29:05 +00:00
badlink = g . db . query ( BadLink ) . options ( lazyload ( ' * ' ) ) . filter (
2021-07-21 01:12:26 +00:00
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
2021-09-19 13:11:34 +00:00
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 . values . get ( " body " , " " ) ) , 400
2021-07-21 01:12:26 +00:00
# check for embeddable video
domain = parsed_url . netloc
2021-09-19 13:11:34 +00:00
if v . paid_dues : club = bool ( request . values . get ( " club " , " " ) )
2021-09-17 15:44:00 +00:00
else : club = False
2021-07-21 01:12:26 +00:00
new_post = Submission (
2021-09-19 13:11:34 +00:00
private = bool ( request . values . get ( " private " , " " ) ) ,
2021-09-17 15:44:00 +00:00
club = club ,
2021-07-21 01:12:26 +00:00
author_id = v . id ,
2021-09-19 13:11:34 +00:00
over_18 = bool ( request . values . get ( " over_18 " , " " ) ) ,
2021-08-03 17:33:13 +00:00
app_id = v . client . application . id if v . client else None ,
2021-09-24 02:00:52 +00:00
is_bot = request . headers . get ( " X-User-Type " , " " ) . lower ( ) == " bot " ,
2021-09-24 02:00:11 +00:00
url = url ,
body = body ,
body_html = body_html ,
embed_url = embed ,
title = title ,
title_html = filter_title ( title )
2021-07-21 01:12:26 +00:00
)
g . db . add ( new_post )
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
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
2021-09-19 13:11:34 +00:00
# else: return render_template("submit.html", v=v, error=f"Image files only.", title=title, body=request.values.get("body", "")), 400
2021-09-05 16:53:18 +00:00
if not file . content_type . startswith ( ( ' image/ ' , ' video/ ' ) ) :
if request . headers . get ( " Authorization " ) : return { " error " : f " File type not allowed " } , 400
2021-09-19 13:11:34 +00:00
else : return render_template ( " submit.html " , v = v , error = f " File type not allowed. " , title = title , body = request . values . get ( " body " , " " ) ) , 400
2021-09-05 16:53:18 +00:00
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 ,
2021-09-19 13:11:34 +00:00
body = request . values . get ( " body " , " " )
2021-09-06 20:56:55 +00:00
) , 403
2021-09-05 16:53:18 +00:00
2021-10-01 06:26:59 +00:00
if file . content_type . startswith ( ' image/ ' ) : new_post . url = upload_ibb ( file = file )
2021-10-01 06:29:04 +00:00
elif file . content_type . startswith ( ' video/ ' ) :
file . save ( " video.mp4 " )
with open ( " video.mp4 " , ' rb ' ) as f :
2021-10-01 06:34:38 +00:00
new_post . url = requests . post ( ' https://catbox.moe/user/api.php ' , data = { ' userhash ' : CATBOX_KEY , ' reqtype ' : ' fileupload ' } , files = { ' fileToUpload ' : f } ) . text
2021-09-02 14:06:28 +00:00
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-14 14:27:18 +00:00
2021-09-23 23:22:15 +00:00
if ( new_post . url or request . files . get ( ' file ' ) ) and ( v . is_activated or request . headers . get ( ' cf-ipcountry ' ) != " T1 " ) :
2021-09-23 23:28:57 +00:00
gevent . spawn ( thumbnail_thread , new_post . id )
2021-07-21 01:12:26 +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 ]
2021-09-17 08:29:05 +00:00
user = g . db . query ( User ) . options ( lazyload ( ' * ' ) ) . filter_by ( username = username ) . first ( )
2021-07-21 01:12:26 +00:00
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-24 02:21:41 +00:00
if " rdrama " in request . host and " ivermectin " in new_post . 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 )
2021-09-24 02:21:41 +00:00
body = VAXX_MSG . format ( username = v . username )
body_md = CustomRenderer ( ) . render ( mistletoe . Document ( body ) )
body_jannied_html = sanitize ( body_md )
2021-09-01 20:51:47 +00:00
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 ,
2021-09-24 02:21:41 +00:00
distinguish_level = 6 ,
body_html = body_jannied_html ,
body = body ,
2021-09-01 20:51:47 +00:00
)
g . db . add ( c_jannied )
g . db . flush ( )
n = Notification ( comment_id = c_jannied . id , user_id = v . id )
g . db . add ( n )
2021-09-24 02:21:41 +00:00
if v . agendaposter and " trans lives matter " not in new_post . body_html . lower ( ) :
2021-07-21 21:36:35 +00:00
new_post . is_banned = True
new_post . ban_reason = " ToS Violation "
g . db . add ( new_post )
2021-09-24 02:21:41 +00:00
body = AGENDAPOSTER_MSG . format ( username = v . username )
body_md = CustomRenderer ( ) . render ( mistletoe . Document ( body ) )
body_jannied_html = sanitize ( body_md )
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 ,
2021-09-24 02:21:41 +00:00
distinguish_level = 6 ,
body_html = body_jannied_html ,
body = body ,
2021-07-21 23:32:40 +00:00
)
2021-07-21 21:36:35 +00:00
g . db . add ( c_jannied )
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
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 )
2021-09-24 02:21:41 +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-08-27 22:10:03 +00:00
body_html = body_html ,
2021-09-24 02:21:41 +00:00
body = body ,
)
g . db . add ( c )
2021-08-27 22:10:03 +00:00
g . db . flush ( )
2021-09-24 02:21:41 +00:00
2021-08-27 22:10:03 +00:00
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-18 00:32:36 +00:00
cache . delete_memoized ( frontlist )
2021-09-14 13:33:10 +00:00
cache . delete_memoized ( User . userpagelisting )
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-09-16 17:02:58 +00:00
g . db . commit ( )
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
2021-09-23 17:28:30 +00:00
post . stickied = None
2021-07-21 01:12:26 +00:00
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-16 17:02:58 +00:00
g . db . commit ( )
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-16 17:02:58 +00:00
g . db . commit ( )
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-09-17 08:29:05 +00:00
comment = g . db . query ( Comment ) . options ( lazyload ( ' * ' ) ) . 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 ( )
2021-09-16 17:02:58 +00:00
g . db . commit ( )
2021-09-08 11:05:31 +00:00
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-16 17:02:58 +00:00
g . db . commit ( )
2021-09-08 11:05:31 +00:00
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 )
2021-09-24 16:18:55 +00:00
save = g . db . query ( SaveRelationship ) . options ( lazyload ( ' * ' ) ) . filter_by ( user_id = v . id , submission_id = post . id , type = 1 ) . first ( )
2021-07-21 01:12:26 +00:00
2021-09-24 16:18:55 +00:00
if not save :
new_save = SaveRelationship ( user_id = v . id , submission_id = post . id , type = 1 )
g . db . add ( new_save )
g . db . commit ( )
2021-09-16 17:02:58 +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 )
2021-09-24 16:18:55 +00:00
save = g . db . query ( SaveRelationship ) . options ( lazyload ( ' * ' ) ) . filter_by ( user_id = v . id , submission_id = post . id , type = 1 ) . first ( )
2021-07-21 01:12:26 +00:00
2021-09-17 08:55:55 +00:00
if save :
g . db . delete ( save )
g . db . commit ( )
2021-09-16 17:02:58 +00:00
2021-09-08 11:05:31 +00:00
return { " message " : " Post unsaved! " }