Example #1
0
def edit(u=None,cid=0):
	try:
		db = open_db()
		
		# Query comment from id
		comment = db.query(Comment).filter_by(id=cid).first()
		if comment is None:
			abort(404)
		if comment.user_id != u.id and u.is_admin == False:
			abort(403)
		
		if request.method == 'POST':
			body = request.form.get('body')
			
			if len(body) == 0:
				raise XaieconException(gettext('Body too short'))
			
			# Update comment
			db.query(Comment).filter_by(id=cid).update({
				'body':body,
				'body_html':md(body)})
			db.commit()
			
			db.close()
			cache.delete_memoized(view)
			return redirect(f'/comment/view/{cid}')
		else:
			db.close()
			return render_template('post/edit_comment.html',u=u,title='Edit comment',comment=comment)
	except XaieconException as e:
		return render_template('user_error.html',u=u,title = 'Whoops!',err=e)
Example #2
0
def mark_all_as_read(u=None):
	db = open_db()
	db.query(Notification).filter_by(user_id=u.id).update({'is_read':True})
	db.commit()
	db.close()
	cache.delete_memoized(notifications)
	return redirect('/user/notifications')
Example #3
0
def csam_check_post(uid: int, pid: int):
	db = open_db()

	post = db.query(Post).filter_by(id=pid).first()

	# Nothing to scan
	if post.is_link == False and post.is_image == False:
		return

	headers = {'User-Agent':'xaiecon-csam-check'}

	# Check link of post
	if post.is_link == True:
		for i in range(10):
			x = requests.get(post.link_url,headers=headers)
			if x.status_code in [200, 451]:
				break
			else:
				time.sleep(10)

	# And check image if it has one...
	if post.is_image == True:
		for i in range(10):
			x = requests.get(f'https://{os.environ.get("DOMAIN_NAME")}/post/thumb/{post.id}',headers=headers)
			if x.status_code in [200, 451]:
				break
			else:
				time.sleep(10)
		for i in range(10):
			x = requests.get(f'https://{os.environ.get("DOMAIN_NAME")}/post/image/{post.id}',headers=headers)
			if x.status_code in [200, 451]:
				break
			else:
				time.sleep(10)

	# If status code is not 451, else...
	if x.status_code != 451:
		return

	print(f'Offensive post {post.id} found!')

	# Ban user
	
	user = db.query(User).filter_by(id=post.user_id).first()
	db.query(User).filter_by(id=post.user_id).update({
		'ban_reason':'CSAM Automatic Removal',
		'is_banned':True})
	db.commit()
	db.refresh(user)
	
	db.close()
	cache.delete_memoized(view)
	return
Example #4
0
def vote(u=None,pid=0):
	db = open_db()
	try:
		val = int(request.values.get('value','1'))
		
		if pid is None:
			abort(404)
		if val not in [-1,1]:
			abort(400)
		
		post = db.query(Post).filter_by(id=pid).first()
		if post is None:
			abort(404)
		
		user = db.query(User).filter_by(id=post.user_id).first()
		vote = db.query(Vote).filter_by(user_id=u.id,post_id=pid).first()
		
		if vote is not None and vote.value == val:
			db.query(User).filter_by(id=post.user_id).update({
				'net_points':user.net_points-vote.value})
			db.query(Vote).filter_by(user_id=u.id,post_id=pid).delete()
		else:
			db.query(Vote).filter_by(user_id=u.id,post_id=pid).delete()
			# Create vote relation
			vote = Vote(user_id=u.id,post_id=post.id,value=val)
			db.add(vote)
			
			db.query(User).filter_by(id=post.user_id).update({
				'net_points':user.net_points+val})
		
		# Update vote count
		downvotes = db.query(Vote).filter_by(post_id=pid,value=-1).count()
		upvotes = db.query(Vote).filter_by(post_id=pid,value=1).count()
		db.query(Post).filter_by(id=pid).update({
			'downvote_count':downvotes,
			'upvote_count':upvotes,
			'total_vote_count':upvotes-downvotes})
		
		db.commit()
		
		db.close()
		
		cache.delete_memoized(ballot)
		cache.delete_memoized(view,pid=pid)
		cache.delete_memoized(list_posts)
		cache.delete_memoized(list_nuked)
		cache.delete_memoized(list_feed)
		return '',200
	except XaieconException as e:
		db.rollback()
		db.close()
		return jsonify({'error':e}),400
Example #5
0
def nuke(u=None,cid=0):
	db = open_db()
	try:
		comment = db.query(Comment).filter_by(id=cid).first()
		if comment is None:
			abort(404)
		
		# User must be also mod of the post's origin board
		# Increment number of comments
		post_comment = None
		post_cid = cid
		post = None
		while post is None:
			post_comment = db.query(Comment).filter_by(id=post_cid).first()
			if post_comment.post_id is None:
				post_cid = post_comment.comment_id
			else:
				post = db.query(Post).filter_by(id=post_comment.post_id).options(joinedload('*')).first()
				if post is None:
					abort(404)
				break
		board = db.query(Board).filter_by(id=post.board_id).first()
		
		# Check that post is not already nuked and that user mods
		# the guild
		if board is None:
			raise XaieconException('Post cannot be nuked because it is not in any board')
		if comment.is_nuked == True:
			raise XaieconException('Post already nuked/deleted by user or someone else')
		if not u.mods(board.id) and u.is_admin == False:
			raise XaieconException('You do not mod the origin board')
		
		# "Nuke" post
		db.query(Comment).filter_by(id=cid).update({'is_nuked':True,'nuker_id':u.id})
		db.commit()
		
		db.close()
		
		cache.delete_memoized(view_p,pid=post.id)
		cache.delete_memoized(view,cid=cid)
		cache.delete_memoized(list_posts)
		cache.delete_memoized(list_nuked)
		cache.delete_memoized(list_feed)
		
		send_admin_notification(f'Comment with id {cid} has been nuked! Review it [here](/comment/view/{cid}) and [do a final nuke](/admin/comment/nuke/{cid}) if you consider it nescesary.')
		
		return redirect(f'/comment/view/{cid}')
	except XaieconException as e:
		db.rollback()
		db.close()
		return render_template('user_error.html',u=u,title = 'Whoops!',err=e)
Example #6
0
def unnuke(u=None,pid=0):
	db = open_db()
	try:
		if u.is_admin == False:
			raise XaieconException('Only admins can un-nuke')
		
		post = db.query(Post).filter_by(id=pid).first()
		if post is None:
			abort(404)
		
		# Check that post is not already nuked and that user mods
		# the guild
		if post.is_deleted == True or post.is_nuked == False:
			raise XaieconException('Post already deleted or has been unnuked by user or someone else')
		
		# "Un-Nuke" post
		db.query(Post).filter_by(id=pid).update({'is_nuked':False})
		db.commit()
		
		db.close()
		
		cache.delete_memoized(view,pid=pid)
		cache.delete_memoized(list_posts)
		cache.delete_memoized(list_nuked)
		cache.delete_memoized(list_feed)
		
		return redirect(f'/post/view/{pid}')
	except XaieconException as e:
		db.rollback()
		db.close()
		return render_template('user_error.html',u=u,title = 'Whoops!',err=e)
Example #7
0
def admin_nuke(u=None,cid=0):
	db = open_db()
	
	comment = db.query(Comment).filter_by(id=cid).first()
	if comment is None:
		abort(404)
	
	# Delete all stuff of the comment
	db.query(Comment).filter_by(id=cid).update({
		'body':gettext('[deleted by nuking]'),
		'body_html':gettext('[deleted by nuking]')})
	db.commit()
	
	# Kill user
	user = db.query(User).filter_by(id=comment.user_id).first()
	db.query(User).filter_by(id=comment.user_id).update({
		'ban_reason':'ToS break. Nuking.',
		'is_banned':True})
	db.commit()
	db.refresh(user)
	
	db.close()
	
	# Delete caching
	cache.delete_memoized(view,cid=cid)
	cache.delete_memoized(list_posts)
	cache.delete_memoized(list_nuked)
	cache.delete_memoized(list_feed)
	return '',200
Example #8
0
def delete(u=None,cid=0):
	db = open_db()
	
	# Query comment from id
	comment = db.query(Comment).filter_by(id=cid).first()
	if comment is None:
		abort(404)
	if comment.user_id != u.id and u.is_admin == False:
		abort(403)
	
	# Update comment
	db.query(Comment).filter_by(id=cid).update({
		'body':gettext('[deleted by user]'),
		'body_html':gettext('[deleted by user]')})
	db.commit()
	
	db.close()
	cache.delete_memoized(view)
	return redirect(f'/comment/view/{cid}')
Example #9
0
def view(u=None,pid=0):
	db = open_db()
	
	# Query post from database
	post = db.query(Post).filter_by(id=pid).options(joinedload('*')).first()
	if post is None:
		abort(404)
	# Dont let people see nsfw
	if post.is_nsfw == True and u.is_nsfw == False:
		abort(403)
	
	# Add one view
	if u is not None:
		if db.query(View).filter_by(user_id=u.id,post_id=pid).first() is None:
			view = View(user_id=u.id,post_id=pid)
			db.add(view)
			db.query(Post).filter_by(id=pid).update({'views':post.views+1})
			db.commit()

	comment = db.query(Comment).filter_by(post_id=post.id).options(joinedload('*')).order_by(desc(Comment.id)).all()
	
	# This is how we get replies, pardon for so many cringe
	comments = []

	# First add the top comment(s)
	for c in comment:
		c.depth_level = 1
		comments.append(c)

		# Obtain comments that reference the current comment (top)
		comms = db.query(Comment).filter_by(comment_id=c.id).options(joinedload('*')).all()
		if comms is not None:
			# Obtain the comments of comments
			for d in comms:
				d.depth_level = 2
				ecomms = db.query(Comment).filter_by(comment_id=d.id).options(joinedload('*')).all()
				
				comments.append(d)
				for l in ecomms:
					l.depth_level = 3

					# Deepest comments, check if they have even more children
					if db.query(Comment).filter_by(comment_id=l.id).options(joinedload('*')).first() is not None:
						l.more_children = True

					comments.append(l)
	
	ret = render_template('post/details.html',u=u,title=post.title,post=post,comment=comments)
	
	db.close()
	
	cache.delete_memoized(list_posts)
	cache.delete_memoized(list_nuked)
	cache.delete_memoized(list_feed)
	
	return ret
Example #10
0
def unhide(u=None,cid=0):
	db = open_db()
	# Obtain boardinfo
	post_comment = None
	post_cid = cid
	post = None
	while post is None:
		post_comment = db.query(Comment).filter_by(id=post_cid).first()
		if post_comment.post_id is None:
			post_cid = post_comment.comment_id
		else:
			post = db.query(Post).filter_by(id=post_comment.post_id).options(joinedload('*')).first()
			if post is None:
				abort(404)
			break
	if u.mods(post.board_id) == False and u.is_admin == False:
		abort(403)
	db.query(Comment).filter_by(id=cid).update({'is_hidden':False})
	db.close()
	
	cache.delete_memoized(view)
	cache.delete_memoized(view_p,pid=post.id)
	
	return redirect(f'/comment/view/{cid}')
Example #11
0
def yank(u=None,pid=0):
	db = open_db()
	try:
		if request.method == 'POST':
			bid = request.values.get('bid')
			
			post = db.query(Post).filter_by(id=pid).first()
			
			# User must be also mod of the post's origin board
			# Or the post must not have a bid
			board = db.query(Board).filter_by(id=post.board_id).first()

			# If post is standalone or baord is not exists then just skip the
			# auth
			if board is not None or board.id == 1:
				if not u.mods(board.id) and u.is_admin == False:
					raise XaieconException('You do not mod the origin board')
				
			# Check that user mods the board he is trying to yank to
			if not u.mods(bid) and u.is_admin == False:
				raise XaieconException('You do not mod the target board')
			
			# Change post's bid
			board = db.query(Board).filter_by(id=bid).first()
			db.query(Post).filter_by(id=pid).update({'board_id':board.id})
			db.commit()
			
			db.close()
			
			cache.delete_memoized(view,pid=pid)
			cache.delete_memoized(list_posts)
			cache.delete_memoized(list_nuked)
			cache.delete_memoized(list_feed)
			
			return redirect(f'/post/view/{pid}')
		else:
			boards = db.query(Board).filter_by(user_id=u.id).options(joinedload('user_info')).all()
			post = db.query(Post).filter_by(id=pid).first()
			db.close()
			return render_template('post/yank.html',u=u,title='Yank post',post=post,boards=boards)
	except XaieconException as e:
		db.rollback()
		db.close()
		return render_template('user_error.html',u=u,title = 'Whoops!',err=e)
Example #12
0
def admin_nuke(u=None,pid=0):
	db = open_db()
	
	post = db.query(Post).filter_by(id=pid).first()
	if post is None:
		abort(404)
	
	# Remove old image
	try:
		os.remove(os.path.join('user_data',post.image_file))
		os.remove(os.path.join('user_data',post.thumb_file))
	except FileNotFoundError:
		pass
	
	# Delete all stuff of the post
	db.query(Post).filter_by(id=pid).update({
		'is_deleted':True,
		'body':'[deleted by user]',
		'body_html':'[deleted by user]',
		'is_link':False,
		'is_image':False,
		'image_file':'',
		'thumb_file':'',
		'link_url':''})
	db.commit()
	
	# Kill user
	user = db.query(User).filter_by(id=post.user_id).first()
	db.query(User).filter_by(id=post.user_id).update({
		'ban_reason':'ToS breaking. Nuking',
		'is_banned':True})
	db.commit()
	db.refresh(user)
	
	db.close()
	
	# Delete caching
	cache.delete_memoized(view,pid=pid)
	cache.delete_memoized(list_posts)
	cache.delete_memoized(list_nuked)
	cache.delete_memoized(list_feed)
	return '',200
Example #13
0
def vote(u=None,cid=0):
	try:
		val = int(request.values.get('value'))
		
		if cid is None or val is None or val not in [-1,1]:
			abort(400)
		
		db = open_db()
		
		vote = db.query(Vote).filter_by(user_id=u.id,comment_id=cid).first()
		comment = db.query(Comment).filter_by(id=cid).first()
		
		if comment is None:
			abort(404)
		
		# Delete previous vote
		db.query(Vote).filter_by(user_id=u.id,comment_id=cid).delete()
		
		if vote is not None and vote.value != val:
			# Create vote relation
			vote = Vote(user_id=u.id,comment_id=cid,value=val)
			db.add(vote)
		
		# Update vote count
		downvotes = db.query(Vote).filter_by(comment_id=cid,value=-1).count()
		upvotes = db.query(Vote).filter_by(comment_id=cid,value=1).count()
		db.query(Post).filter_by(id=cid).update({
			'downvote_count':downvotes,
			'upvote_count':upvotes,
			'total_vote_count':upvotes-downvotes})
		
		db.commit()
		
		db.close()
		
		cache.delete_memoized(view_p)
		cache.delete_memoized(list_posts)
		cache.delete_memoized(list_nuked)
		cache.delete_memoized(list_feed)
		return '',200
	except XaieconException as e:
		return jsonify({'error':e}),400
Example #14
0
def delete(u=None,pid=0):
	db = open_db()
	try:
		post = db.query(Post).filter_by(id=pid).first()
		if post == None:
			abort(404)

		if u.id != post.user_id and u.is_admin == False:
			raise XaieconException('User is not authorized')

		# Remove old image
		if post.is_image == True:
			try:
				os.remove(os.path.join('user_data',post.image_file))
				os.remove(os.path.join('user_data',post.thumb_file))
			except FileNotFoundError:
				pass
		
		# Set is_deleted to true
		db.query(Post).filter_by(id=pid).update({
			'is_deleted':True,
			'body':'[deleted by user]',
			'body_html':'[deleted by user]',
			'is_link':False,
			'is_image':False,
			'image_file':'',
			'thumb_file':'',
			'link_url':''})
		db.commit()
		db.close()
		
		cache.delete_memoized(view,pid=pid)
		cache.delete_memoized(list_posts)
		cache.delete_memoized(list_nuked)
		cache.delete_memoized(list_feed)
		
		return redirect(f'/post/view/{pid}')
	except XaieconException as e:
		db.rollback()
		db.close()
		return jsonify({'error':e}),400
Example #15
0
def kick(u=None,pid=0):
	db = open_db()
	try:
		if request.method == 'POST':
			post = db.query(Post).filter_by(id=pid).first()
			
			if post is None:
				abort(404)
			
			# User must be also mod of the post's origin board
			board = db.query(Board).filter_by(id=post.board_id).first()
			
			# Check that post is not already kicked and that user mods
			# the guild
			if board is None:
				raise XaieconException('Post cannot be kicked because it is not in any board')
			if not u.mods(board.id) and u.is_admin == False:
				raise XaieconException('You do not mod the origin board')
			
			# Change post's bid to general waters
			db.query(Post).filter_by(id=pid).update({'board_id':1})
			db.commit()
			
			db.close()
			
			cache.delete_memoized(view,pid=pid)
			cache.delete_memoized(list_posts)
			cache.delete_memoized(list_nuked)
			cache.delete_memoized(list_feed)
			
			return redirect(f'/post/view/{pid}')
		else:
			post = db.query(Post).filter_by(id=pid).first()
			db.close()
			return render_template('post/kick.html',u=u,title='Kick post',post=post)
	except XaieconException as e:
		db.rollback()
		db.close()
		return render_template('user_error.html',u=u,title = 'Whoops!',err=e)
Example #16
0
def write(u=None):
	db = open_db()
	try:
		if request.method == 'POST':
			body = request.form.get('body','')
			title = request.form.get('title')
			keywords = request.form.get('keywords')
			link = request.form.get('link','')
			bid = request.form.get('bid')
			category = int(request.values.get('category','0'))
			show_votes = strtobool(request.form.get('show_votes','False'))
			is_nsfw = strtobool(request.form.get('is_nsfw','False'))

			if len(title) > 255:
				raise XaieconException('Too long title')
			if len(body) > 16000:
				raise XaieconException('Too long body')
			
			category = db.query(Category).filter_by(id=category).first()
			if category is None:
				raise XaieconException('Not a valid category')
			board = db.query(Board).filter_by(id=bid).first()
			if board is None:
				raise XaieconException('Invalid board')
			bid = board.id

			if u.is_banned_from_board(bid) == True:
				raise XaieconException(f'You\'re banned from /b/{board.name}')
			
			is_link = False
			embed_html = ''
			if link != '':
				is_link = True

				embed = obtain_embed_url(link)
				if embed is not None:
					embed_html = f'<iframe width="560" height="315" src="{embed}" allowfullscreen frameborder=\'0\'></iframe>'

			if body == '' and is_link == False:
				raise XaieconException('Empty body')
			if title is None or title == '':
				raise XaieconException('Empty title')
			
			body_html = md(body)
			
			post = Post(keywords=keywords,
						title=title,
						body=body,
						link_url=link,
						is_link=is_link,
						user_id=u.id,
						is_nsfw=is_nsfw,
						downvote_count=0,
						upvote_count=0,
						total_vote_count=0,
						category_id=category.id,
						board_id=bid,
						embed_html=embed_html,
						body_html=body_html,
						show_votes=show_votes)
			
			file = request.files['image']
			if file:
				try:
					# Build paths and filenames
					image_filename = secure_filename(f'{secrets.token_hex(12)}.jpeg')
					image_filepath = os.path.join('user_data',image_filename)
	
					thumb_filename = secure_filename(f'thumb_{image_filename}')
					thumb_filepath = os.path.join('user_data',thumb_filename)
	
					# Save full image file
					file.save(image_filepath)
	
					# Create thumbnail for image
					image = PIL.Image.open(image_filepath)
					image = image.convert('RGB')
					image.thumbnail((128,128))
					image.save(thumb_filepath)
	
					post.image_file = image_filename
					post.thumb_file = thumb_filename
	
					post.is_image = True
					post.is_thumb = True
				except PIL.UnidentifiedImageError:
					pass
			else:
				post.is_image = False
				if is_link == True:
					img = obtain_post_thumb(link)
					if img is not None:
						thumb_filename = secure_filename(f'thumb_{secrets.token_hex(12)}.jpeg')
						thumb_filepath = os.path.join('user_data',thumb_filename)
						
						timg = img.convert('RGB')
						timg.resize((128,128))
						timg.save(thumb_filepath)
						
						post.thumb_file = thumb_filename
						post.is_thumb = True
			
			db.add(post)
			db.commit()
			
			db.refresh(post)
			
			csam_thread = threading.Thread(target=csam_check_post, args=(u.id,post.id,))
			csam_thread.start()
			
			notif_msg = f'# {post.title}\n\rBy [/u/{u.username}](/user/view/{u.id}) on [/b/{board.name}](/board/view/{board.id})\n\r{post.body}'
			
			# Alert boardmaster of the posts in the guild
			if board.user_id != u.id:
				send_notification(notif_msg,board.user_id)
			
			# Notify followers
			follows = db.query(UserFollow).filter_by(target_id=u.id,notify=True).all()
			for f in follows:
				if f.user_id != u.id:
					send_notification(notif_msg,f.user_id)
			
			ping = body.find('@everyone')
			if ping != -1 and u.is_admin == True:
				users = db.query(User).all()
				for us in users:
					if us.id != u.id:
						send_notification(notif_msg,us.id)
			
			ping = body.find('@here')
			if ping != -1 and u.mods(post.board_id):
				subs = db.query(BoardSub).filter_by(board_id=post.board_id).all()
				for s in subs:
					if s.user_id != u.id:
						send_notification(notif_msg,s.user_id)
			
			for m in re.finditer(r'([u][\/]|[@])([a-zA-Z0-9#][^ ,.;:\n\r\t<>\/\'])*\w+',body):
				m = m.group(0)
				try:
					name = re.split(r'([u][\/]|[@])',m)[2]
					tag = name.split('#')
					
					# direct mention
					if len(tag) > 1:
						uid = int(tag[1])
						user = db.query(User).filter_by(id=uid).first()
						if user is None:
							raise IndexError
						send_notification(notif_msg,user.id)
					else:
						users = db.query(User).filter_by(username=name).all()
						if users is None:
							raise IndexError
						for user in users:
							send_notification(notif_msg,user.id)
				except IndexError:
					pass
			
			db.close()
			
			# Mess with everyone's feed
			cache.delete_memoized(list_posts)
			cache.delete_memoized(list_nuked)
			cache.delete_memoized(list_feed)
			
			return redirect(f'/post/view/{post.id}')
		else:
			board = db.query(Board).filter_by(is_banned=False).options(joinedload('user_info')).all()
			categories = db.query(Category).all()
			db.close()
			return render_template('post/write.html',u=u,title='New post',boards=board,categories=categories)
	except XaieconException as e:
		db.rollback()
		db.close()
		return render_template('user_error.html',u=u,title = 'Whoops!',err=e)
Example #17
0
def edit(u=None,pid=0):
	db = open_db()
	try:
		post = db.query(Post).filter_by(id=pid).first()
		if post is None:
			abort(404)
		
		if u.id != post.user_id and u.is_admin == False:
			raise XaieconException('User is not authorized')
		
		if request.method == 'POST':
			body = request.form.get('body')
			title = request.form.get('title')
			keywords = request.form.get('keywords')
			link = request.form.get('link','')
			category = int(request.form.get('category','0'))
			is_nsfw = strtobool(request.form.get('is_nsfw','False'))

			if len(title) > 255:
				raise XaieconException('Too long title')

			category = db.query(Category).filter_by(id=category).first()
			if category is None:
				raise XaieconException('Not a valid category')
			
			is_link = False
			embed_html = ''
			if link != '':
				is_link = True

				embed = obtain_embed_url(link)
				if embed is not None:
					embed_html = f'<iframe width="560" height="315" src="{embed}" allowfullscreen frameborder=\'0\'></iframe>'
			
			if body == None or body == '':
				raise XaieconException('Empty body')
			if title == None or title == '':
				raise XaieconException('Empty title')

			body_html = ''
			
			# Remove old image
			try:
				if post.is_image == True:
					os.remove(os.path.join('user_data',post.image_file))
					os.remove(os.path.join('user_data',post.thumb_file))
			except FileNotFoundError:
				pass
			
			file = request.files['image']
			if file:
				try:
					# Build paths and filenames
					image_filename = secure_filename(f'{secrets.token_hex(12)}.jpeg')
					image_filepath = os.path.join('user_data',image_filename)

					thumb_filename = secure_filename(f'thumb_{image_filename}')
					thumb_filepath = os.path.join('user_data',thumb_filename)

					# Save full image file
					file.save(image_filepath)

					# Create thumbnail for image
					image = PIL.Image.open(image_filepath)
					image = image.convert('RGB')
					image.resize((128,128))
					image.save(thumb_filepath)

					db.query(Post).filter_by(id=pid).update({
						'image_file':image_filename,
						'thumb_file':thumb_filename,
						'is_image':True,
						'is_thumb':True})
				except PIL.UnidentifiedImageError:
					# Failure creating image!
					db.query(Post).filter_by(id=pid).update({
						'is_image':False,
						'is_thumb':False})
			else:
				db.query(Post).filter_by(id=pid).update({
					'is_image':False,
					'is_thumb':False})
				if is_link == True:
					img = obtain_post_thumb(link)
					if img is not None:
						thumb_filename = secure_filename(f'thumb_{secrets.token_hex(12)}.jpeg')
						thumb_filepath = os.path.join('user_data',thumb_filename)
						
						img = img.convert('RGB')
						img.thumbnail((128,128))
						img.save(thumb_filepath)
						
						db.query(Post).filter_by(id=pid).update({
							'is_thumb':True,
							'thumb_file':thumb_filename})
			
			body_html = md(body)
			
			# Update post entry on database
			db.query(Post).filter_by(id=pid).update({
						'keywords':keywords,
						'body':body,
						'body_html':body_html,
						'is_link':is_link,
						'is_nsfw':is_nsfw,
						'title':title,
						'link_url':link,
						'category_id':category.id,
						'body_html':body_html,
						'embed_html':embed_html})
			db.commit()

			csam_thread = threading.Thread(target=csam_check_post, args=(u.id,post.id,))
			csam_thread.start()
			
			db.close()
			
			cache.delete_memoized(view,pid=pid)
			cache.delete_memoized(list_posts)
			cache.delete_memoized(list_nuked)
			cache.delete_memoized(list_feed)
			
			return redirect(f'/post/view/{pid}')
		else:
			categories = db.query(Category).all()
			db.close()
			return render_template('post/edit.html',u=u,title='Edit',post=post,categories=categories)
	except XaieconException as e:
		db.rollback()
		db.close()
		return render_template('user_error.html',u=u,title = 'Whoops!',err=e)
Example #18
0
def create(u=None,pid=0):
	try:
		db = open_db()
		
		body = request.form.get('body')
		
		if len(body) == 0:
			raise XaieconException('Body too short')
		
		# Post exists in first place?
		post = db.query(Post).filter_by(id=pid).options(joinedload('*')).first()
		if post is None:
			abort(404)
		
		# Add comment
		comment = Comment(body=body,body_html=md(body),user_id=u.id,post_id=pid)
		db.add(comment)
		
		# Increment number of comments
		db.query(Post).filter_by(id=pid).update({'number_comments':post.number_comments+1})
		db.commit()
		
		notif_msg = f'Comment by [/u/{comment.user_info.username}](/user/view/{post.user_info.id}) on [/b/{post.board_info.name}](/board/view/{post.board_info.id}) in post ***{post.title}*** [View](/comment/view/{comment.id})\n\r{comment.body}'
		
		idlist = []
		if post.user_id != u.id and post.user_id not in idlist:
				idlist.append(post.user_id)
		
		# Notify followers
		follows = db.query(UserFollow).filter_by(target_id=u.id,notify=True).all()
		for f in follows:
			if f.user_id != u.id and f.user_id not in idlist:
				idlist.append(f.user_id)
		
		# Notify post poster
		if post.user_id != u.id and post.user_id not in idlist:
				idlist.append(post.user_id)
		
		# Notify commenter
		if comment.user_id != u.id and comment.user_id not in idlist:
				idlist.append(comment.user_id)

		for id in idlist:
			send_notification(notif_msg,id)

		ping = body.find('@everyone')
		if ping != -1 and u.is_admin == True:
			users = db.query(User).all()
			for us in users:
				if us.id != u.id:
					send_notification(notif_msg,us.id)
		
		ping = body.find('@here')
		if ping != -1 and u.mods(post.board_id):
			subs = db.query(BoardSub).filter_by(board_id=post.board_id).all()
			for s in subs:
				if s.user_id != u.id:
					send_notification(notif_msg,s.user_id)
		
		for m in re.finditer(r'([u][\/]|[@])([a-zA-Z0-9#][^ ,.;:\n\r\t<>\/\'])*\w+',body):
			m = m.group(0)
			print(m)
			try:
				name = re.split(r'([u][\/]|[@])',m)[2]
				tag = name.split('#')
				
				# direct mention
				if len(tag) > 1:
					uid = int(tag[1])
					user = db.query(User).filter_by(id=uid).first()
					if user is None:
						raise IndexError
					send_notification(notif_msg,user.id)
				else:
					users = db.query(User).filter_by(username=name).all()
					if users is None:
						raise IndexError
					for user in users:
						send_notification(notif_msg,user.id)
			except IndexError:
				pass
		
		db.close()
		
		cache.delete_memoized(view_p)
		cache.delete_memoized(list_posts)
		cache.delete_memoized(list_nuked)
		cache.delete_memoized(list_feed)
		
		return redirect(f'/post/view/{pid}')
	except XaieconException as e:
		return render_template('user_error.html',u=u,title = 'Whoops!',err=e)