2024-09-20 16:06:08 +00:00
|
|
|
from app import cache
|
2025-01-18 17:56:09 +00:00
|
|
|
from app.api.alpha.views import post_view, post_report_view
|
2025-01-14 13:54:17 +00:00
|
|
|
from app.api.alpha.utils.validators import required, integer_expected, boolean_expected, string_expected
|
2025-01-22 00:51:41 +00:00
|
|
|
from app.constants import POST_TYPE_ARTICLE, POST_TYPE_LINK, POST_TYPE_IMAGE, POST_TYPE_VIDEO, POST_TYPE_POLL
|
2024-09-20 16:06:08 +00:00
|
|
|
from app.models import Post, Community, CommunityMember, utcnow
|
2025-01-20 05:01:31 +00:00
|
|
|
from app.shared.post import vote_for_post, bookmark_the_post, remove_the_bookmark_from_post, toggle_post_notification, make_post, edit_post, \
|
|
|
|
delete_post, restore_post, report_post, lock_post, sticky_post, mod_remove_post, mod_restore_post
|
2025-01-15 01:26:27 +00:00
|
|
|
from app.utils import authorise_api_user, blocked_users, blocked_communities, blocked_instances, community_ids_from_instances, is_image_url, is_video_url
|
2024-09-20 16:06:08 +00:00
|
|
|
|
|
|
|
from datetime import timedelta
|
|
|
|
from sqlalchemy import desc
|
|
|
|
|
|
|
|
|
|
|
|
@cache.memoize(timeout=3)
|
2025-01-22 00:51:41 +00:00
|
|
|
def cached_post_list(type, sort, user_id, community_id, community_name, person_id, query='', search_type='Posts'):
|
2024-09-20 16:06:08 +00:00
|
|
|
if type == "All":
|
|
|
|
if community_name:
|
2024-09-22 09:56:17 +00:00
|
|
|
name, ap_domain = community_name.split('@')
|
|
|
|
posts = Post.query.filter_by(deleted=False).join(Community, Community.id == Post.community_id).filter_by(show_all=True, name=name, ap_domain=ap_domain)
|
2024-09-20 16:06:08 +00:00
|
|
|
elif community_id:
|
|
|
|
posts = Post.query.filter_by(deleted=False).join(Community, Community.id == Post.community_id).filter_by(show_all=True, id=community_id)
|
|
|
|
elif person_id:
|
|
|
|
posts = Post.query.filter_by(deleted=False, user_id=person_id)
|
|
|
|
else:
|
|
|
|
posts = Post.query.filter_by(deleted=False).join(Community, Community.id == Post.community_id).filter_by(show_all=True)
|
|
|
|
elif type == "Local":
|
|
|
|
posts = Post.query.filter_by(deleted=False).join(Community, Community.id == Post.community_id).filter_by(ap_id=None)
|
2024-10-12 11:14:41 +00:00
|
|
|
elif type == "Popular":
|
|
|
|
posts = Post.query.filter_by(deleted=False).join(Community, Community.id == Post.community_id).filter(Community.show_popular == True, Post.score > 100)
|
2024-09-20 16:06:08 +00:00
|
|
|
elif type == "Subscribed" and user_id is not None:
|
|
|
|
posts = Post.query.filter_by(deleted=False).join(CommunityMember, Post.community_id == CommunityMember.community_id).filter_by(is_banned=False, user_id=user_id)
|
|
|
|
else:
|
|
|
|
posts = Post.query.filter_by(deleted=False)
|
|
|
|
|
2025-01-22 00:51:41 +00:00
|
|
|
# change when polls are supported
|
|
|
|
posts = posts.filter(Post.type != POST_TYPE_POLL)
|
|
|
|
|
2025-01-23 05:07:37 +00:00
|
|
|
if user_id and user_id != person_id:
|
2024-10-05 20:55:04 +00:00
|
|
|
blocked_person_ids = blocked_users(user_id)
|
|
|
|
if blocked_person_ids:
|
|
|
|
posts = posts.filter(Post.user_id.not_in(blocked_person_ids))
|
2024-10-07 13:57:19 +00:00
|
|
|
blocked_community_ids = blocked_communities(user_id)
|
|
|
|
if blocked_community_ids:
|
|
|
|
posts = posts.filter(Post.community_id.not_in(blocked_community_ids))
|
2024-10-09 23:48:58 +00:00
|
|
|
blocked_instance_ids = blocked_instances(user_id)
|
|
|
|
if blocked_instance_ids:
|
|
|
|
posts = posts.filter(Post.instance_id.not_in(blocked_instance_ids)) # users from blocked instance
|
|
|
|
posts = posts.filter(Post.community_id.not_in(community_ids_from_instances(blocked_instance_ids))) # communities from blocked instance
|
2024-10-05 20:55:04 +00:00
|
|
|
|
2025-01-22 00:51:41 +00:00
|
|
|
if query:
|
|
|
|
if search_type == 'Url':
|
|
|
|
posts = posts.filter(Post.url.ilike(f"%{query}%"))
|
|
|
|
else:
|
|
|
|
posts = posts.filter(Post.title.ilike(f"%{query}%"))
|
|
|
|
|
2024-09-20 16:06:08 +00:00
|
|
|
if sort == "Hot":
|
|
|
|
posts = posts.order_by(desc(Post.ranking)).order_by(desc(Post.posted_at))
|
|
|
|
elif sort == "TopDay":
|
|
|
|
posts = posts.filter(Post.posted_at > utcnow() - timedelta(days=1)).order_by(desc(Post.up_votes - Post.down_votes))
|
|
|
|
elif sort == "New":
|
|
|
|
posts = posts.order_by(desc(Post.posted_at))
|
|
|
|
elif sort == "Active":
|
|
|
|
posts = posts.order_by(desc(Post.last_active))
|
|
|
|
|
|
|
|
return posts.all()
|
|
|
|
|
|
|
|
|
2025-01-22 00:51:41 +00:00
|
|
|
def get_post_list(auth, data, user_id=None, search_type='Posts'):
|
2024-09-20 16:06:08 +00:00
|
|
|
type = data['type_'] if data and 'type_' in data else "All"
|
|
|
|
sort = data['sort'] if data and 'sort' in data else "Hot"
|
|
|
|
page = int(data['page']) if data and 'page' in data else 1
|
|
|
|
limit = int(data['limit']) if data and 'limit' in data else 10
|
|
|
|
|
2025-01-22 00:51:41 +00:00
|
|
|
query = data['q'] if data and 'q' in data else ''
|
|
|
|
|
2024-09-20 16:06:08 +00:00
|
|
|
if auth:
|
2024-10-08 03:26:40 +00:00
|
|
|
user_id = authorise_api_user(auth)
|
2024-09-20 16:06:08 +00:00
|
|
|
|
|
|
|
# user_id: the logged in user
|
|
|
|
# person_id: the author of the posts being requested
|
|
|
|
|
|
|
|
community_id = int(data['community_id']) if data and 'community_id' in data else None
|
|
|
|
community_name = data['community_name'] if data and 'community_name' in data else None
|
|
|
|
person_id = int(data['person_id']) if data and 'person_id' in data else None
|
|
|
|
|
2025-01-22 00:51:41 +00:00
|
|
|
posts = cached_post_list(type, sort, user_id, community_id, community_name, person_id, query, search_type)
|
2024-09-20 16:06:08 +00:00
|
|
|
|
|
|
|
start = (page - 1) * limit
|
|
|
|
end = start + limit
|
|
|
|
posts = posts[start:end]
|
|
|
|
|
|
|
|
postlist = []
|
|
|
|
for post in posts:
|
|
|
|
try:
|
|
|
|
postlist.append(post_view(post=post, variant=2, stub=True, user_id=user_id))
|
|
|
|
except:
|
|
|
|
continue
|
|
|
|
list_json = {
|
|
|
|
"posts": postlist
|
|
|
|
}
|
|
|
|
|
|
|
|
return list_json
|
|
|
|
|
|
|
|
|
|
|
|
def get_post(auth, data):
|
|
|
|
if not data or 'id' not in data:
|
2025-01-23 05:07:37 +00:00
|
|
|
raise Exception('missing parameters for post')
|
2024-09-20 16:06:08 +00:00
|
|
|
|
|
|
|
id = int(data['id'])
|
|
|
|
|
2024-10-08 03:26:40 +00:00
|
|
|
user_id = authorise_api_user(auth) if auth else None
|
2024-09-20 16:06:08 +00:00
|
|
|
|
|
|
|
post_json = post_view(post=id, variant=3, user_id=user_id)
|
2024-10-27 13:36:17 +00:00
|
|
|
return post_json
|
2024-09-20 16:06:08 +00:00
|
|
|
|
|
|
|
|
|
|
|
# would be in app/constants.py
|
|
|
|
SRC_API = 3
|
|
|
|
|
|
|
|
def post_post_like(auth, data):
|
2024-10-08 03:26:40 +00:00
|
|
|
required(['post_id', 'score'], data)
|
|
|
|
integer_expected(['post_id', 'score'], data)
|
2024-09-20 16:06:08 +00:00
|
|
|
|
|
|
|
post_id = data['post_id']
|
|
|
|
score = data['score']
|
|
|
|
if score == 1:
|
|
|
|
direction = 'upvote'
|
|
|
|
elif score == -1:
|
|
|
|
direction = 'downvote'
|
|
|
|
else:
|
|
|
|
score = 0
|
|
|
|
direction = 'reversal'
|
|
|
|
|
2024-10-08 03:26:40 +00:00
|
|
|
user_id = vote_for_post(post_id, direction, SRC_API, auth)
|
|
|
|
cache.delete_memoized(cached_post_list)
|
|
|
|
post_json = post_view(post=post_id, variant=4, user_id=user_id, my_vote=score)
|
|
|
|
return post_json
|
2024-09-20 16:06:08 +00:00
|
|
|
|
|
|
|
|
2024-09-23 12:40:27 +00:00
|
|
|
def put_post_save(auth, data):
|
2024-10-08 03:26:40 +00:00
|
|
|
required(['post_id', 'save'], data)
|
|
|
|
integer_expected(['post_id'], data)
|
|
|
|
boolean_expected(['save'], data)
|
2024-09-23 12:40:27 +00:00
|
|
|
|
|
|
|
post_id = data['post_id']
|
|
|
|
save = data['save']
|
|
|
|
|
2024-10-08 03:26:40 +00:00
|
|
|
user_id = bookmark_the_post(post_id, SRC_API, auth) if save else remove_the_bookmark_from_post(post_id, SRC_API, auth)
|
|
|
|
post_json = post_view(post=post_id, variant=4, user_id=user_id)
|
|
|
|
return post_json
|
2024-09-23 12:40:27 +00:00
|
|
|
|
|
|
|
|
2024-09-26 16:01:55 +00:00
|
|
|
def put_post_subscribe(auth, data):
|
2024-10-08 03:26:40 +00:00
|
|
|
required(['post_id', 'subscribe'], data)
|
|
|
|
integer_expected(['post_id'], data)
|
|
|
|
boolean_expected(['subscribe'], data)
|
2024-09-26 16:01:55 +00:00
|
|
|
|
|
|
|
post_id = data['post_id']
|
|
|
|
subscribe = data['subscribe'] # not actually processed - is just a toggle
|
|
|
|
|
2024-10-08 03:26:40 +00:00
|
|
|
user_id = toggle_post_notification(post_id, SRC_API, auth)
|
|
|
|
post_json = post_view(post=post_id, variant=4, user_id=user_id)
|
|
|
|
return post_json
|
2024-09-20 16:06:08 +00:00
|
|
|
|
2025-01-14 13:54:17 +00:00
|
|
|
|
|
|
|
def post_post(auth, data):
|
|
|
|
required(['title', 'community_id'], data)
|
|
|
|
integer_expected(['language_id'], data)
|
|
|
|
boolean_expected(['nsfw'], data)
|
2025-01-15 01:26:27 +00:00
|
|
|
string_expected(['title', 'body', 'url'], data)
|
2025-01-14 13:54:17 +00:00
|
|
|
|
|
|
|
title = data['title']
|
|
|
|
community_id = data['community_id']
|
|
|
|
body = data['body'] if 'body' in data else ''
|
|
|
|
url = data['url'] if 'url' in data else None
|
|
|
|
nsfw = data['nsfw'] if 'nsfw' in data else False
|
|
|
|
language_id = data['language_id'] if 'language_id' in data else 2 # FIXME: use site language
|
|
|
|
if language_id < 2:
|
|
|
|
language_id = 2
|
|
|
|
|
2025-01-17 17:20:15 +00:00
|
|
|
# change when Polls are supported
|
2025-01-18 00:35:20 +00:00
|
|
|
type = POST_TYPE_ARTICLE
|
|
|
|
if url:
|
|
|
|
type = POST_TYPE_LINK
|
2025-01-14 13:54:17 +00:00
|
|
|
|
|
|
|
input = {'title': title, 'body': body, 'url': url, 'nsfw': nsfw, 'language_id': language_id, 'notify_author': True}
|
|
|
|
community = Community.query.filter_by(id=community_id).one()
|
|
|
|
user_id, post = make_post(input, community, type, SRC_API, auth)
|
|
|
|
|
|
|
|
post_json = post_view(post=post, variant=4, user_id=user_id)
|
|
|
|
return post_json
|
|
|
|
|
|
|
|
|
2025-01-15 01:26:27 +00:00
|
|
|
def put_post(auth, data):
|
|
|
|
required(['post_id'], data)
|
|
|
|
integer_expected(['language_id'], data)
|
|
|
|
boolean_expected(['nsfw'], data)
|
|
|
|
string_expected(['title', 'body', 'url'], data)
|
|
|
|
|
|
|
|
post_id = data['post_id']
|
|
|
|
title = data['title']
|
|
|
|
body = data['body'] if 'body' in data else ''
|
|
|
|
url = data['url'] if 'url' in data else None
|
|
|
|
nsfw = data['nsfw'] if 'nsfw' in data else False
|
|
|
|
language_id = data['language_id'] if 'language_id' in data else 2 # FIXME: use site language
|
|
|
|
if language_id < 2:
|
|
|
|
language_id = 2
|
|
|
|
|
2025-01-17 17:20:15 +00:00
|
|
|
# change when Polls are supported
|
2025-01-18 00:35:20 +00:00
|
|
|
type = POST_TYPE_ARTICLE
|
|
|
|
if url:
|
|
|
|
type = POST_TYPE_LINK
|
2025-01-15 01:26:27 +00:00
|
|
|
|
|
|
|
input = {'title': title, 'body': body, 'url': url, 'nsfw': nsfw, 'language_id': language_id, 'notify_author': True}
|
|
|
|
post = Post.query.filter_by(id=post_id).one()
|
2025-01-18 00:35:20 +00:00
|
|
|
user_id, post = edit_post(input, post, type, SRC_API, auth=auth)
|
2025-01-15 01:26:27 +00:00
|
|
|
|
|
|
|
post_json = post_view(post=post, variant=4, user_id=user_id)
|
|
|
|
return post_json
|
2025-01-18 14:52:09 +00:00
|
|
|
|
|
|
|
|
|
|
|
def post_post_delete(auth, data):
|
|
|
|
required(['post_id', 'deleted'], data)
|
|
|
|
integer_expected(['post_id'], data)
|
|
|
|
boolean_expected(['deleted'], data)
|
|
|
|
|
|
|
|
post_id = data['post_id']
|
|
|
|
deleted = data['deleted']
|
|
|
|
|
|
|
|
if deleted == True:
|
|
|
|
user_id, post = delete_post(post_id, SRC_API, auth)
|
|
|
|
else:
|
|
|
|
user_id, post = restore_post(post_id, SRC_API, auth)
|
|
|
|
|
|
|
|
post_json = post_view(post=post, variant=4, user_id=user_id)
|
|
|
|
return post_json
|
2025-01-18 17:56:09 +00:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def post_post_report(auth, data):
|
|
|
|
required(['post_id', 'reason'], data)
|
|
|
|
integer_expected(['post_id'], data)
|
|
|
|
string_expected(['reason'], data)
|
|
|
|
|
|
|
|
post_id = data['post_id']
|
|
|
|
reason = data['reason']
|
|
|
|
input = {'reason': reason, 'description': '', 'report_remote': True}
|
|
|
|
|
|
|
|
user_id, report = report_post(post_id, input, SRC_API, auth)
|
|
|
|
|
|
|
|
post_json = post_report_view(report=report, post_id=post_id, user_id=user_id)
|
|
|
|
return post_json
|
|
|
|
|
2025-01-19 21:28:42 +00:00
|
|
|
|
|
|
|
def post_post_lock(auth, data):
|
|
|
|
required(['post_id', 'locked'], data)
|
|
|
|
integer_expected(['post_id'], data)
|
|
|
|
boolean_expected(['locked'], data)
|
|
|
|
|
|
|
|
post_id = data['post_id']
|
|
|
|
locked = data['locked']
|
|
|
|
|
|
|
|
user_id, post = lock_post(post_id, locked, SRC_API, auth)
|
|
|
|
|
|
|
|
post_json = post_view(post=post, variant=4, user_id=user_id)
|
|
|
|
return post_json
|
2025-01-19 22:53:32 +00:00
|
|
|
|
|
|
|
|
|
|
|
def post_post_feature(auth, data):
|
|
|
|
required(['post_id', 'featured', 'feature_type'], data)
|
|
|
|
integer_expected(['post_id'], data)
|
|
|
|
boolean_expected(['featured'], data)
|
|
|
|
string_expected(['feature_type'], data)
|
|
|
|
|
|
|
|
post_id = data['post_id']
|
|
|
|
featured = data['featured']
|
|
|
|
|
|
|
|
user_id, post = sticky_post(post_id, featured, SRC_API, auth)
|
|
|
|
|
|
|
|
post_json = post_view(post=post, variant=4, user_id=user_id)
|
|
|
|
return post_json
|
2025-01-20 05:01:31 +00:00
|
|
|
|
|
|
|
|
|
|
|
def post_post_remove(auth, data):
|
|
|
|
required(['post_id', 'removed'], data)
|
|
|
|
integer_expected(['post_id'], data)
|
|
|
|
boolean_expected(['removed'], data)
|
|
|
|
string_expected(['reason'], data)
|
|
|
|
|
|
|
|
post_id = data['post_id']
|
|
|
|
removed = data['removed']
|
|
|
|
|
|
|
|
if removed == True:
|
|
|
|
reason = data['reason'] if 'reason' in data else 'Removed by mod'
|
|
|
|
user_id, post = mod_remove_post(post_id, reason, SRC_API, auth)
|
|
|
|
else:
|
|
|
|
reason = data['reason'] if 'reason' in data else 'Restored by mod'
|
|
|
|
user_id, post = mod_restore_post(post_id, reason, SRC_API, auth)
|
|
|
|
|
|
|
|
post_json = post_view(post=post, variant=4, user_id=user_id)
|
|
|
|
return post_json
|