2024-02-10 06:41:24 +13:00
import os . path
2024-08-16 13:42:29 +12:00
from datetime import timedelta
2024-01-19 15:08:39 +13:00
from random import randint
2024-01-03 20:14:39 +13:00
2024-02-23 16:52:17 +13:00
import flask
2024-08-27 19:37:47 +12:00
from pyld import jsonld
2024-02-23 16:52:17 +13:00
from sqlalchemy . sql . operators import or_ , and_
2023-08-10 21:13:37 +12:00
2023-12-03 22:41:15 +13:00
from app import db , cache
2024-07-15 20:46:48 +08:00
from app . activitypub . util import users_total , active_month , local_posts , local_communities
2024-08-27 19:37:47 +12:00
from app . activitypub . signature import default_context , LDSignature
2024-01-11 20:52:09 +13:00
from app . constants import SUBSCRIPTION_PENDING , SUBSCRIPTION_MEMBER , POST_TYPE_IMAGE , POST_TYPE_LINK , \
2024-05-19 11:30:41 +12:00
SUBSCRIPTION_OWNER , SUBSCRIPTION_MODERATOR , POST_TYPE_VIDEO , POST_TYPE_POLL
2024-08-16 13:42:29 +12:00
from app . email import send_email
2024-01-19 15:08:39 +13:00
from app . inoculation import inoculation
2023-07-28 16:22:12 +12:00
from app . main import bp
2023-12-21 22:14:43 +13:00
from flask import g , session , flash , request , current_app , url_for , redirect , make_response , jsonify
2024-03-01 16:43:05 +13:00
from flask_login import current_user , login_required
2023-07-28 16:22:12 +12:00
from flask_babel import _ , get_locale
2024-08-16 13:42:29 +12:00
from sqlalchemy import desc , text
from app . utils import render_template , get_setting , request_etag_matches , return_304 , blocked_domains , \
ap_datetime , shorten_string , markdown_to_text , user_filters_home , \
joined_communities , moderating_communities , markdown_to_html , allowlist_html , \
2024-04-16 16:35:12 +12:00
blocked_instances , communities_banned_from , topic_tree , recently_upvoted_posts , recently_downvoted_posts , \
2024-09-15 19:30:45 +12:00
blocked_users , menu_topics , languages_for_form , blocked_communities , get_request
2024-08-18 16:38:55 +12:00
from app . models import Community , CommunityMember , Post , Site , User , utcnow , Topic , Instance , \
2024-09-30 13:49:06 +13:00
Notification , Language , community_language , ModLog , read_posts
2023-08-22 21:24:11 +12:00
2023-07-28 16:22:12 +12:00
2023-12-21 22:14:43 +13:00
@bp.route ( ' / ' , methods = [ ' HEAD ' , ' GET ' , ' POST ' ] )
2024-01-12 17:15:08 +13:00
@bp.route ( ' /home ' , methods = [ ' GET ' , ' POST ' ] )
2024-08-14 15:03:09 -04:00
@bp.route ( ' /home/<sort> ' , methods = [ ' GET ' , ' POST ' ] )
2024-08-12 15:43:00 -04:00
@bp.route ( ' /home/<sort>/<view_filter> ' , methods = [ ' GET ' , ' POST ' ] )
def index ( sort = None , view_filter = None ) :
2023-12-21 22:14:43 +13:00
if ' application/ld+json ' in request . headers . get ( ' Accept ' , ' ' ) or ' application/activity+json ' in request . headers . get (
' Accept ' , ' ' ) :
return activitypub_application ( )
2024-08-18 16:38:55 +12:00
return home_page ( sort , view_filter )
2024-01-03 20:14:39 +13:00
2024-08-16 13:42:29 +12:00
def home_page ( sort , view_filter ) :
2024-01-03 20:14:39 +13:00
verification_warning ( )
2024-01-15 18:26:22 +13:00
if sort is None :
sort = current_user . default_sort if current_user . is_authenticated else ' hot '
2024-08-12 15:43:00 -04:00
if view_filter is None :
2024-08-16 13:42:29 +12:00
view_filter = current_user . default_filter if current_user . is_authenticated else ' popular '
if view_filter is None :
view_filter = ' subscribed '
2024-08-12 15:43:00 -04:00
2024-01-03 20:14:39 +13:00
# If nothing has changed since their last visit, return HTTP 304
2024-08-16 13:42:29 +12:00
current_etag = f " { sort } _ { view_filter } _ { hash ( str ( g . site . last_active ) ) } "
2024-01-03 20:14:39 +13:00
if current_user . is_anonymous and request_etag_matches ( current_etag ) :
return return_304 ( current_etag )
page = request . args . get ( ' page ' , 1 , type = int )
2024-02-13 21:28:33 +13:00
low_bandwidth = request . cookies . get ( ' low_bandwidth ' , ' 0 ' ) == ' 1 '
2024-01-03 20:14:39 +13:00
if current_user . is_anonymous :
2024-01-12 17:15:08 +13:00
flash ( _ ( ' Create an account to tailor this feed to your interests. ' ) )
2024-06-02 16:45:21 +12:00
posts = Post . query . filter ( Post . from_bot == False , Post . nsfw == False , Post . nsfl == False , Post . deleted == False )
2024-11-30 13:43:44 +13:00
content_filters = { ' trump ' : { ' trump ' , ' elon ' , ' musk ' } }
2024-01-03 20:14:39 +13:00
else :
2024-08-16 13:42:29 +12:00
posts = Post . query . filter ( Post . deleted == False )
2024-02-01 11:59:09 +13:00
2024-06-28 13:22:15 +02:00
if current_user . ignore_bots == 1 :
2024-02-01 11:59:09 +13:00
posts = posts . filter ( Post . from_bot == False )
2024-06-28 15:04:06 +00:00
if current_user . hide_nsfl == 1 :
2024-02-01 11:59:09 +13:00
posts = posts . filter ( Post . nsfl == False )
2024-06-28 15:04:06 +00:00
if current_user . hide_nsfw == 1 :
2024-02-01 11:59:09 +13:00
posts = posts . filter ( Post . nsfw == False )
2024-09-27 18:12:47 -04:00
if current_user . hide_read_posts :
2024-09-30 13:49:06 +13:00
posts = posts . outerjoin ( read_posts , ( Post . id == read_posts . c . read_post_id ) & ( read_posts . c . user_id == current_user . id ) )
posts = posts . filter ( read_posts . c . read_post_id . is_ ( None ) ) # Filter where there is no corresponding read post for the current user
2024-02-01 11:59:09 +13:00
2024-01-03 20:14:39 +13:00
domains_ids = blocked_domains ( current_user . id )
if domains_ids :
posts = posts . filter ( or_ ( Post . domain_id . not_in ( domains_ids ) , Post . domain_id == None ) )
2024-03-12 20:06:24 +13:00
instance_ids = blocked_instances ( current_user . id )
if instance_ids :
posts = posts . filter ( or_ ( Post . instance_id . not_in ( instance_ids ) , Post . instance_id == None ) )
2024-08-12 20:54:10 +12:00
community_ids = blocked_communities ( current_user . id )
if community_ids :
posts = posts . filter ( Post . community_id . not_in ( community_ids ) )
2024-04-26 12:54:12 +01:00
# filter blocked users
blocked_accounts = blocked_users ( current_user . id )
if blocked_accounts :
posts = posts . filter ( Post . user_id . not_in ( blocked_accounts ) )
2024-01-11 20:39:22 +13:00
content_filters = user_filters_home ( current_user . id )
2024-01-03 20:14:39 +13:00
2024-08-13 15:56:38 -04:00
# view filter - subscribed/local/all
if view_filter == ' subscribed ' :
2024-08-16 13:42:29 +12:00
posts = posts . join ( CommunityMember , Post . community_id == CommunityMember . community_id ) . filter ( CommunityMember . is_banned == False )
2024-08-13 15:56:38 -04:00
posts = posts . filter ( CommunityMember . user_id == current_user . id )
elif view_filter == ' local ' :
2024-08-16 13:50:59 +12:00
posts = posts . join ( Community , Community . id == Post . community_id )
posts = posts . filter ( Community . instance_id == 1 )
2024-08-16 13:42:29 +12:00
elif view_filter == ' popular ' :
posts = posts . join ( Community , Community . id == Post . community_id )
posts = posts . filter ( Community . show_popular == True , Post . score > 100 )
2024-11-30 13:43:44 +13:00
if current_user . is_anonymous :
posts = posts . filter ( Community . low_quality == False )
2024-08-16 13:42:29 +12:00
elif view_filter == ' all ' :
posts = posts . join ( Community , Community . id == Post . community_id )
posts = posts . filter ( Community . show_all == True )
2024-08-13 15:56:38 -04:00
2024-01-12 17:15:08 +13:00
# Sorting
if sort == ' hot ' :
2024-02-21 19:56:03 +13:00
posts = posts . order_by ( desc ( Post . ranking ) ) . order_by ( desc ( Post . posted_at ) )
2024-01-12 17:15:08 +13:00
elif sort == ' top ' :
2024-04-14 07:59:24 +12:00
posts = posts . filter ( Post . posted_at > utcnow ( ) - timedelta ( days = 1 ) ) . order_by ( desc ( Post . up_votes - Post . down_votes ) )
2024-01-12 17:15:08 +13:00
elif sort == ' new ' :
posts = posts . order_by ( desc ( Post . posted_at ) )
2024-01-15 18:26:22 +13:00
elif sort == ' active ' :
posts = posts . order_by ( desc ( Post . last_active ) )
2024-01-12 17:15:08 +13:00
# Pagination
2024-02-13 21:28:33 +13:00
posts = posts . paginate ( page = page , per_page = 100 if current_user . is_authenticated and not low_bandwidth else 50 , error_out = False )
2024-08-16 13:42:29 +12:00
next_url = url_for ( ' main.index ' , page = posts . next_num , sort = sort , view_filter = view_filter ) if posts . has_next else None
prev_url = url_for ( ' main.index ' , page = posts . prev_num , sort = sort , view_filter = view_filter ) if posts . has_prev and page != 1 else None
2024-01-03 20:14:39 +13:00
2024-03-21 21:19:50 +13:00
# Active Communities
active_communities = Community . query . filter_by ( banned = False )
if current_user . is_authenticated : # do not show communities current user is banned from
banned_from = communities_banned_from ( current_user . id )
if banned_from :
active_communities = active_communities . filter ( Community . id . not_in ( banned_from ) )
2024-08-12 20:54:10 +12:00
community_ids = blocked_communities ( current_user . id )
if community_ids :
active_communities = active_communities . filter ( Community . id . not_in ( community_ids ) )
2024-03-21 21:19:50 +13:00
active_communities = active_communities . order_by ( desc ( Community . last_active ) ) . limit ( 5 ) . all ( )
2024-01-03 20:14:39 +13:00
2024-04-11 14:04:57 +12:00
# Voting history
if current_user . is_authenticated :
recently_upvoted = recently_upvoted_posts ( current_user . id )
recently_downvoted = recently_downvoted_posts ( current_user . id )
else :
recently_upvoted = [ ]
recently_downvoted = [ ]
2024-01-12 17:15:08 +13:00
return render_template ( ' index.html ' , posts = posts , active_communities = active_communities , show_post_community = True ,
2024-04-11 14:04:57 +12:00
low_bandwidth = low_bandwidth , recently_upvoted = recently_upvoted ,
recently_downvoted = recently_downvoted ,
2024-01-03 20:14:39 +13:00
SUBSCRIPTION_PENDING = SUBSCRIPTION_PENDING , SUBSCRIPTION_MEMBER = SUBSCRIPTION_MEMBER ,
2024-08-16 13:42:29 +12:00
etag = f " { sort } _ { view_filter } _ { hash ( str ( g . site . last_active ) ) } " , next_url = next_url , prev_url = prev_url ,
2024-02-27 06:49:37 +13:00
#rss_feed=f"https://{current_app.config['SERVER_NAME']}/feed",
#rss_feed_name=f"Posts on " + g.site.name,
2024-01-12 17:15:08 +13:00
title = f " { g . site . name } - { g . site . description } " ,
description = shorten_string ( markdown_to_text ( g . site . sidebar ) , 150 ) ,
2024-08-16 13:42:29 +12:00
content_filters = content_filters , sort = sort , view_filter = view_filter ,
2024-06-10 19:07:15 +08:00
announcement = allowlist_html ( get_setting ( ' announcement ' , ' ' ) ) ,
2024-01-12 17:15:08 +13:00
moderating_communities = moderating_communities ( current_user . get_id ( ) ) ,
2024-01-19 15:08:39 +13:00
joined_communities = joined_communities ( current_user . get_id ( ) ) ,
2024-05-30 21:54:25 +12:00
menu_topics = menu_topics ( ) , site = g . site ,
2024-07-12 19:56:57 +08:00
inoculation = inoculation [ randint ( 0 , len ( inoculation ) - 1 ) ] if g . site . show_inoculation_block else None
)
2024-01-12 12:34:08 +13:00
@bp.route ( ' /topics ' , methods = [ ' GET ' ] )
def list_topics ( ) :
verification_warning ( )
2024-04-08 19:48:25 +12:00
topics = topic_tree ( )
2024-01-12 12:34:08 +13:00
return render_template ( ' list_topics.html ' , topics = topics , title = _ ( ' Browse by topic ' ) ,
2024-01-22 21:14:40 +13:00
low_bandwidth = request . cookies . get ( ' low_bandwidth ' , ' 0 ' ) == ' 1 ' ,
moderating_communities = moderating_communities ( current_user . get_id ( ) ) ,
2024-05-30 21:54:25 +12:00
joined_communities = joined_communities ( current_user . get_id ( ) ) ,
menu_topics = menu_topics ( ) , site = g . site )
2024-01-03 20:14:39 +13:00
2023-08-22 21:24:11 +12:00
@bp.route ( ' /communities ' , methods = [ ' GET ' ] )
def list_communities ( ) :
2023-10-23 13:03:35 +13:00
verification_warning ( )
2023-09-05 20:25:02 +12:00
search_param = request . args . get ( ' search ' , ' ' )
2024-01-04 16:00:19 +13:00
topic_id = int ( request . args . get ( ' topic_id ' , 0 ) )
2024-05-08 19:55:04 +12:00
language_id = int ( request . args . get ( ' language_id ' , 0 ) )
2024-05-11 14:02:18 +12:00
page = request . args . get ( ' page ' , 1 , type = int )
low_bandwidth = request . cookies . get ( ' low_bandwidth ' , ' 0 ' ) == ' 1 '
sort_by = request . args . get ( ' sort_by ' , ' post_reply_count desc ' )
2024-01-04 16:00:19 +13:00
topics = Topic . query . order_by ( Topic . name ) . all ( )
2024-05-08 19:55:04 +12:00
languages = Language . query . order_by ( Language . name ) . all ( )
2024-02-02 15:57:22 +13:00
communities = Community . query . filter_by ( banned = False )
2023-09-05 20:25:02 +12:00
if search_param == ' ' :
2024-01-04 16:00:19 +13:00
pass
2023-09-05 20:25:02 +12:00
else :
2024-02-02 15:57:22 +13:00
communities = communities . filter ( or_ ( Community . title . ilike ( f " % { search_param } % " ) , Community . ap_id . ilike ( f " % { search_param } % " ) ) )
2024-01-04 16:00:19 +13:00
if topic_id != 0 :
communities = communities . filter_by ( topic_id = topic_id )
2023-09-05 20:25:02 +12:00
2024-05-08 19:55:04 +12:00
if language_id != 0 :
communities = communities . join ( community_language ) . filter ( community_language . c . language_id == language_id )
2024-03-21 21:19:50 +13:00
if current_user . is_authenticated :
banned_from = communities_banned_from ( current_user . id )
if banned_from :
communities = communities . filter ( Community . id . not_in ( banned_from ) )
2024-06-28 15:04:06 +00:00
if current_user . hide_nsfw == 1 :
2024-06-27 00:48:25 +02:00
communities = communities . filter ( Community . nsfw == False )
2024-06-28 15:04:06 +00:00
if current_user . hide_nsfl == 1 :
2024-06-27 00:48:25 +02:00
communities = communities . filter ( Community . nsfl == False )
2024-10-23 13:00:30 +13:00
instance_ids = blocked_instances ( current_user . id )
if instance_ids :
communities = communities . filter ( or_ ( Community . instance_id . not_in ( instance_ids ) , Community . instance_id == None ) )
2024-06-27 00:48:25 +02:00
else :
communities = communities . filter ( and_ ( Community . nsfw == False , Community . nsfl == False ) )
2024-03-21 21:19:50 +13:00
2024-05-11 14:02:18 +12:00
communities = communities . order_by ( text ( ' community. ' + sort_by ) )
# Pagination
communities = communities . paginate ( page = page , per_page = 250 if current_user . is_authenticated and not low_bandwidth else 50 ,
error_out = False )
next_url = url_for ( ' main.list_communities ' , page = communities . next_num , sort_by = sort_by , language_id = language_id ) if communities . has_next else None
prev_url = url_for ( ' main.list_communities ' , page = communities . prev_num , sort_by = sort_by , language_id = language_id ) if communities . has_prev and page != 1 else None
return render_template ( ' list_communities.html ' , communities = communities , search = search_param , title = _ ( ' Communities ' ) ,
2023-12-17 00:12:49 +13:00
SUBSCRIPTION_PENDING = SUBSCRIPTION_PENDING , SUBSCRIPTION_MEMBER = SUBSCRIPTION_MEMBER ,
2024-01-11 20:52:09 +13:00
SUBSCRIPTION_OWNER = SUBSCRIPTION_OWNER , SUBSCRIPTION_MODERATOR = SUBSCRIPTION_MODERATOR ,
2024-05-11 14:02:18 +12:00
next_url = next_url , prev_url = prev_url ,
2024-05-08 19:55:04 +12:00
topics = topics , languages = languages , topic_id = topic_id , language_id = language_id , sort_by = sort_by ,
2024-05-11 14:02:18 +12:00
low_bandwidth = low_bandwidth , moderating_communities = moderating_communities ( current_user . get_id ( ) ) ,
2024-05-30 21:54:25 +12:00
joined_communities = joined_communities ( current_user . get_id ( ) ) ,
menu_topics = menu_topics ( ) , site = g . site )
2023-09-05 20:25:02 +12:00
@bp.route ( ' /communities/local ' , methods = [ ' GET ' ] )
def list_local_communities ( ) :
2023-10-23 13:03:35 +13:00
verification_warning ( )
2024-05-27 00:52:18 +01:00
search_param = request . args . get ( ' search ' , ' ' )
topic_id = int ( request . args . get ( ' topic_id ' , 0 ) )
language_id = int ( request . args . get ( ' language_id ' , 0 ) )
page = request . args . get ( ' page ' , 1 , type = int )
low_bandwidth = request . cookies . get ( ' low_bandwidth ' , ' 0 ' ) == ' 1 '
sort_by = request . args . get ( ' sort_by ' , ' post_reply_count desc ' )
topics = Topic . query . order_by ( Topic . name ) . all ( )
languages = Language . query . order_by ( Language . name ) . all ( )
2024-01-07 22:45:09 +13:00
communities = Community . query . filter_by ( ap_id = None , banned = False )
2024-05-27 00:52:18 +01:00
if search_param == ' ' :
pass
else :
communities = communities . filter ( or_ ( Community . title . ilike ( f " % { search_param } % " ) , Community . ap_id . ilike ( f " % { search_param } % " ) ) )
if topic_id != 0 :
communities = communities . filter_by ( topic_id = topic_id )
if language_id != 0 :
communities = communities . join ( community_language ) . filter ( community_language . c . language_id == language_id )
if current_user . is_authenticated :
banned_from = communities_banned_from ( current_user . id )
if banned_from :
communities = communities . filter ( Community . id . not_in ( banned_from ) )
2024-06-28 15:04:06 +00:00
if current_user . hide_nsfw == 1 :
2024-06-27 00:48:25 +02:00
communities = communities . filter ( Community . nsfw == False )
2024-06-28 15:04:06 +00:00
if current_user . hide_nsfl == 1 :
2024-06-27 00:48:25 +02:00
communities = communities . filter ( Community . nsfl == False )
else :
communities = communities . filter ( and_ ( Community . nsfw == False , Community . nsfl == False ) )
2024-05-27 00:52:18 +01:00
communities = communities . order_by ( text ( ' community. ' + sort_by ) )
# Pagination
communities = communities . paginate ( page = page , per_page = 250 if current_user . is_authenticated and not low_bandwidth else 50 ,
error_out = False )
next_url = url_for ( ' main.list_communities ' , page = communities . next_num , sort_by = sort_by , language_id = language_id ) if communities . has_next else None
prev_url = url_for ( ' main.list_communities ' , page = communities . prev_num , sort_by = sort_by , language_id = language_id ) if communities . has_prev and page != 1 else None
return render_template ( ' list_communities.html ' , communities = communities , search = search_param , title = _ ( ' Local Communities ' ) ,
2024-01-08 19:41:32 +13:00
SUBSCRIPTION_PENDING = SUBSCRIPTION_PENDING , SUBSCRIPTION_MEMBER = SUBSCRIPTION_MEMBER ,
2024-03-03 22:09:38 +00:00
SUBSCRIPTION_OWNER = SUBSCRIPTION_OWNER , SUBSCRIPTION_MODERATOR = SUBSCRIPTION_MODERATOR ,
2024-05-27 00:52:18 +01:00
next_url = next_url , prev_url = prev_url ,
topics = topics , languages = languages , topic_id = topic_id , language_id = language_id , sort_by = sort_by ,
low_bandwidth = low_bandwidth , moderating_communities = moderating_communities ( current_user . get_id ( ) ) ,
2024-05-30 21:54:25 +12:00
joined_communities = joined_communities ( current_user . get_id ( ) ) ,
menu_topics = menu_topics ( ) , site = g . site )
2023-09-05 20:25:02 +12:00
@bp.route ( ' /communities/subscribed ' , methods = [ ' GET ' ] )
def list_subscribed_communities ( ) :
2023-10-23 13:03:35 +13:00
verification_warning ( )
2024-05-27 00:52:18 +01:00
search_param = request . args . get ( ' search ' , ' ' )
topic_id = int ( request . args . get ( ' topic_id ' , 0 ) )
language_id = int ( request . args . get ( ' language_id ' , 0 ) )
page = request . args . get ( ' page ' , 1 , type = int )
low_bandwidth = request . cookies . get ( ' low_bandwidth ' , ' 0 ' ) == ' 1 '
sort_by = request . args . get ( ' sort_by ' , ' post_reply_count desc ' )
topics = Topic . query . order_by ( Topic . name ) . all ( )
languages = Language . query . order_by ( Language . name ) . all ( )
2024-01-05 14:09:46 +13:00
if current_user . is_authenticated :
2024-05-27 00:52:18 +01:00
communities = Community . query . filter_by ( banned = False ) . join ( CommunityMember ) . filter ( CommunityMember . user_id == current_user . id )
if search_param == ' ' :
pass
else :
communities = communities . filter ( or_ ( Community . title . ilike ( f " % { search_param } % " ) , Community . ap_id . ilike ( f " % { search_param } % " ) ) )
if topic_id != 0 :
communities = communities . filter_by ( topic_id = topic_id )
if language_id != 0 :
communities = communities . join ( community_language ) . filter ( community_language . c . language_id == language_id )
banned_from = communities_banned_from ( current_user . id )
if banned_from :
communities = communities . filter ( Community . id . not_in ( banned_from ) )
communities = communities . order_by ( text ( ' community. ' + sort_by ) )
# Pagination
communities = communities . paginate ( page = page , per_page = 250 if current_user . is_authenticated and not low_bandwidth else 50 ,
error_out = False )
next_url = url_for ( ' main.list_communities ' , page = communities . next_num , sort_by = sort_by , language_id = language_id ) if communities . has_next else None
prev_url = url_for ( ' main.list_communities ' , page = communities . prev_num , sort_by = sort_by , language_id = language_id ) if communities . has_prev and page != 1 else None
2024-01-05 14:09:46 +13:00
else :
communities = [ ]
2024-05-27 00:52:18 +01:00
next_url = None
prev_url = None
return render_template ( ' list_communities.html ' , communities = communities , search = search_param , title = _ ( ' Joined Communities ' ) ,
SUBSCRIPTION_PENDING = SUBSCRIPTION_PENDING , SUBSCRIPTION_MEMBER = SUBSCRIPTION_MEMBER ,
2024-03-03 22:09:38 +00:00
SUBSCRIPTION_OWNER = SUBSCRIPTION_OWNER , SUBSCRIPTION_MODERATOR = SUBSCRIPTION_MODERATOR ,
2024-05-27 00:52:18 +01:00
next_url = next_url , prev_url = prev_url ,
topics = topics , languages = languages , topic_id = topic_id , language_id = language_id , sort_by = sort_by ,
low_bandwidth = low_bandwidth , moderating_communities = moderating_communities ( current_user . get_id ( ) ) ,
2024-05-30 21:54:25 +12:00
joined_communities = joined_communities ( current_user . get_id ( ) ) ,
menu_topics = menu_topics ( ) , site = g . site )
2023-12-03 22:41:15 +13:00
2024-07-07 16:03:35 +08:00
@bp.route ( ' /modlog ' , methods = [ ' GET ' ] )
def modlog ( ) :
page = request . args . get ( ' page ' , 1 , type = int )
low_bandwidth = request . cookies . get ( ' low_bandwidth ' , ' 0 ' ) == ' 1 '
2024-08-14 07:47:41 +12:00
can_see_names = False
2024-07-07 16:03:35 +08:00
2024-07-07 16:09:50 +08:00
# Admins can see all of the modlog, everyone else can only see public entries
if current_user . is_authenticated :
if current_user . is_admin ( ) or current_user . is_staff ( ) :
modlog_entries = ModLog . query . order_by ( desc ( ModLog . created_at ) )
2024-08-14 07:47:41 +12:00
can_see_names = True
2024-07-07 16:09:50 +08:00
else :
modlog_entries = ModLog . query . filter ( ModLog . public == True ) . order_by ( desc ( ModLog . created_at ) )
else :
modlog_entries = ModLog . query . filter ( ModLog . public == True ) . order_by ( desc ( ModLog . created_at ) )
2024-07-07 16:03:35 +08:00
# Pagination
modlog_entries = modlog_entries . paginate ( page = page , per_page = 100 if not low_bandwidth else 50 , error_out = False )
next_url = url_for ( ' main.modlog ' , page = modlog_entries . next_num ) if modlog_entries . has_next else None
prev_url = url_for ( ' main.modlog ' , page = modlog_entries . prev_num ) if modlog_entries . has_prev and page != 1 else None
return render_template ( ' modlog.html ' ,
2024-08-14 07:47:41 +12:00
title = _ ( ' Moderation Log ' ) , modlog_entries = modlog_entries , can_see_names = can_see_names ,
2024-07-07 16:03:35 +08:00
next_url = next_url , prev_url = prev_url , low_bandwidth = low_bandwidth ,
moderating_communities = moderating_communities ( current_user . get_id ( ) ) ,
joined_communities = joined_communities ( current_user . get_id ( ) ) ,
menu_topics = menu_topics ( ) , site = g . site ,
2024-07-12 19:56:57 +08:00
inoculation = inoculation [ randint ( 0 , len ( inoculation ) - 1 ) ] if g . site . show_inoculation_block else None
2024-07-07 16:03:35 +08:00
)
2024-01-05 16:14:55 +13:00
@bp.route ( ' /donate ' )
def donate ( ) :
return render_template ( ' donate.html ' )
2024-05-11 14:02:18 +12:00
2024-04-01 13:05:09 +02:00
@bp.route ( ' /about ' )
def about_page ( ) :
2024-04-08 14:22:47 +02:00
user_amount = users_total ( )
MAU = active_month ( )
posts_amount = local_posts ( )
2024-06-26 16:24:15 +02:00
admins = Site . admins ( )
staff = Site . staff ( )
2024-04-08 14:22:47 +02:00
domains_amount = db . session . execute ( text ( ' SELECT COUNT(id) as c FROM " domain " WHERE " banned " IS false ' ) ) . scalar ( )
community_amount = local_communities ( )
2024-04-01 13:05:09 +02:00
instance = Instance . query . filter_by ( id = 1 ) . first ( )
2024-06-27 15:38:10 +08:00
return render_template ( ' about.html ' , user_amount = user_amount , mau = MAU , posts_amount = posts_amount ,
domains_amount = domains_amount , community_amount = community_amount , instance = instance ,
admins = admins , staff = staff )
2024-04-01 13:05:09 +02:00
2024-01-05 16:14:55 +13:00
@bp.route ( ' /privacy ' )
def privacy ( ) :
return render_template ( ' privacy.html ' )
2023-12-17 00:12:49 +13:00
@bp.route ( ' /login ' )
def login ( ) :
return redirect ( url_for ( ' auth.login ' ) )
@bp.route ( ' /robots.txt ' )
def robots ( ) :
resp = make_response ( render_template ( ' robots.txt ' ) )
resp . mimetype = ' text/plain '
return resp
2024-01-24 17:02:48 +13:00
@bp.route ( ' /sitemap.xml ' )
@cache.cached ( timeout = 6000 )
def sitemap ( ) :
2024-06-02 16:45:21 +12:00
posts = Post . query . filter ( Post . from_bot == False , Post . deleted == False )
2024-01-24 17:02:48 +13:00
posts = posts . join ( Community , Community . id == Post . community_id )
posts = posts . filter ( Community . show_all == True , Community . ap_id == None ) # sitemap.xml only includes local posts
if not g . site . enable_nsfw :
posts = posts . filter ( Community . nsfw == False )
if not g . site . enable_nsfl :
posts = posts . filter ( Community . nsfl == False )
posts = posts . order_by ( desc ( Post . posted_at ) )
resp = make_response ( render_template ( ' sitemap.xml ' , posts = posts , current_app = current_app ) )
resp . mimetype = ' text/xml '
return resp
2024-01-21 12:14:05 +13:00
@bp.route ( ' /keyboard_shortcuts ' )
def keyboard_shortcuts ( ) :
return render_template ( ' keyboard_shortcuts.html ' )
2024-02-10 12:20:18 +13:00
def list_files ( directory ) :
for root , dirs , files in os . walk ( directory ) :
for file in files :
yield os . path . join ( root , file )
2024-11-29 15:44:33 +00:00
@bp.route ( ' /replay_inbox ' )
@login_required
def replay_inbox ( ) :
from app . activitypub . routes import replay_inbox_request
request_json = { }
"""
request_json = { " @context " : [ " https://join-lemmy.org/context.json " , " https://www.w3.org/ns/activitystreams " ] ,
" actor " : " https://lemmy.lemmy/u/doesnotexist " ,
" cc " : [ ] ,
" id " : " https://lemmy.lemmy/activities/delete/5d42c8bf-cc60-4d2c-a3b5-673ddb7ce64b " ,
" object " : " https://lemmy.lemmy/u/doesnotexist " ,
" to " : [ " https://www.w3.org/ns/activitystreams#Public " ] ,
" type " : " Delete " }
"""
replay_inbox_request ( request_json )
return ' ok '
2023-12-03 22:41:15 +13:00
@bp.route ( ' /test ' )
def test ( ) :
2024-05-21 18:07:07 +12:00
2024-09-15 19:30:45 +12:00
response = get_request ( ' https://rimu.geek.nz ' )
x = ' '
if response . status_code == 200 :
x = response . content
response . close ( )
return x
2024-08-27 19:37:47 +12:00
json = {
" @context " : " https://www.w3.org/ns/activitystreams " ,
" actor " : " https://ioc.exchange/users/haiviittech " ,
" id " : " https://ioc.exchange/users/haiviittech#delete " ,
" object " : " https://ioc.exchange/users/haiviittech " ,
" to " : [
" https://www.w3.org/ns/activitystreams#Public "
] ,
" type " : " Delete "
}
r = User . query . get ( 1 )
jsonld . set_document_loader ( jsonld . requests_document_loader ( timeout = 5 ) )
ld = LDSignature . create_signature ( json , r . private_key , r . public_url ( ) + ' #main-key ' )
json . update ( ld )
LDSignature . verify_signature ( json , r . public_key )
2024-06-20 17:27:36 +08:00
2024-06-02 16:45:21 +12:00
#for community in Community.query.filter(Community.content_retention != -1):
# for post in community.posts.filter(Post.posted_at < utcnow() - timedelta(days=Community.content_retention)):
# post.delete_dependencies()
2024-05-21 18:07:07 +12:00
return ' done '
2024-05-18 11:51:32 +12:00
2024-04-09 13:12:10 +12:00
md = " ::: spoiler I ' m all for ya having fun and your right to hurt yourself. \n \n I am a former racer, commuter, and professional Buyer for a chain of bike shops. I ' m also disabled from the crash involving the 6th and 7th cars that have hit me in the last 170k+ miles of riding. I only barely survived what I simplify as a \" broken neck and back. \" Cars making U-turns are what will get you if you ride long enough, \n \n especially commuting. It will look like just another person turning in front of you, you ' ll compensate like usual, and before your brain can even register what is really happening, what was your normal escape route will close and you ' re going to crash really hard. It is the only kind of crash that your intuition is useless against. \n ::: "
return markdown_to_html ( md )
2024-02-24 14:15:38 +13:00
2024-02-23 16:52:17 +13:00
users_to_notify = User . query . join ( Notification , User . id == Notification . user_id ) . filter (
User . ap_id == None ,
Notification . created_at > User . last_seen ,
Notification . read == False ,
User . email_unread_sent == False , # they have not been emailed since last activity
User . email_unread == True # they want to be emailed
) . all ( )
for user in users_to_notify :
notifications = Notification . query . filter ( Notification . user_id == user . id , Notification . read == False ,
Notification . created_at > user . last_seen ) . all ( )
if notifications :
# Also get the top 20 posts since their last login
posts = Post . query . join ( CommunityMember , Post . community_id == CommunityMember . community_id ) . filter (
CommunityMember . is_banned == False )
posts = posts . filter ( CommunityMember . user_id == user . id )
2024-06-28 13:22:15 +02:00
if user . ignore_bots == 1 :
2024-02-23 16:52:17 +13:00
posts = posts . filter ( Post . from_bot == False )
2024-06-28 15:04:06 +00:00
if user . hide_nsfl == 1 :
2024-02-23 16:52:17 +13:00
posts = posts . filter ( Post . nsfl == False )
2024-06-28 15:04:06 +00:00
if user . hide_nsfw == 1 :
2024-02-23 16:52:17 +13:00
posts = posts . filter ( Post . nsfw == False )
domains_ids = blocked_domains ( user . id )
if domains_ids :
posts = posts . filter ( or_ ( Post . domain_id . not_in ( domains_ids ) , Post . domain_id == None ) )
posts = posts . filter ( Post . posted_at > user . last_seen ) . order_by ( desc ( Post . score ) )
posts = posts . limit ( 20 ) . all ( )
# Send email!
2024-02-24 13:33:28 +13:00
send_email ( _ ( ' [PieFed] You have unread notifications ' ) ,
2024-06-26 10:21:39 +02:00
sender = f ' { g . site . name } < { current_app . config [ " MAIL_FROM " ] } > ' ,
2024-02-23 16:52:17 +13:00
recipients = [ user . email ] ,
text_body = flask . render_template ( ' email/unread_notifications.txt ' , user = user , notifications = notifications ) ,
html_body = flask . render_template ( ' email/unread_notifications.html ' , user = user ,
notifications = notifications ,
posts = posts ,
domain = current_app . config [ ' SERVER_NAME ' ] ) )
user . email_unread_sent = True
db . session . commit ( )
2024-02-19 15:01:53 +13:00
return ' ok '
2023-10-23 13:03:35 +13:00
2024-03-01 16:43:05 +13:00
@bp.route ( ' /test_email ' )
def test_email ( ) :
2024-06-13 10:38:09 +08:00
if current_user . is_anonymous :
email = request . args . get ( ' email ' )
else :
email = current_user . email
send_email ( ' This is a test email ' , f ' { g . site . name } < { current_app . config [ " MAIL_FROM " ] } > ' , [ email ] ,
2024-03-01 16:43:05 +13:00
' This is a test email. If you received this, email sending is working! ' ,
' <p>This is a test email. If you received this, email sending is working!</p> ' )
2024-06-13 10:38:09 +08:00
return f ' Email sent to { email } . '
2024-03-01 16:43:05 +13:00
2024-04-12 10:52:15 +12:00
@bp.route ( ' /find_voters ' )
def find_voters ( ) :
user_ids = db . session . execute ( text ( ' SELECT id from " user " ORDER BY last_seen DESC LIMIT 5000 ' ) ) . scalars ( )
voters = { }
for user_id in user_ids :
recently_downvoted = recently_downvoted_posts ( user_id )
if len ( recently_downvoted ) > 10 :
voters [ user_id ] = str ( recently_downvoted )
return str ( find_duplicate_values ( voters ) )
def find_duplicate_values ( dictionary ) :
# Create a dictionary to store the keys for each value
value_to_keys = { }
# Iterate through the input dictionary
for key , value in dictionary . items ( ) :
# If the value is not already in the dictionary, add it
if value not in value_to_keys :
value_to_keys [ value ] = [ key ]
else :
# If the value is already in the dictionary, append the key to the list
value_to_keys [ value ] . append ( key )
# Filter out the values that have only one key (i.e., unique values)
duplicates = { value : keys for value , keys in value_to_keys . items ( ) if len ( keys ) > 1 }
return duplicates
2024-09-14 15:50:23 +12:00
2023-10-23 13:03:35 +13:00
def verification_warning ( ) :
if hasattr ( current_user , ' verified ' ) and current_user . verified is False :
flash ( _ ( ' Please click the link in your email inbox to verify your account. ' ) , ' warning ' )
2023-12-21 22:14:43 +13:00
2023-12-24 13:28:41 +13:00
@cache.cached ( timeout = 6 )
2023-12-21 22:14:43 +13:00
def activitypub_application ( ) :
application_data = {
' @context ' : default_context ( ) ,
' type ' : ' Application ' ,
' id ' : f " https:// { current_app . config [ ' SERVER_NAME ' ] } / " ,
2024-03-24 15:35:45 +13:00
' name ' : ' PieFed ' ,
' summary ' : g . site . name + ' - ' + g . site . description ,
2023-12-21 22:14:43 +13:00
' published ' : ap_datetime ( g . site . created_at ) ,
' updated ' : ap_datetime ( g . site . updated ) ,
' inbox ' : f " https:// { current_app . config [ ' SERVER_NAME ' ] } /site_inbox " ,
' outbox ' : f " https:// { current_app . config [ ' SERVER_NAME ' ] } /site_outbox " ,
2024-05-22 16:42:47 +01:00
' icon ' : {
' type ' : ' Image ' ,
' url ' : f " https:// { current_app . config [ ' SERVER_NAME ' ] } /static/images/logo2.png "
} ,
' publicKey ' : {
' id ' : f " https:// { current_app . config [ ' SERVER_NAME ' ] } /#main-key " ,
' owner ' : f " https:// { current_app . config [ ' SERVER_NAME ' ] } / " ,
' publicKeyPem ' : g . site . public_key
}
2023-12-21 22:14:43 +13:00
}
resp = jsonify ( application_data )
resp . content_type = ' application/activity+json '
return resp
2024-05-04 21:26:39 +01:00
# instance actor (literally uses the word 'actor' without the /u/)
# required for interacting with instances using 'secure mode' (aka authorized fetch)
@bp.route ( ' /actor ' , methods = [ ' GET ' ] )
def instance_actor ( ) :
application_data = {
' @context ' : default_context ( ) ,
' type ' : ' Application ' ,
' id ' : f " https:// { current_app . config [ ' SERVER_NAME ' ] } /actor " ,
' preferredUsername ' : f " { current_app . config [ ' SERVER_NAME ' ] } " ,
' url ' : f " https:// { current_app . config [ ' SERVER_NAME ' ] } /about " ,
' manuallyApprovesFollowers ' : True ,
' inbox ' : f " https:// { current_app . config [ ' SERVER_NAME ' ] } /actor/inbox " ,
' outbox ' : f " https:// { current_app . config [ ' SERVER_NAME ' ] } /actor/outbox " ,
' publicKey ' : {
' id ' : f " https:// { current_app . config [ ' SERVER_NAME ' ] } /actor#main-key " ,
' owner ' : f " https:// { current_app . config [ ' SERVER_NAME ' ] } /actor " ,
' publicKeyPem ' : g . site . public_key
} ,
' endpoints ' : {
' sharedInbox ' : f " https:// { current_app . config [ ' SERVER_NAME ' ] } /site_inbox " ,
}
}
resp = jsonify ( application_data )
resp . content_type = ' application/activity+json '
return resp