2023-08-29 22:01:06 +12:00
from datetime import date , datetime , timedelta
2023-09-05 20:25:02 +12:00
from flask import render_template , redirect , url_for , flash , request , make_response , session , Markup , current_app , abort
2023-08-29 22:01:06 +12:00
from flask_login import login_user , logout_user , current_user
from flask_babel import _
from app import db
2023-09-03 16:30:20 +12:00
from app . activitypub . signature import RsaKeys
from app . community . forms import SearchRemoteCommunity , AddLocalCommunity
2023-09-05 20:25:02 +12:00
from app . community . util import search_for_community , community_url_exists
from app . constants import SUBSCRIPTION_MEMBER , SUBSCRIPTION_OWNER
2023-09-03 16:30:20 +12:00
from app . models import User , Community , CommunityMember
2023-08-29 22:01:06 +12:00
from app . community import bp
2023-09-03 16:30:20 +12:00
from app . utils import get_setting
2023-09-05 20:25:02 +12:00
from sqlalchemy import or_
2023-08-29 22:01:06 +12:00
@bp.route ( ' /add_local ' , methods = [ ' GET ' , ' POST ' ] )
def add_local ( ) :
form = AddLocalCommunity ( )
2023-09-03 16:30:20 +12:00
if get_setting ( ' allow_nsfw ' , False ) is False :
form . nsfw . render_kw = { ' disabled ' : True }
2023-09-05 20:25:02 +12:00
if form . validate_on_submit ( ) and not community_url_exists ( form . url . data ) :
# todo: more intense data validation
if form . url . data . trim ( ) . lower ( ) . startswith ( ' /c/ ' ) :
form . url . data = form . url . data [ 3 : ]
2023-09-03 16:30:20 +12:00
private_key , public_key = RsaKeys . generate_keypair ( )
community = Community ( title = form . community_name . data , name = form . url . data , description = form . description . data ,
rules = form . rules . data , nsfw = form . nsfw . data , private_key = private_key , public_key = public_key ,
subscriptions_count = 1 )
db . session . add ( community )
db . session . commit ( )
membership = CommunityMember ( user_id = current_user . id , community_id = community . id , is_moderator = True ,
is_owner = True )
db . session . add ( membership )
db . session . commit ( )
flash ( _ ( ' Your new community has been created. ' ) )
return redirect ( ' /c/ ' + community . name )
return render_template ( ' community/add_local.html ' , title = _ ( ' Create community ' ) , form = form )
2023-08-29 22:01:06 +12:00
@bp.route ( ' /add_remote ' , methods = [ ' GET ' , ' POST ' ] )
def add_remote ( ) :
form = SearchRemoteCommunity ( )
new_community = None
if form . validate_on_submit ( ) :
address = form . address . data . strip ( )
if address . startswith ( ' ! ' ) and ' @ ' in address :
new_community = search_for_community ( address )
elif address . startswith ( ' @ ' ) and ' @ ' in address [ 1 : ] :
# todo: the user is searching for a person instead
. . .
elif ' @ ' in address :
new_community = search_for_community ( ' ! ' + address )
else :
message = Markup ( ' Type address in the format !community@server.name. Search on <a href= " https://lemmyverse.net/communities " >Lemmyverse.net</a> to find some. ' )
flash ( message , ' error ' )
return render_template ( ' community/add_remote.html ' ,
title = _ ( ' Add remote community ' ) , form = form , new_community = new_community ,
subscribed = current_user . subscribed ( new_community ) > = SUBSCRIPTION_MEMBER )
# @bp.route('/c/<actor>', methods=['GET']) - defined in activitypub/routes.py, which calls this function for user requests. A bit weird.
def show_community ( community : Community ) :
2023-09-05 20:25:02 +12:00
mods = CommunityMember . query . filter ( ( CommunityMember . community_id == community . id ) &
( or_ (
CommunityMember . is_owner ,
CommunityMember . is_moderator
) )
) . all ( )
is_moderator = any ( mod . user_id == current_user . id for mod in mods )
is_owner = any ( mod . user_id == current_user . id and mod . is_owner == True for mod in mods )
if community . private_mods :
mod_list = [ ]
else :
mod_user_ids = [ mod . user_id for mod in mods ]
mod_list = User . query . filter ( User . id . in_ ( mod_user_ids ) ) . all ( )
return render_template ( ' community/community.html ' , community = community , title = community . title ,
is_moderator = is_moderator , is_owner = is_owner , mods = mod_list )
@bp.route ( ' /<actor>/subscribe ' , methods = [ ' GET ' ] )
def subscribe ( actor ) :
actor = actor . strip ( )
if ' @ ' in actor :
community = Community . query . filter_by ( banned = False , ap_id = actor ) . first ( )
else :
community = Community . query . filter_by ( name = actor , banned = False , ap_id = None ) . first ( )
if community is not None :
if not current_user . subscribed ( community ) :
membership = CommunityMember ( user_id = current_user . id , community_id = community . id )
db . session . add ( membership )
db . session . commit ( )
flash ( ' You have subscribed to ' + community . title )
referrer = request . headers . get ( ' Referer ' , None )
if referrer is not None :
return redirect ( referrer )
else :
return redirect ( ' /c/ ' + actor )
else :
abort ( 404 )
@bp.route ( ' /<actor>/unsubscribe ' , methods = [ ' GET ' ] )
def unsubscribe ( actor ) :
actor = actor . strip ( )
if ' @ ' in actor :
community = Community . query . filter_by ( banned = False , ap_id = actor ) . first ( )
else :
community = Community . query . filter_by ( name = actor , banned = False , ap_id = None ) . first ( )
if community is not None :
subscription = current_user . subscribed ( community )
if subscription :
if subscription != SUBSCRIPTION_OWNER :
db . session . query ( CommunityMember ) . filter_by ( user_id = current_user . id , community_id = community . id ) . delete ( )
db . session . commit ( )
flash ( ' You are unsubscribed from ' + community . title )
else :
# todo: community deletion
flash ( ' You need to make someone else the owner before unsubscribing. ' , ' warning ' )
# send them back where they came from
referrer = request . headers . get ( ' Referer ' , None )
if referrer is not None :
return redirect ( referrer )
else :
return redirect ( ' /c/ ' + actor )
else :
abort ( 404 )