Просмотр исходного кода

Clean up Post and Topic forms a bit

Peter Justin 6 лет назад
Родитель
Сommit
8b20502300

+ 37 - 16
flaskbb/forum/forms.py

@@ -24,52 +24,73 @@ from flaskbb.user.models import User
 logger = logging.getLogger(__name__)
 logger = logging.getLogger(__name__)
 
 
 
 
-class QuickreplyForm(FlaskForm):
-    content = TextAreaField(_("Quick reply"), validators=[
+class PostForm(FlaskForm):
+    content = TextAreaField(_("Content"), validators=[
         DataRequired(message=_("You cannot post a reply without content."))])
         DataRequired(message=_("You cannot post a reply without content."))])
 
 
     submit = SubmitField(_("Reply"))
     submit = SubmitField(_("Reply"))
 
 
     def save(self, user, topic):
     def save(self, user, topic):
         post = Post(content=self.content.data)
         post = Post(content=self.content.data)
+        current_app.pluggy.hook.flaskbb_form_new_post_save(form=self)
         return post.save(user=user, topic=topic)
         return post.save(user=user, topic=topic)
 
 
 
 
-class ReplyForm(FlaskForm):
-    content = TextAreaField(_("Content"), validators=[
-        DataRequired(message=_("You cannot post a reply without content."))])
+class QuickreplyForm(PostForm):
+    pass
+
 
 
+class ReplyForm(PostForm):
     track_topic = BooleanField(_("Track this topic"), default=False,
     track_topic = BooleanField(_("Track this topic"), default=False,
                                validators=[Optional()])
                                validators=[Optional()])
 
 
-    submit = SubmitField(_("Reply"))
-
     def save(self, user, topic):
     def save(self, user, topic):
-        post = Post(content=self.content.data)
-
         if self.track_topic.data:
         if self.track_topic.data:
             user.track_topic(topic)
             user.track_topic(topic)
+        else:
+            user.untrack_topic(topic)
 
 
-        current_app.pluggy.hook.flaskbb_form_new_post_save(form=self)
-        return post.save(user=user, topic=topic)
+        return super(ReplyForm, self).save(user, topic)
 
 
 
 
-class NewTopicForm(ReplyForm):
+class TopicForm(FlaskForm):
     title = StringField(_("Topic title"), validators=[
     title = StringField(_("Topic title"), validators=[
         DataRequired(message=_("Please choose a title for your topic."))])
         DataRequired(message=_("Please choose a title for your topic."))])
 
 
-    submit = SubmitField(_("Post Topic"))
+    content = TextAreaField(_("Content"), validators=[
+        DataRequired(message=_("You cannot post a reply without content."))])
+
+    track_topic = BooleanField(_("Track this topic"), default=False,
+                               validators=[Optional()])
+
+    submit = SubmitField(_("Post topic"))
 
 
     def save(self, user, forum):
     def save(self, user, forum):
-        topic = Topic(title=self.title.data)
-        post = Post(content=self.content.data)
+        topic = Topic(title=self.title.data, content=self.content.data)
 
 
         if self.track_topic.data:
         if self.track_topic.data:
             user.track_topic(topic)
             user.track_topic(topic)
+        else:
+            user.untrack_topic(topic)
 
 
         current_app.pluggy.hook.flaskbb_form_new_topic_save(form=self,
         current_app.pluggy.hook.flaskbb_form_new_topic_save(form=self,
                                                             topic=topic)
                                                             topic=topic)
-        return topic.save(user=user, forum=forum, post=post)
+        return topic.save(user=user, forum=forum)
+
+
+class NewTopicForm(TopicForm):
+    pass
+
+
+class EditTopicForm(TopicForm):
+    def populate_obj(self, *objs):
+        """
+        Populates the attributes of the passed `obj`s with data from the
+        form's fields. This is especially useful to populate the topic and
+        post objects at the same time.
+        """
+        for obj in objs:
+            super(EditTopicForm, self).populate_obj(obj)
 
 
 
 
 class ReportForm(FlaskForm):
 class ReportForm(FlaskForm):

+ 43 - 28
flaskbb/forum/models.py

@@ -193,6 +193,10 @@ class Post(HideableCRUDMixin, db.Model):
         """
         """
         return "<{} {}>".format(self.__class__.__name__, self.id)
         return "<{} {}>".format(self.__class__.__name__, self.id)
 
 
+    def is_first_post(self):
+        """Checks whether this post is the first post in the topic or not."""
+        return self.topic.is_first_post(self)
+
     def save(self, user=None, topic=None):
     def save(self, user=None, topic=None):
         """Saves a new post. If no parameters are passed we assume that
         """Saves a new post. If no parameters are passed we assume that
         you will just update an existing post. It returns the object after the
         you will just update an existing post. It returns the object after the
@@ -433,7 +437,6 @@ class Topic(HideableCRUDMixin, db.Model):
                             cascade="all, delete-orphan",
                             cascade="all, delete-orphan",
                             post_update=True)
                             post_update=True)
 
 
-    # Properties
     @property
     @property
     def second_last_post(self):
     def second_last_post(self):
         """Returns the second last post or None."""
         """Returns the second last post or None."""
@@ -452,31 +455,7 @@ class Topic(HideableCRUDMixin, db.Model):
         """Returns the slugified url for the topic."""
         """Returns the slugified url for the topic."""
         return url_for("forum.view_topic", topic_id=self.id, slug=self.slug)
         return url_for("forum.view_topic", topic_id=self.id, slug=self.slug)
 
 
-    def first_unread(self, topicsread, user, forumsread=None):
-        """Returns the url to the first unread post. If no unread posts exist
-        it will return the url to the topic.
-
-        :param topicsread: The topicsread object for the topic
-        :param user: The user who should be checked if he has read the
-                     last post in the topic
-        :param forumsread: The forumsread object in which the topic is. If you
-                        also want to check if the user has marked the forum as
-                        read, than you will also need to pass an forumsread
-                        object.
-        """
-        # If the topic is unread try to get the first unread post
-        if topic_is_unread(self, topicsread, user, forumsread):
-            query = Post.query.filter(Post.topic_id == self.id)
-            if topicsread is not None:
-                query = query.filter(Post.date_created > topicsread.last_read)
-            post = query.order_by(Post.id.asc()).first()
-            if post is not None:
-                return post.url
-
-        return self.url
-
-    # Methods
-    def __init__(self, title=None, user=None):
+    def __init__(self, title=None, user=None, content=None):
         """Creates a topic object with some initial values.
         """Creates a topic object with some initial values.
 
 
         :param title: The title of the topic.
         :param title: The title of the topic.
@@ -492,6 +471,9 @@ class Topic(HideableCRUDMixin, db.Model):
             self.user_id = user.id
             self.user_id = user.id
             self.username = user.username
             self.username = user.username
 
 
+        if content:
+            self._post = Post(content=content)
+
         self.date_created = self.last_updated = time_utcnow()
         self.date_created = self.last_updated = time_utcnow()
 
 
     def __repr__(self):
     def __repr__(self):
@@ -500,6 +482,36 @@ class Topic(HideableCRUDMixin, db.Model):
         """
         """
         return "<{} {}>".format(self.__class__.__name__, self.id)
         return "<{} {}>".format(self.__class__.__name__, self.id)
 
 
+    def is_first_post(self, post):
+        """Checks if the post is the first post in the topic.
+
+        :param post: The post object.
+        """
+        return self.first_post_id == post.id
+
+    def first_unread(self, topicsread, user, forumsread=None):
+        """Returns the url to the first unread post. If no unread posts exist
+        it will return the url to the topic.
+
+        :param topicsread: The topicsread object for the topic
+        :param user: The user who should be checked if he has read the
+                     last post in the topic
+        :param forumsread: The forumsread object in which the topic is. If you
+                        also want to check if the user has marked the forum as
+                        read, than you will also need to pass an forumsread
+                        object.
+        """
+        # If the topic is unread try to get the first unread post
+        if topic_is_unread(self, topicsread, user, forumsread):
+            query = Post.query.filter(Post.topic_id == self.id)
+            if topicsread is not None:
+                query = query.filter(Post.date_created > topicsread.last_read)
+            post = query.order_by(Post.id.asc()).first()
+            if post is not None:
+                return post.url
+
+        return self.url
+
     @classmethod
     @classmethod
     def get_topic(cls, topic_id, user):
     def get_topic(cls, topic_id, user):
         topic = Topic.query.filter_by(id=topic_id).first_or_404()
         topic = Topic.query.filter_by(id=topic_id).first_or_404()
@@ -668,11 +680,14 @@ class Topic(HideableCRUDMixin, db.Model):
         db.session.add(self)
         db.session.add(self)
         db.session.commit()
         db.session.commit()
 
 
+        if post is not None:
+            self._post = post
+
         # Create the topic post
         # Create the topic post
-        post.save(user, self)
+        self._post.save(user, self)
 
 
         # Update the first and last post id
         # Update the first and last post id
-        self.last_post = self.first_post = post
+        self.last_post = self.first_post = self._post
 
 
         # Update the topic count
         # Update the topic count
         forum.topic_count += 1
         forum.topic_count += 1

+ 30 - 17
flaskbb/forum/views.py

@@ -22,25 +22,27 @@ from pluggy import HookimplMarker
 from sqlalchemy import asc, desc
 from sqlalchemy import asc, desc
 
 
 from flaskbb.extensions import allows, db
 from flaskbb.extensions import allows, db
-from flaskbb.markup import make_renderer
-from flaskbb.forum.forms import (NewTopicForm, QuickreplyForm, ReplyForm,
-                                 ReportForm, SearchPageForm, UserSearchForm)
+from flaskbb.forum.forms import (EditTopicForm, NewTopicForm, QuickreplyForm,
+                                 ReplyForm, ReportForm, SearchPageForm,
+                                 UserSearchForm)
 from flaskbb.forum.models import (Category, Forum, ForumsRead, Post, Topic,
 from flaskbb.forum.models import (Category, Forum, ForumsRead, Post, Topic,
                                   TopicsRead)
                                   TopicsRead)
+from flaskbb.markup import make_renderer
 from flaskbb.user.models import User
 from flaskbb.user.models import User
-from flaskbb.utils.helpers import (do_topic_action, format_quote,
-                                   get_online_users, real, register_view,
-                                   render_template, time_diff, time_utcnow,
-                                   FlashAndRedirect)
-from flaskbb.utils.requirements import (CanAccessForum,
-                                        CanDeletePost, CanDeleteTopic,
-                                        CanEditPost, CanPostReply,
-                                        CanPostTopic, Has,
+from flaskbb.utils.helpers import (FlashAndRedirect, do_topic_action,
+                                   format_quote, get_online_users, real,
+                                   register_view, render_template, time_diff,
+                                   time_utcnow)
+from flaskbb.utils.requirements import (CanAccessForum, CanDeletePost,
+                                        CanDeleteTopic, CanEditPost,
+                                        CanPostReply, CanPostTopic, Has,
                                         IsAtleastModeratorInForum)
                                         IsAtleastModeratorInForum)
 from flaskbb.utils.settings import flaskbb_config
 from flaskbb.utils.settings import flaskbb_config
-from .locals import current_topic, current_forum, current_category
+
+from .locals import current_category, current_forum, current_topic
 from .utils import force_login_if_needed
 from .utils import force_login_if_needed
 
 
+
 impl = HookimplMarker("flaskbb")
 impl = HookimplMarker("flaskbb")
 
 
 logger = logging.getLogger(__name__)
 logger = logging.getLogger(__name__)
@@ -292,8 +294,8 @@ class EditTopic(MethodView):
     decorators = [
     decorators = [
         login_required,
         login_required,
         allows.requires(
         allows.requires(
-            CanAccessForum(),
             CanPostTopic,
             CanPostTopic,
+            CanEditPost,
             on_fail=FlashAndRedirect(
             on_fail=FlashAndRedirect(
                 message=_("You are not allowed to edit that topic"),
                 message=_("You are not allowed to edit that topic"),
                 level="warning",
                 level="warning",
@@ -305,6 +307,7 @@ class EditTopic(MethodView):
     def get(self, topic_id, slug=None):
     def get(self, topic_id, slug=None):
         topic = Topic.query.filter_by(id=topic_id).first_or_404()
         topic = Topic.query.filter_by(id=topic_id).first_or_404()
         form = self.form(obj=topic.first_post, title=topic.title)
         form = self.form(obj=topic.first_post, title=topic.title)
+        form.track_topic.data = current_user.is_tracking_topic(topic)
 
 
         return render_template(
         return render_template(
             "forum/new_topic.html", forum=topic.forum, form=form, edit_mode=True
             "forum/new_topic.html", forum=topic.forum, form=form, edit_mode=True
@@ -316,10 +319,15 @@ class EditTopic(MethodView):
         form = self.form(obj=post, title=topic.title)
         form = self.form(obj=post, title=topic.title)
 
 
         if form.validate_on_submit():
         if form.validate_on_submit():
-            form.populate_obj(topic)
-            form.populate_obj(post)
+            form.populate_obj(topic, post)
             post.date_modified = time_utcnow()
             post.date_modified = time_utcnow()
             post.modified_by = real(current_user).username
             post.modified_by = real(current_user).username
+
+            if form.track_topic.data:
+                current_user.track_topic(topic)
+            else:
+                current_user.untrack_topic(topic)
+
             post.save()
             post.save()
             topic.save()
             topic.save()
             return redirect(url_for("forum.view_topic", topic_id=topic.id))
             return redirect(url_for("forum.view_topic", topic_id=topic.id))
@@ -330,7 +338,7 @@ class EditTopic(MethodView):
 
 
     def form(self, **kwargs):
     def form(self, **kwargs):
         current_app.pluggy.hook.flaskbb_form_new_topic(form=NewTopicForm)
         current_app.pluggy.hook.flaskbb_form_new_topic(form=NewTopicForm)
-        return NewTopicForm(**kwargs)
+        return EditTopicForm(**kwargs)
 
 
 
 
 class ManageForum(MethodView):
 class ManageForum(MethodView):
@@ -570,10 +578,11 @@ class EditPost(MethodView):
     def get(self, post_id):
     def get(self, post_id):
         post = Post.query.filter_by(id=post_id).first_or_404()
         post = Post.query.filter_by(id=post_id).first_or_404()
 
 
-        if post.topic.first_post_id == post.id:
+        if post.is_first_post():
             return redirect(url_for("forum.edit_topic", topic_id=post.topic_id))
             return redirect(url_for("forum.edit_topic", topic_id=post.topic_id))
 
 
         form = self.form(obj=post)
         form = self.form(obj=post)
+        form.track_topic.data = current_user.is_tracking_topic(post.topic)
 
 
         return render_template(
         return render_template(
             "forum/new_post.html", topic=post.topic, form=form, edit_mode=True
             "forum/new_post.html", topic=post.topic, form=form, edit_mode=True
@@ -587,6 +596,10 @@ class EditPost(MethodView):
             form.populate_obj(post)
             form.populate_obj(post)
             post.date_modified = time_utcnow()
             post.date_modified = time_utcnow()
             post.modified_by = real(current_user).username
             post.modified_by = real(current_user).username
+
+            if not form.track_topic.data and current_user.is_tracking_topic(post.topic):
+                current_user.untrack_topic(post.topic)
+
             post.save()
             post.save()
             return redirect(url_for("forum.view_post", post_id=post.id))
             return redirect(url_for("forum.view_post", post_id=post.id))
 
 

+ 1 - 1
flaskbb/templates/auth/login.html

@@ -2,7 +2,7 @@
 {% set active_forum_nav=True %}
 {% set active_forum_nav=True %}
 
 
 {% extends theme("layout.html") %}
 {% extends theme("layout.html") %}
-{% from theme("macros.html") import horizontal_field, render_boolean_field %}
+{% from theme("macros.html") import horizontal_field %}
 {% block content %}
 {% block content %}
 
 
 <div class="panel page-panel">
 <div class="panel page-panel">

+ 3 - 1
flaskbb/templates/forum/new_post.html

@@ -10,7 +10,7 @@
 {% extends theme("layout.html") %}
 {% extends theme("layout.html") %}
 
 
 {% block content %}
 {% block content %}
-{% from theme("macros.html") import render_quickreply, render_submit_field, render_field %}
+{% from theme("macros.html") import render_field, render_submit_field, render_quickreply, render_boolean_field %}
 
 
 <div class="page-view">
 <div class="page-view">
     <ol class="breadcrumb flaskbb-breadcrumb">
     <ol class="breadcrumb flaskbb-breadcrumb">
@@ -43,6 +43,8 @@
                                     {{ render_quickreply(form.content, div_class="new-message", rows=7, cols=75, placeholder="", **{'data-provide': 'markdown', 'data-autofocus': 'false', 'class': 'flaskbb-editor'}) }}
                                     {{ render_quickreply(form.content, div_class="new-message", rows=7, cols=75, placeholder="", **{'data-provide': 'markdown', 'data-autofocus': 'false', 'class': 'flaskbb-editor'}) }}
                                 </div>
                                 </div>
 
 
+                                {{ render_boolean_field(form.track_topic) }}
+
                                 {{ run_hook("flaskbb_tpl_form_new_post_after", form=form) }}
                                 {{ run_hook("flaskbb_tpl_form_new_post_after", form=form) }}
 
 
                                 <div class="editor-submit">
                                 <div class="editor-submit">

+ 3 - 1
flaskbb/templates/forum/new_topic.html

@@ -10,7 +10,7 @@
 {% extends theme("layout.html") %}
 {% extends theme("layout.html") %}
 
 
 {% block content %}
 {% block content %}
-{% from theme("macros.html") import render_field, render_submit_field, render_quickreply %}
+{% from theme("macros.html") import render_field, render_submit_field, render_quickreply, render_boolean_field %}
 
 
 <div class="page-view">
 <div class="page-view">
     <ol class="breadcrumb flaskbb-breadcrumb">
     <ol class="breadcrumb flaskbb-breadcrumb">
@@ -42,6 +42,8 @@
                                     {{ render_quickreply(form.content, div_class="new-message", rows=7, cols=75, placeholder="", **{'data-provide': 'markdown', 'data-autofocus': 'false', 'class': 'flaskbb-editor'}) }}
                                     {{ render_quickreply(form.content, div_class="new-message", rows=7, cols=75, placeholder="", **{'data-provide': 'markdown', 'data-autofocus': 'false', 'class': 'flaskbb-editor'}) }}
                                 </div>
                                 </div>
 
 
+                                {{ render_boolean_field(form.track_topic) }}
+
                                 {{ run_hook("flaskbb_tpl_form_new_topic_after", form=form) }}
                                 {{ run_hook("flaskbb_tpl_form_new_topic_after", form=form) }}
 
 
                                 <div class="editor-submit">
                                 <div class="editor-submit">