sub-topics - admin area #44

This commit is contained in:
rimu 2024-03-04 12:13:14 +13:00
parent b9a88a7fa6
commit 1f7f2967e7
6 changed files with 119 additions and 40 deletions

View file

@ -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'))

View file

@ -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/<int:community_id>/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()),

View file

@ -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

View file

@ -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)

View file

@ -11,6 +11,24 @@
{% include 'admin/_nav.html' %}
</div>
</div>
{% macro render_topic(topic, depth) %}
<tr>
<td nowrap="nowrap">{{ '--' * depth }} {{ topic['topic'].name }}</td>
<td>{{ topic['topic'].num_communities }}</td>
<td><a href="{{ url_for('admin.admin_topic_edit', topic_id=topic['topic'].id) }}">Edit</a> |
{% if topic['topic'].num_communities == 0 %}
<a href="{{ url_for('admin.admin_topic_delete', topic_id=topic['topic'].id) }}" class="confirm_first">Delete</a>
{% else %}
Delete
{% endif %}
</td>
</tr>
{% if topic['children'] %}
{% for topic in topic['children'] %}
{{ render_topic(topic, depth + 1)|safe }}
{% endfor %}
{% endif %}
{% endmacro %}
<div class="row">
<div class="col">
@ -22,13 +40,7 @@
<th>Actions</th>
</tr>
{% for topic in topics %}
<tr>
<td>{{ topic.name }}</td>
<td>{{ topic.num_communities }}</td>
<td><a href="{{ url_for('admin.admin_topic_edit', topic_id=topic.id) }}">Edit</a> |
<a href="{{ url_for('admin.admin_topic_delete', topic_id=topic.id) }}" class="confirm_first">Delete</a>
</td>
</tr>
{{ render_topic(topic, 0)|safe }}
{% endfor %}
</table>
</div>

View file

@ -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 ###