diff --git a/CHANGELOG.md b/CHANGELOG.md index 6ba5f63..3b89685 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,15 +6,18 @@ - Users can now block each other + 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 ✨**color themes**✨ - 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 + Allowed operations: change display name, description, restriction status, and exile (guild-local ban) members + Site administrators and guild owners can add moderators - Administrators can claim ownership of abandoned guilds - 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` -- 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 diff --git a/freak/__init__.py b/freak/__init__.py index 25f7452..e84954c 100644 --- a/freak/__init__.py +++ b/freak/__init__.py @@ -40,6 +40,7 @@ class AppConfig(ConfigOptions): 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) impressum = ConfigValue(cast=twocolon_list, default='') + create_guild_threshold = ConfigValue(cast=int, default=15, prefix='freak_') app_config = AppConfig() diff --git a/freak/models.py b/freak/models.py index f2f4657..ab0e6b3 100644 --- a/freak/models.py +++ b/freak/models.py @@ -220,8 +220,8 @@ class User(Base): db.session.commit() def can_create_guild(self): - ## TODO make guild creation requirements configurable - return self.karma > 15 or self.is_administrator + ## TODO make guild creation requirements fully configurable + return self.karma > app_config.create_guild_threshold or self.is_administrator 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() 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): if self.owner: yield ModeratorInfo(self.owner, True) diff --git a/freak/templates/create.html b/freak/templates/create.html index db3f011..5e5095c 100644 --- a/freak/templates/create.html +++ b/freak/templates/create.html @@ -14,15 +14,16 @@

Posting as {{ current_user.handle() }}

-

Post to:

+

Post to:

- +
+
- +
{#
Add a file...#} -
{{ privacy_select() }}
+
{{ privacy_select(sv_privacy) }}
diff --git a/freak/website/create.py b/freak/website/create.py index 59b50cc..ecbd05f 100644 --- a/freak/website/create.py +++ b/freak/website/create.py @@ -7,23 +7,43 @@ from flask_login import current_user, login_required from sqlalchemy import insert, select from ..models import User, db, Guild, Post +current_user: User + 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']) @login_required def create(): user: User = current_user if request.method == 'POST' and 'title' in request.form: 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'] text = request.form['text'] 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: new_post: Post = db.session.execute(insert(Post).values( author_id = user.id, @@ -40,7 +60,7 @@ def create(): except Exception as e: sys.excepthook(*sys.exc_info()) flash('Unable to publish!') - return render_template('create.html') + return create_savepoint(target=request.args.get('on','')) @bp.route('/createguild/', methods=['GET', 'POST'])