From af61b21fc8bdd11bc7e5cfcc8e0e155422a441ec Mon Sep 17 00:00:00 2001 From: Darks Date: Tue, 25 Jul 2023 22:26:16 +0200 Subject: [PATCH] news: add summary and thumbnails to topics Provides data for homepage, as well as others topics --- app/forms/forum.py | 18 +++--- app/models/topic.py | 10 ++- app/routes/forum/index.py | 5 ++ app/routes/posts/edit.py | 7 +++ app/templates/forum/edit_topic.html | 16 +++++ app/templates/forum/forum.html | 16 +++++ app/templates/forum/topic.html | 4 ++ app/templates/index.html | 61 +++---------------- app/utils/validators/__init__.py | 10 +++ ...a93bd5_topics_add_summary_and_thumbnail.py | 36 +++++++++++ 10 files changed, 122 insertions(+), 61 deletions(-) create mode 100644 migrations/versions/a8f539a93bd5_topics_add_summary_and_thumbnail.py diff --git a/app/forms/forum.py b/app/forms/forum.py index d28d873..fe24ed6 100644 --- a/app/forms/forum.py +++ b/app/forms/forum.py @@ -1,6 +1,6 @@ from flask_wtf import FlaskForm -from wtforms import StringField, SubmitField, TextAreaField, MultipleFileField, SelectField -from wtforms.validators import InputRequired, Length +from wtforms import StringField, SubmitField, TextAreaField, MultipleFileField, SelectField, DecimalField +from wtforms.validators import InputRequired, Length, Optional import app.utils.validators as vd from app.utils.antibot_field import AntibotField @@ -54,6 +54,14 @@ class TopicCreationForm(CommentForm): 'Nom du sujet', validators=[InputRequired(), Length(min=3, max=128)]) + summary = TextAreaField( + 'Résumé', + validators=[Optional(), Length(min=3, max=128)]) + + thumbnail = DecimalField( + 'N° de l’illustration', + validators=[Optional(), vd.attachment_exists]) + submit = SubmitField('Créer le sujet') @@ -61,11 +69,7 @@ class AnonymousTopicCreationForm(TopicCreationForm, AnonymousCommentForm): ab = AntibotField() -class TopicEditForm(CommentEditForm): - title = StringField( - 'Nom du sujet', - validators=[InputRequired(), Length(min=3, max=128)]) - +class TopicEditForm(TopicCreationForm): # List of forums is generated at runtime forum = SelectField( 'Forum', diff --git a/app/models/topic.py b/app/models/topic.py index 89383d5..1f96cc1 100644 --- a/app/models/topic.py +++ b/app/models/topic.py @@ -1,6 +1,7 @@ from app import db from app.models.post import Post from sqlalchemy.orm import backref +from sqlalchemy.dialects.postgresql import UUID class Topic(Post): __tablename__ = 'topic' @@ -29,10 +30,17 @@ class Topic(Post): backref=backref('topics', lazy='dynamic'), foreign_keys=forum_id) # Associated thread - thread_id = db.Column(db.Integer,db.ForeignKey('thread.id'),nullable=False) + thread_id = db.Column(db.Integer, db.ForeignKey('thread.id'), nullable=False) thread = db.relationship('Thread', foreign_keys=thread_id, back_populates='owner_topic') + # Summary + summary = db.Column(db.UnicodeText) + + # ID of thumbnail + thumbnail_id = db.Column(UUID(as_uuid=True), db.ForeignKey('attachment.id'), nullable=True) + thumbnail = db.relationship('Attachment', foreign_keys=thumbnail_id, lazy='joined') + # Number of views in the forum views = db.Column(db.Integer) diff --git a/app/routes/forum/index.py b/app/routes/forum/index.py index ad9c680..c660e69 100644 --- a/app/routes/forum/index.py +++ b/app/routes/forum/index.py @@ -54,6 +54,7 @@ def forum_page(f, page=1): db.session.merge(th) t = Topic(f, author, form.title.data, th) + t.summary = form.summary.data db.session.add(t) db.session.commit() @@ -68,6 +69,10 @@ def forum_page(f, page=1): for a, file in attachments: a.set_file(file) + # If there's a thumbnail, set it + if form.thumbnail.data: + t.thumbnail = c.attachments[int(form.thumbnail.data)-1] + # Update member's xp and trophies if current_user.is_authenticated: current_user.add_xp(2) # 2 points for a topic diff --git a/app/routes/posts/edit.py b/app/routes/posts/edit.py index 31230c4..bade1d1 100644 --- a/app/routes/posts/edit.py +++ b/app/routes/posts/edit.py @@ -74,6 +74,12 @@ def edit_post(postid): if isinstance(p, Topic): p.title = form.title.data + p.summary = form.summary.data + # If there's a thumbnail, set it + if form.thumbnail.data: + p.thumbnail = comment.attachments[int(form.thumbnail.data)-1] + else: + p.thumbnail = None f = Forum.query.filter_by(url=form.forum.data).first_or_404() if current_user.can_post_in_forum(f): p.forum = f @@ -102,6 +108,7 @@ def edit_post(postid): form.message.data = p.thread.top_comment.text form.title.data = p.title form.forum.data = p.forum.url + form.summary.data = p.summary return render('forum/edit_topic.html', t=p, form=form) @app.route('/post/supprimer/', methods=['GET','POST']) diff --git a/app/templates/forum/edit_topic.html b/app/templates/forum/edit_topic.html index 97d2343..63e9034 100644 --- a/app/templates/forum/edit_topic.html +++ b/app/templates/forum/edit_topic.html @@ -48,6 +48,22 @@ {% endfor %} +
+ {{ form.summary.label }} + {{ form.summary }} + {% for error in form.summary.errors %} + {{ error }} + {% endfor %} +
+ +
+ {{ form.thumbnail.label }} + {{ form.thumbnail }} + {% for error in form.thumbnail.errors %} + {{ error }} + {% endfor %} +
+ {% if form.pseudo %}
{{ form.pseudo.label }} diff --git a/app/templates/forum/forum.html b/app/templates/forum/forum.html index a1cbef8..e872999 100644 --- a/app/templates/forum/forum.html +++ b/app/templates/forum/forum.html @@ -75,6 +75,22 @@ {% endfor %}
+
+ {{ form.summary.label }} + {{ form.summary }} + {% for error in form.summary.errors %} + {{ error }} + {% endfor %} +
+ +
+ {{ form.thumbnail.label }} + {{ form.thumbnail }} + {% for error in form.thumbnail.errors %} + {{ error }} + {% endfor %} +
+ {{ widget_editor.text_editor(form.message) }}
diff --git a/app/templates/forum/topic.html b/app/templates/forum/topic.html index dc9fec8..a280718 100644 --- a/app/templates/forum/topic.html +++ b/app/templates/forum/topic.html @@ -15,6 +15,10 @@

{{ t.title }}

+ {% if t.summary %} +
{{ t.summary | md }}
+ {% endif %} + {% if t.thread.top_comment %} {% call widget_thread.thread_leader(t.thread.top_comment) %}
diff --git a/app/templates/index.html b/app/templates/index.html index f86738a..96f4849 100644 --- a/app/templates/index.html +++ b/app/templates/index.html @@ -46,63 +46,18 @@

Actualitées

diff --git a/app/utils/validators/__init__.py b/app/utils/validators/__init__.py index 376d4d7..1a056e6 100644 --- a/app/utils/validators/__init__.py +++ b/app/utils/validators/__init__.py @@ -56,3 +56,13 @@ def own_title(form, title): return True else: return False + +def attachment_exists(form, number): + try: + n = int(number.data) + if n <= 0 or n > len(form.attachments.data): + raise Exception() + except Exception as e: + raise ValidationError('L’illustration doit être le numéro d’une pièce-jointe') + + return True diff --git a/migrations/versions/a8f539a93bd5_topics_add_summary_and_thumbnail.py b/migrations/versions/a8f539a93bd5_topics_add_summary_and_thumbnail.py new file mode 100644 index 0000000..6e38010 --- /dev/null +++ b/migrations/versions/a8f539a93bd5_topics_add_summary_and_thumbnail.py @@ -0,0 +1,36 @@ +"""Topics: add summary and thumbnail + +Revision ID: a8f539a93bd5 +Revises: 5ffc4e562ed8 +Create Date: 2023-07-25 21:44:55.782425 + +""" +from alembic import op +import sqlalchemy as sa +from sqlalchemy.dialects import postgresql + +# revision identifiers, used by Alembic. +revision = 'a8f539a93bd5' +down_revision = '5ffc4e562ed8' +branch_labels = None +depends_on = None + + +def upgrade(): + # ### commands auto generated by Alembic - please adjust! ### + with op.batch_alter_table('topic', schema=None) as batch_op: + batch_op.add_column(sa.Column('summary', sa.UnicodeText(), nullable=True)) + batch_op.add_column(sa.Column('thumbnail_id', postgresql.UUID(as_uuid=True), nullable=True)) + batch_op.create_foreign_key(None, 'attachment', ['thumbnail_id'], ['id']) + + # ### end Alembic commands ### + + +def downgrade(): + # ### commands auto generated by Alembic - please adjust! ### + with op.batch_alter_table('topic', schema=None) as batch_op: + batch_op.drop_constraint(None, type_='foreignkey') + batch_op.drop_column('thumbnail_id') + batch_op.drop_column('summary') + + # ### end Alembic commands ###