From 1f7f2967e7b6c01c4260a78c9e4dd1637c102415 Mon Sep 17 00:00:00 2001 From: rimu <3310831+rimu@users.noreply.github.com> Date: Mon, 4 Mar 2024 12:13:14 +1300 Subject: [PATCH] sub-topics - admin area #44 --- app/admin/forms.py | 2 +- app/admin/routes.py | 50 ++++++++----------- app/admin/util.py | 41 ++++++++++++++- app/models.py | 2 +- app/templates/admin/topics.html | 26 +++++++--- .../e72aa356e4d0_increase_alt_text_length.py | 38 ++++++++++++++ 6 files changed, 119 insertions(+), 40 deletions(-) create mode 100644 migrations/versions/e72aa356e4d0_increase_alt_text_length.py diff --git a/app/admin/forms.py b/app/admin/forms.py index 6a759280..1a50d314 100644 --- a/app/admin/forms.py +++ b/app/admin/forms.py @@ -95,7 +95,7 @@ class EditCommunityForm(FlaskForm): class EditTopicForm(FlaskForm): name = StringField(_l('Name'), validators=[DataRequired()]) machine_name = StringField(_l('Url'), validators=[DataRequired()]) - add_community = SelectField(_l('Community to add'), coerce=int, validators=[Optional()]) + parent_id = SelectField(_l('Parent topic'), coerce=int, validators=[Optional()]) submit = SubmitField(_l('Save')) diff --git a/app/admin/routes.py b/app/admin/routes.py index b09292e9..4e55193f 100644 --- a/app/admin/routes.py +++ b/app/admin/routes.py @@ -12,7 +12,8 @@ from app.activitypub.signature import post_request from app.activitypub.util import default_context from app.admin.forms import FederationForm, SiteMiscForm, SiteProfileForm, EditCommunityForm, EditUserForm, \ EditTopicForm, SendNewsletterForm, AddUserForm -from app.admin.util import unsubscribe_from_everything_then_delete, unsubscribe_from_community, send_newsletter +from app.admin.util import unsubscribe_from_everything_then_delete, unsubscribe_from_community, send_newsletter, \ + topic_tree, topics_for_form from app.community.util import save_icon_file, save_banner_file from app.models import AllowedInstances, BannedInstances, ActivityPubLog, utcnow, Site, Community, CommunityMember, \ User, Instance, File, Report, Topic, UserRegistration, Role, Post @@ -212,29 +213,13 @@ def admin_communities(): site=g.site) -def topics_for_form(): - topics = Topic.query.order_by(Topic.name).all() - result = [(0, _('None'))] - for topic in topics: - result.append((topic.id, topic.name)) - return result - - -def communities_for_form(): - communities = Community.query.order_by(Community.title).all() - result = [(0, _('None'))] - for community in communities: - result.append((community.id, community.title)) - return result - - @bp.route('/community//edit', methods=['GET', 'POST']) @login_required @permission_required('administer all communities') def admin_community_edit(community_id): form = EditCommunityForm() community = Community.query.get_or_404(community_id) - form.topic.choices = topics_for_form() + form.topic.choices = topics_for_form(0) if form.validate_on_submit(): community.name = form.url.data community.title = form.title.data @@ -253,6 +238,7 @@ def admin_community_edit(community_id): community.content_retention = form.content_retention.data community.topic_id = form.topic.data if form.topic.data != 0 else None community.default_layout = form.default_layout.data + icon_file = request.files['icon_file'] if icon_file and icon_file.filename != '': if community.icon_id: @@ -268,6 +254,8 @@ def admin_community_edit(community_id): if file: community.image = file + db.session.commit() + community.topic.num_communities = community.topic.communities.count() db.session.commit() flash(_('Saved')) return redirect(url_for('admin.admin_communities')) @@ -341,7 +329,7 @@ def unsubscribe_everyone_then_delete_task(community_id): @login_required @permission_required('administer all communities') def admin_topics(): - topics = Topic.query.order_by(Topic.name).all() + topics = topic_tree() return render_template('admin/topics.html', title=_('Topics'), topics=topics, moderating_communities=moderating_communities(current_user.get_id()), joined_communities=joined_communities(current_user.get_id()), @@ -354,16 +342,16 @@ def admin_topics(): @permission_required('administer all communities') def admin_topic_add(): form = EditTopicForm() - form.add_community.choices = communities_for_form() + form.parent_id.choices = topics_for_form(0) if form.validate_on_submit(): topic = Topic(name=form.name.data, machine_name=form.machine_name.data, num_communities=0) + if form.parent_id.data: + topic.parent_id = form.parent_id.data + else: + topic.parent_id = None db.session.add(topic) db.session.commit() - if form.add_community.data: - community = Community.query.get(form.add_community.data) - community.topic_id = topic.id - topic.num_communities += 1 - db.session.commit() + flash(_('Saved')) return redirect(url_for('admin.admin_topics')) @@ -379,20 +367,22 @@ def admin_topic_add(): def admin_topic_edit(topic_id): form = EditTopicForm() topic = Topic.query.get_or_404(topic_id) - form.add_community.choices = communities_for_form() + form.parent_id.choices = topics_for_form(topic_id) if form.validate_on_submit(): topic.name = form.name.data - topic.num_communities = topic.communities.count() + 1 + topic.num_communities = topic.communities.count() topic.machine_name = form.machine_name.data - if form.add_community.data: - community = Community.query.get(form.add_community.data) - community.topic_id = topic.id + if form.parent_id.data: + topic.parent_id = form.parent_id.data + else: + topic.parent_id = None db.session.commit() flash(_('Saved')) return redirect(url_for('admin.admin_topics')) else: form.name.data = topic.name form.machine_name.data = topic.machine_name + form.parent_id.data = topic.parent_id return render_template('admin/edit_topic.html', title=_('Edit topic'), form=form, topic=topic, moderating_communities=moderating_communities(current_user.get_id()), joined_communities=joined_communities(current_user.get_id()), diff --git a/app/admin/util.py b/app/admin/util.py index c076c222..b1669ac1 100644 --- a/app/admin/util.py +++ b/app/admin/util.py @@ -1,11 +1,14 @@ +from typing import List, Tuple + from flask import request, abort, g, current_app, json, flash, render_template from flask_login import current_user from sqlalchemy import text, desc +from flask_babel import _ from app import db, cache, celery from app.activitypub.signature import post_request from app.activitypub.util import default_context -from app.models import User, Community, Instance, Site, ActivityPubLog, CommunityMember +from app.models import User, Community, Instance, Site, ActivityPubLog, CommunityMember, Topic from app.utils import gibberish @@ -101,3 +104,39 @@ def send_newsletter(form): if form.test.data: break + + +# replies to a post, in a tree, sorted by a variety of methods +def topic_tree() -> List: + topics = Topic.query.order_by(Topic.name) + + topics_dict = {topic.id: {'topic': topic, 'children': []} for topic in topics.all()} + + for topic in topics: + if topic.parent_id is not None: + parent_comment = topics_dict.get(topic.parent_id) + if parent_comment: + parent_comment['children'].append(topics_dict[topic.id]) + + return [topic for topic in topics_dict.values() if topic['topic'].parent_id is None] + + +def topics_for_form(current_topic: int) -> List[Tuple[int, str]]: + result = [(0, _('None'))] + topics = topic_tree() + for topic in topics: + if topic['topic'].id != current_topic: + result.append((topic['topic'].id, topic['topic'].name)) + if topic['children']: + result.extend(topics_for_form_children(topic['children'], current_topic, 1)) + return result + + +def topics_for_form_children(topics, current_topic: int, depth: int) -> List[Tuple[int, str]]: + result = [] + for topic in topics: + if topic['topic'].id != current_topic: + result.append((topic['topic'].id, '--' * depth + ' ' + topic['topic'].name)) + if topic['children']: + result.extend(topics_for_form_children(topic['children'], current_topic, depth + 1)) + return result diff --git a/app/models.py b/app/models.py index 6b8a36ae..6bb9623b 100644 --- a/app/models.py +++ b/app/models.py @@ -172,7 +172,7 @@ class File(db.Model): file_name = db.Column(db.String(255)) width = db.Column(db.Integer) height = db.Column(db.Integer) - alt_text = db.Column(db.String(256)) + alt_text = db.Column(db.String(300)) source_url = db.Column(db.String(1024)) thumbnail_path = db.Column(db.String(255)) thumbnail_width = db.Column(db.Integer) diff --git a/app/templates/admin/topics.html b/app/templates/admin/topics.html index 7bba2707..7763a83f 100644 --- a/app/templates/admin/topics.html +++ b/app/templates/admin/topics.html @@ -11,6 +11,24 @@ {% include 'admin/_nav.html' %} +{% macro render_topic(topic, depth) %} + + {{ '--' * depth }} {{ topic['topic'].name }} + {{ topic['topic'].num_communities }} + Edit | + {% if topic['topic'].num_communities == 0 %} + Delete + {% else %} + Delete + {% endif %} + + + {% if topic['children'] %} + {% for topic in topic['children'] %} + {{ render_topic(topic, depth + 1)|safe }} + {% endfor %} + {% endif %} +{% endmacro %}
@@ -22,13 +40,7 @@ Actions {% for topic in topics %} - - {{ topic.name }} - {{ topic.num_communities }} - Edit | - Delete - - + {{ render_topic(topic, 0)|safe }} {% endfor %}
diff --git a/migrations/versions/e72aa356e4d0_increase_alt_text_length.py b/migrations/versions/e72aa356e4d0_increase_alt_text_length.py new file mode 100644 index 00000000..bc0cac28 --- /dev/null +++ b/migrations/versions/e72aa356e4d0_increase_alt_text_length.py @@ -0,0 +1,38 @@ +"""increase alt text length + +Revision ID: e72aa356e4d0 +Revises: a88efa63415b +Create Date: 2024-03-04 12:12:07.458127 + +""" +from alembic import op +import sqlalchemy as sa + + +# revision identifiers, used by Alembic. +revision = 'e72aa356e4d0' +down_revision = 'a88efa63415b' +branch_labels = None +depends_on = None + + +def upgrade(): + # ### commands auto generated by Alembic - please adjust! ### + with op.batch_alter_table('file', schema=None) as batch_op: + batch_op.alter_column('alt_text', + existing_type=sa.VARCHAR(length=256), + type_=sa.String(length=300), + existing_nullable=True) + + # ### end Alembic commands ### + + +def downgrade(): + # ### commands auto generated by Alembic - please adjust! ### + with op.batch_alter_table('file', schema=None) as batch_op: + batch_op.alter_column('alt_text', + existing_type=sa.String(length=300), + type_=sa.VARCHAR(length=256), + existing_nullable=True) + + # ### end Alembic commands ###