make create guild threshold configurable, add savepoint
This commit is contained in:
parent
71042a720c
commit
a88b12e844
5 changed files with 53 additions and 15 deletions
|
|
@ -6,15 +6,18 @@
|
||||||
- Users can now block each other
|
- Users can now block each other
|
||||||
+ Blocking a user prevents them from seeing your comments, posts (standalone or in feed) and profile
|
+ Blocking a user prevents them from seeing your comments, posts (standalone or in feed) and profile
|
||||||
- Added user strikes: a strike logs the content of a removed message for future use
|
- Added user strikes: a strike logs the content of a removed message for future use
|
||||||
|
- Added ✨**color themes**✨
|
||||||
- Posts may now be deleted by author. If it has comments, comments are not spared
|
- Posts may now be deleted by author. If it has comments, comments are not spared
|
||||||
|
- If a user for some reason can't post, their post is blocked and they can choose to post it onto another community. Previously it got posted to the user page.
|
||||||
- Moderators (and admins) have now access to mod tools
|
- Moderators (and admins) have now access to mod tools
|
||||||
+ Allowed operations: change display name, description, restriction status, and exile (guild-local ban) members
|
+ Allowed operations: change display name, description, restriction status, and exile (guild-local ban) members
|
||||||
+ Site administrators and guild owners can add moderators
|
+ Site administrators and guild owners can add moderators
|
||||||
- Administrators can claim ownership of abandoned guilds
|
- Administrators can claim ownership of abandoned guilds
|
||||||
- Implemented guild subscriptions (not as in $$$, yes as in the follow button)
|
- Implemented guild subscriptions (not as in $$$, yes as in the follow button)
|
||||||
- Added ✨color themes✨
|
- Minimum karma requirement for creating a guild is now configurable via env variable `FREAK_CREATE_GUILD_THRESHOLD` (previously hardcoded at 15)
|
||||||
- Users can now set their display name, biography and color theme in `/settings`
|
- Users can now set their display name, biography and color theme in `/settings`
|
||||||
- You can now add an impressum in .env, e.g. `IMPRESSUM='Acme Ltd.::1 Short Island::Old York, Divided States::Responsible: ::Donald Duck'` Lines are separated by two colons. Version before 0.4.0 CAN'T BE RUN in German-speaking countries as of 2025.
|
- Impressum can now be set in .env, e.g. `IMPRESSUM='Acme Ltd.::1 Short Island::Old York, Divided States::Responsible: ::Donald Duck'` Lines are separated by two colons. **Versions before 0.4.0 CAN'T BE RUN in German-speaking countries** as of 2025.
|
||||||
|
- Several aesthetic improvements
|
||||||
|
|
||||||
## 0.3.3
|
## 0.3.3
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -40,6 +40,7 @@ class AppConfig(ConfigOptions):
|
||||||
jquery_url = ConfigValue(default='https://ajax.googleapis.com/ajax/libs/jquery/3.7.1/jquery.min.js')
|
jquery_url = ConfigValue(default='https://ajax.googleapis.com/ajax/libs/jquery/3.7.1/jquery.min.js')
|
||||||
app_is_behind_proxy = ConfigValue(cast=bool, default=False)
|
app_is_behind_proxy = ConfigValue(cast=bool, default=False)
|
||||||
impressum = ConfigValue(cast=twocolon_list, default='')
|
impressum = ConfigValue(cast=twocolon_list, default='')
|
||||||
|
create_guild_threshold = ConfigValue(cast=int, default=15, prefix='freak_')
|
||||||
|
|
||||||
app_config = AppConfig()
|
app_config = AppConfig()
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -220,8 +220,8 @@ class User(Base):
|
||||||
db.session.commit()
|
db.session.commit()
|
||||||
|
|
||||||
def can_create_guild(self):
|
def can_create_guild(self):
|
||||||
## TODO make guild creation requirements configurable
|
## TODO make guild creation requirements fully configurable
|
||||||
return self.karma > 15 or self.is_administrator
|
return self.karma > app_config.create_guild_threshold or self.is_administrator
|
||||||
|
|
||||||
can_create_community = deprecated('use .can_create_guild()')(can_create_guild)
|
can_create_community = deprecated('use .can_create_guild()')(can_create_guild)
|
||||||
|
|
||||||
|
|
@ -356,6 +356,19 @@ class Guild(Base):
|
||||||
u = db.session.execute(select(Member).where(Member.user_id == other.id, Member.guild_id == self.id)).scalar()
|
u = db.session.execute(select(Member).where(Member.user_id == other.id, Member.guild_id == self.id)).scalar()
|
||||||
return u.is_banned if u else False
|
return u.is_banned if u else False
|
||||||
|
|
||||||
|
def allows_posting(self, other: User) -> bool:
|
||||||
|
if self.owner is None:
|
||||||
|
return False
|
||||||
|
if other.is_disabled:
|
||||||
|
return False
|
||||||
|
mem: Member | None = db.session.execute(select(Member).where(Member.user_id == other.id, Member.guild_id == self.id)).scalar() if other else None
|
||||||
|
if mem and mem.is_banned:
|
||||||
|
return False
|
||||||
|
if self.is_restricted:
|
||||||
|
return mem and mem.is_approved
|
||||||
|
return True
|
||||||
|
|
||||||
|
|
||||||
def moderators(self):
|
def moderators(self):
|
||||||
if self.owner:
|
if self.owner:
|
||||||
yield ModeratorInfo(self.owner, True)
|
yield ModeratorInfo(self.owner, True)
|
||||||
|
|
|
||||||
|
|
@ -14,15 +14,16 @@
|
||||||
<input type="hidden" name="csrf_token" value="{{ csrf_token() }}">
|
<input type="hidden" name="csrf_token" value="{{ csrf_token() }}">
|
||||||
<div>
|
<div>
|
||||||
<p>Posting as <strong>{{ current_user.handle() }}</strong></p>
|
<p>Posting as <strong>{{ current_user.handle() }}</strong></p>
|
||||||
<p>Post to: <input type="text" name="to" placeholder="{{ current_user.handle() }}"></p>
|
<p>Post to: <input type="text" name="to" placeholder="{{ current_user.handle() }}" value="{{ sv_target }}"></p>
|
||||||
<div>
|
<div>
|
||||||
<input type="text" name="title" placeholder="An interesting title" maxlength="256" class="fullwidth" />
|
<input type="text" name="title" placeholder="An interesting title" maxlength="256" class="fullwidth" value="{{ sv_title }}" />
|
||||||
</div>
|
</div>
|
||||||
|
<hr />
|
||||||
<div>
|
<div>
|
||||||
<textarea name="text" placeholder="What's happening?" class="create_text fullwidth">{{ request.args['preload'] }}</textarea>
|
<textarea name="text" placeholder="What's happening ~" class="create_text fullwidth">{{ sv_content }}</textarea>
|
||||||
</div>
|
</div>
|
||||||
{#<dd id="fileInputContainer"><a href="javascript:attachFileInput();">Add a file...</a>#}
|
{#<dd id="fileInputContainer"><a href="javascript:attachFileInput();">Add a file...</a>#}
|
||||||
<div>{{ privacy_select() }}</div>
|
<div>{{ privacy_select(sv_privacy) }}</div>
|
||||||
<div><button type="submit" class="primary">Create</button></div>
|
<div><button type="submit" class="primary">Create</button></div>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
|
|
|
||||||
|
|
@ -7,23 +7,43 @@ from flask_login import current_user, login_required
|
||||||
from sqlalchemy import insert, select
|
from sqlalchemy import insert, select
|
||||||
from ..models import User, db, Guild, Post
|
from ..models import User, db, Guild, Post
|
||||||
|
|
||||||
|
current_user: User
|
||||||
|
|
||||||
bp = Blueprint('create', __name__)
|
bp = Blueprint('create', __name__)
|
||||||
|
|
||||||
|
def create_savepoint(
|
||||||
|
target = '', title = '', content = '',
|
||||||
|
privacy = 0
|
||||||
|
):
|
||||||
|
return render_template('create.html',
|
||||||
|
sv_target = target,
|
||||||
|
sv_title = title,
|
||||||
|
sv_content = content,
|
||||||
|
sv_privacy = privacy
|
||||||
|
)
|
||||||
|
|
||||||
@bp.route('/create/', methods=['GET', 'POST'])
|
@bp.route('/create/', methods=['GET', 'POST'])
|
||||||
@login_required
|
@login_required
|
||||||
def create():
|
def create():
|
||||||
user: User = current_user
|
user: User = current_user
|
||||||
if request.method == 'POST' and 'title' in request.form:
|
if request.method == 'POST' and 'title' in request.form:
|
||||||
gname = request.form['to']
|
gname = request.form['to']
|
||||||
if gname:
|
|
||||||
guild: Guild | None = db.session.execute(select(Guild).where(Guild.name == gname)).scalar()
|
|
||||||
if guild is None:
|
|
||||||
flash(f'Guild +{gname} not found or inaccessible, posting to your user page instead')
|
|
||||||
else:
|
|
||||||
guild = None
|
|
||||||
title = request.form['title']
|
title = request.form['title']
|
||||||
text = request.form['text']
|
text = request.form['text']
|
||||||
privacy = int(request.form.get('privacy', '0'))
|
privacy = int(request.form.get('privacy', '0'))
|
||||||
|
if gname:
|
||||||
|
guild: Guild | None = db.session.execute(select(Guild).where(Guild.name == gname)).scalar()
|
||||||
|
if guild is None:
|
||||||
|
flash(f'Guild +{gname} not found or inaccessible')
|
||||||
|
return create_savepoint('', title, text, privacy)
|
||||||
|
if guild.has_exiled(user):
|
||||||
|
flash(f'You are banned from +{gname}')
|
||||||
|
return create_savepoint('', title, text, privacy)
|
||||||
|
if not guild.allows_posting(user):
|
||||||
|
flash(f'You can\'t post on +{gname}')
|
||||||
|
return create_savepoint('', title, text, privacy)
|
||||||
|
else:
|
||||||
|
guild = None
|
||||||
try:
|
try:
|
||||||
new_post: Post = db.session.execute(insert(Post).values(
|
new_post: Post = db.session.execute(insert(Post).values(
|
||||||
author_id = user.id,
|
author_id = user.id,
|
||||||
|
|
@ -40,7 +60,7 @@ def create():
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
sys.excepthook(*sys.exc_info())
|
sys.excepthook(*sys.exc_info())
|
||||||
flash('Unable to publish!')
|
flash('Unable to publish!')
|
||||||
return render_template('create.html')
|
return create_savepoint(target=request.args.get('on',''))
|
||||||
|
|
||||||
|
|
||||||
@bp.route('/createguild/', methods=['GET', 'POST'])
|
@bp.route('/createguild/', methods=['GET', 'POST'])
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue