Browse Source

topicId to pk

honmaple 5 years ago
parent
commit
7bac5bc314
45 changed files with 442 additions and 379 deletions
  1. 1 5
      config.example
  2. 5 5
      forums/admin/views.py
  3. 2 2
      forums/api/__init__.py
  4. 2 2
      forums/api/collect/__init__.py
  5. 6 6
      forums/api/collect/views.py
  6. 3 3
      forums/api/follow/views.py
  7. 2 2
      forums/api/forums/db.py
  8. 16 26
      forums/api/forums/views.py
  9. 6 6
      forums/api/message/db.py
  10. 30 43
      forums/api/tag/views.py
  11. 5 5
      forums/api/topic/__init__.py
  12. 11 11
      forums/api/topic/permissions.py
  13. 30 32
      forums/api/topic/views.py
  14. 38 4
      forums/common/views.py
  15. 6 6
      forums/count.py
  16. 40 1
      forums/default.py
  17. 4 4
      forums/extension/babel.py
  18. 3 3
      forums/jinja.py
  19. 3 3
      static/assets/home.js
  20. 4 4
      static/styles/following.js
  21. 2 2
      static/styles/topic.js
  22. 1 3
      templates/base/base.html
  23. 14 14
      templates/base/form.html
  24. 11 11
      templates/base/head.html
  25. 5 7
      templates/base/header.html
  26. 25 26
      templates/base/link.html
  27. 3 0
      templates/board/board.html
  28. 19 16
      templates/board/board_list.html
  29. 1 1
      templates/collect/collect.html
  30. 46 42
      templates/forums/_macro.html
  31. 11 8
      templates/forums/about.html
  32. 12 9
      templates/forums/contact.html
  33. 11 8
      templates/forums/help.html
  34. 25 27
      templates/forums/index.html
  35. 2 4
      templates/maple/footer.html
  36. 1 1
      templates/search/result.html
  37. 3 0
      templates/tag/tag.html
  38. 3 0
      templates/tag/tag_list.html
  39. 1 1
      templates/topic/_list_macro.html
  40. 1 1
      templates/topic/collect.html
  41. 1 1
      templates/topic/panel.html
  42. 1 1
      templates/topic/reply/form.html
  43. 3 3
      templates/topic/reply/itemlist.html
  44. 20 20
      templates/topic/topic.html
  45. 3 0
      templates/topic/topic_list.html

+ 1 - 5
config.example

@@ -6,7 +6,7 @@
 # Author: jianglin
 # Email: mail@honmaple.com
 # Created: 2016-05-20 12:31:46 (CST)
-# Last Update: Thursday 2018-07-26 11:41:00 (CST)
+# Last Update: Wednesday 2019-05-08 16:28:02 (CST)
 #          By: jianglin
 # Description:
 # **************************************************************************
@@ -97,7 +97,3 @@ MSEARCH_BACKEND = 'whoosh'
 BABEL_DEFAULT_LOCALE = 'en'
 BABEL_DEFAULT_TIMEZONE = 'UTC'
 BABEL_TRANSLATION_DIRECTORIES = path.join(PATH, 'translations')
-
-# Locale
-LANGUAGES = {'en': 'English', 'zh': 'Chinese'}
-SITE = {'title': 'Honmaple', 'description': '爱生活,更爱自由', 'avatar': ''}

+ 5 - 5
forums/admin/views.py

@@ -6,7 +6,7 @@
 # Author: jianglin
 # Email: xiyang0807@gmail.com
 # Created: 2016-12-17 13:15:10 (CST)
-# Last Update:星期日 2018-01-07 22:06:09 (CST)
+# Last Update: Wednesday 2019-05-08 14:32:26 (CST)
 #          By:
 # Description:
 # **************************************************************************
@@ -29,8 +29,8 @@ class BaseView(ModelView):
     can_view_details = True
     form_base_class = BaseForm
 
-    def is_accessible(self):
-        return super_permission.can()
+    # def is_accessible(self):
+    #     return super_permission.can()
 
-    def inaccessible_callback(self, name, **kwargs):
-        abort(404)
+    # def inaccessible_callback(self, name, **kwargs):
+    #     abort(404)

+ 2 - 2
forums/api/__init__.py

@@ -6,7 +6,7 @@
 # Author: jianglin
 # Email: xiyang0807@gmail.com
 # Created: 2016-11-20 15:49:33 (CST)
-# Last Update: Monday 2019-05-06 23:15:23 (CST)
+# Last Update: Wednesday 2019-05-08 15:43:20 (CST)
 #          By:
 # Description:
 # **************************************************************************
@@ -16,8 +16,8 @@ from werkzeug import import_string
 def init_app(app):
     blueprints = [
         "forums.api.forums",
-        "forums.api.tag",
         "forums.api.topic",
+        "forums.api.tag",
         "forums.api.user",
         "forums.api.collect",
         "forums.api.message",

+ 2 - 2
forums/api/collect/__init__.py

@@ -6,7 +6,7 @@
 # Author: jianglin
 # Email: xiyang0807@gmail.com
 # Created: 2017-03-28 16:23:58 (CST)
-# Last Update: Wednesday 2019-05-08 13:24:05 (CST)
+# Last Update: Wednesday 2019-05-08 15:09:17 (CST)
 #          By:
 # Description:
 # **************************************************************************
@@ -21,6 +21,6 @@ def init_app(app):
     site.add_url_rule(
         '/collect/<int:pk>', view_func=CollectView.as_view('collect'))
     site.add_url_rule(
-        '/topic/<int:topicId>/collect',
+        '/topic/<int:pk>/collect',
         view_func=AddToCollectView.as_view('add_to_collect'))
     app.register_blueprint(site)

+ 6 - 6
forums/api/collect/views.py

@@ -93,10 +93,10 @@ class CollectView(MethodView):
 
 
 class AddToCollectView(MethodView):
-    def post(self, topicId):
+    def post(self, pk):
         user = request.user
         form = request.form.getlist('add-to-collect')
-        topic = Topic.query.filter_by(id=topicId).first_or_404()
+        topic = Topic.query.filter_by(id=pk).first_or_404()
         for cid in form:
             '''This has a problem'''
             collect = Collect.query.filter_by(id=cid).first_or_404()
@@ -105,12 +105,12 @@ class AddToCollectView(MethodView):
                 collect.topics.append(topic)
                 collect.save()
             MessageClient.collect(topic)
-        return redirect(url_for('topic.topic', topicId=topic.id))
+        return redirect(url_for('topic.topic', pk=topic.id))
 
-    # def delete(self, topicId):
+    # def delete(self, pk):
     #     user = request.user
     #     form = request.form.getlist('add-to-collect')
-    #     topic = Topic.query.filter_by(id=topicId).first_or_404()
+    #     topic = Topic.query.filter_by(id=pk).first_or_404()
     #     for cid in form:
     #         '''This has a problem'''
     #         collect = Collect.query.filter_by(id=cid).first_or_404()
@@ -118,4 +118,4 @@ class AddToCollectView(MethodView):
     #                 topics__id=topic.id, author_id=user.id).exists():
     #             collect.topics.append(topic)
     #             collect.save()
-    #     return redirect(url_for('topic.topic', topicId=topic.id))
+    #     return redirect(url_for('topic.topic', pk=topic.id))

+ 3 - 3
forums/api/follow/views.py

@@ -6,7 +6,7 @@
 # Author: jianglin
 # Email: xiyang0807@gmail.com
 # Created: 2016-12-22 21:49:05 (CST)
-# Last Update: Thursday 2018-07-26 10:45:39 (CST)
+# Last Update: Wednesday 2019-05-08 15:09:18 (CST)
 #          By:
 # Description:
 # **************************************************************************
@@ -66,7 +66,7 @@ class FollowingTopicsView(MethodView):
     def post(self):
         user = request.user
         post_data = request.data
-        topic_id = post_data.pop('topicId', None)
+        topic_id = post_data.pop('pk', None)
         if topic_id is not None and not User.query.filter_by(
                 following_topics__id=topic_id).exists():
             topic = Topic.query.filter_by(id=topic_id).first_or_404()
@@ -79,7 +79,7 @@ class FollowingTopicsView(MethodView):
     def delete(self):
         user = request.user
         post_data = request.data
-        topic_id = post_data.pop('topicId', None)
+        topic_id = post_data.pop('pk', None)
         if topic_id is not None and User.query.filter_by(
                 following_topics__id=topic_id).exists():
             topic = Topic.query.filter_by(id=topic_id).first_or_404()

+ 2 - 2
forums/api/forums/db.py

@@ -2,11 +2,11 @@
 # -*- coding: utf-8 -*-
 # **************************************************************************
 # Copyright © 2017 jianglin
-# File Name: models.py
+# File Name: db.py
 # Author: jianglin
 # Email: xiyang0807@gmail.com
 # Created: 2017-03-25 18:48:33 (CST)
-# Last Update: Monday 2019-05-06 23:37:21 (CST)
+# Last Update: Wednesday 2019-05-08 14:39:58 (CST)
 #          By:
 # Description:
 # **************************************************************************

+ 16 - 26
forums/api/forums/views.py

@@ -6,12 +6,11 @@
 # Author: jianglin
 # Email: xiyang0807@gmail.com
 # Created: 2016-12-17 20:45:08 (CST)
-# Last Update: Monday 2019-05-06 23:36:54 (CST)
+# Last Update: Wednesday 2019-05-08 14:37:48 (CST)
 #          By:
 # Description:
 # **************************************************************************
 from flask import render_template, request
-from flask_babel import gettext as _
 
 from forums.api.topic.db import Topic
 from forums.common.views import BaseMethodView as MethodView
@@ -28,39 +27,30 @@ class IndexView(MethodView):
         top_topics = Topic.query.filter_by(is_top=True).limit(5)
         if not topics.items:
             topics = Topic.query.filter_by(is_top=False).paginate(1, 10)
-        data = {'title': '', 'topics': topics, 'top_topics': top_topics}
+
+        data = {'topics': topics, 'top_topics': top_topics}
         return render_template('forums/index.html', **data)
 
 
 class AboutView(MethodView):
     def get(self):
-        data = {'title': _('About - ')}
-        return render_template('forums/about.html', **data)
+        return self.render_template('forums/about.html')
 
 
 class HelpView(MethodView):
     def get(self):
-        data = {'title': _('Help - ')}
-        return render_template('forums/help.html', **data)
+        return self.render_template('forums/help.html')
 
 
 class ContactView(MethodView):
     def get(self):
-        data = {'title': _('Contact - ')}
-        return render_template('forums/contact.html', **data)
+        return self.render_template('forums/contact.html')
 
 
 class BoardListView(MethodView):
     def get(self):
-        query_dict = request.data
-        page, number = self.pageinfo
-        keys = ['name']
-        order_by = gen_order_by(query_dict, keys)
-        filter_dict = gen_filter_dict(query_dict, keys)
-        filter_dict.update(parent_id=None)
-        boards = Board.query.filter_by(
-            **filter_dict).order_by(*order_by).paginate(page, number, True)
-        data = {'title': 'Board', 'boards': boards}
+        boards = Board.query.filter_by(parent_id=None).order_by("-name").all()
+        data = {'boards': boards}
         return render_template('board/board_list.html', **data)
 
 
@@ -69,17 +59,17 @@ class BoardView(MethodView):
         board = Board.query.filter_by(id=pk).first_or_404()
         has_children = board.child_boards.exists()
         topics = self.topics(pk, has_children)
-        data = {'title': 'Board', 'board': board, 'topics': topics}
+        data = {'board': board, 'topics': topics}
         return render_template('board/board.html', **data)
 
     def topics(self, pk, has_children):
-        query_dict = request.data
+        request_data = request.data
         page, number = self.pageinfo
         keys = ['title']
-        # order_by = gen_order_by(query_dict, keys)
-        # filter_dict = gen_filter_dict(query_dict, keys)
-        order_by = gen_topic_orderby(query_dict, keys)
-        filter_dict = gen_topic_filter(query_dict, keys)
+        # order_by = gen_order_by(request_data, keys)
+        # filter_dict = gen_filter_dict(request_data, keys)
+        order_by = gen_topic_orderby(request_data, keys)
+        filter_dict = gen_topic_filter(request_data, keys)
         if has_children:
             o = []
             for i in order_by:
@@ -88,8 +78,8 @@ class BoardView(MethodView):
                 else:
                     o.append(getattr(Topic, i))
             topics = Topic.query.filter_by(**filter_dict).outerjoin(Board).or_(
-                Board.parent_id == pk,
-                Board.id == pk).order_by(*o).paginate(page, number, True)
+                Board.parent_id == pk, Board.id == pk).order_by(*o).paginate(
+                    page, number, True)
             return topics
         filter_dict.update(board_id=pk)
         topics = Topic.query.filter_by(

+ 6 - 6
forums/api/message/db.py

@@ -6,7 +6,7 @@
 # Author: jianglin
 # Email: xiyang0807@gmail.com
 # Created: 2017-04-01 18:33:37 (CST)
-# Last Update: Tuesday 2019-05-07 01:19:46 (CST)
+# Last Update: Wednesday 2019-05-08 15:09:17 (CST)
 #          By:
 # Description:
 # **************************************************************************
@@ -141,7 +141,7 @@ class MessageClient(object):
             return
         title = '[{}]({})回复了你创建的主题:[{}]({})'.format(
             sender.username, url_for('user.user', username=sender.username),
-            topic.title, url_for('topic.topic', topicId=topic.id))
+            topic.title, url_for('topic.topic', pk=topic.id))
         content = reply.content
         message_text = MessageText(
             sender_id=sender.id, title=title, content=content)
@@ -162,7 +162,7 @@ class MessageClient(object):
             return
         title = '[{}]({})收藏了你创建的主题:[{}]({})'.format(
             sender.username, url_for('user.user', username=sender.username),
-            topic.title, url_for('topic.topic', topicId=topic.id))
+            topic.title, url_for('topic.topic', pk=topic.id))
         content = 'a'
         message_text = MessageText(
             sender_id=sender.id, title=title, content=content)
@@ -183,7 +183,7 @@ class MessageClient(object):
             title = '[{}]({})关注了你创建的主题:[{}]({})'.format(
                 sender.username, url_for(
                     'user.user', username=sender.username), following.title,
-                url_for('topic.topic', topicId=following.id))
+                url_for('topic.topic', pk=following.id))
         elif following.__class__.__name__ == 'Collect':
             receiver = following.author
             title = '[{}]({})关注了你创建的收藏:[{}]({})'.format(
@@ -218,7 +218,7 @@ class MessageClient(object):
         topic = reply.topic
         title = '[{}]({})在[{}]({})回复了你'.format(
             sender.username, url_for('user.user', username=sender.username),
-            topic.title, url_for('topic.topic', topicId=topic.id))
+            topic.title, url_for('topic.topic', pk=topic.id))
         content = reply.content
         message_text = MessageText(
             sender_id=sender.id, title=title, content=content)
@@ -240,7 +240,7 @@ class MessageClient(object):
         topic = reply.topic
         title = '[{}]({})在[{}]({})赞了你的回复'.format(
             sender.username, url_for('user.user', username=sender.username),
-            topic.title, url_for('topic.topic', topicId=topic.id))
+            topic.title, url_for('topic.topic', pk=topic.id))
         content = reply.content
         message_text = MessageText(
             sender_id=sender.id, title=title, content=content)

+ 30 - 43
forums/api/tag/views.py

@@ -6,7 +6,7 @@
 # Author: jianglin
 # Email: xiyang0807@gmail.com
 # Created: 2016-12-15 22:07:04 (CST)
-# Last Update: Monday 2019-05-06 23:36:54 (CST)
+# Last Update: Wednesday 2019-05-08 16:27:50 (CST)
 #          By:
 # Description:
 # **************************************************************************
@@ -17,8 +17,9 @@ from werkzeug.contrib.atom import AtomFeed
 
 from forums.api.topic.db import Topic
 from forums.api.utils import gen_topic_filter, gen_topic_orderby
-from forums.common.utils import gen_filter_dict, gen_order_by
 from forums.common.views import BaseMethodView as MethodView
+from forums.utils import filter_maybe, orderby_maybe
+from forums.default import SITE
 
 from .db import Tags
 
@@ -27,65 +28,51 @@ class TagsListView(MethodView):
     per_page = 99
 
     def get(self):
-        query_dict = request.data
+        request_data = request.data
         page, number = self.pageinfo
-        keys = ['name']
-        order_by = gen_order_by(query_dict, keys)
-        filter_dict = gen_filter_dict(query_dict, keys)
-        tags = Tags.query.filter_by(
-            **filter_dict).order_by(*order_by).paginate(page, number, True)
-        data = {'title': 'Tags', 'tags': tags}
+        params = filter_maybe(request_data, ["name"])
+        orderby = orderby_maybe(request_data, ["name"])
+        tags = Tags.query.filter_by(**params).order_by(*orderby).paginate(
+            page, number, True)
+        data = {'tags': tags}
         return render_template('tag/tag_list.html', **data)
 
 
 class TagsView(MethodView):
     def get(self, name):
+        request_data = request.data
         page, number = self.pageinfo
         tag = Tags.query.filter_by(name=name).first_or_404()
-        topics = self.topics(tag)
-        data = {'title': tag.name, 'tag': tag, 'topics': topics}
-        return render_template('tag/tag.html', **data)
 
-    def topics(self, tag):
-        query_dict = request.data
-        page, number = self.pageinfo
         keys = ['name']
-        # order_by = gen_order_by(query_dict, keys)
-        # filter_dict = gen_filter_dict(query_dict, keys)
-        order_by = gen_topic_orderby(query_dict, keys)
-        filter_dict = gen_topic_filter(query_dict, keys)
-        filter_dict.update(tags__id=tag.id)
-        return Topic.query.filter_by(
-            **filter_dict).order_by(*order_by).paginate(page, number, True)
+        params = gen_topic_filter(request_data, keys)
+        params.update(tags__id=tag.id)
+        orderby = gen_topic_orderby(request_data, keys)
+        topics = Topic.query.filter_by(**params).order_by(*orderby).paginate(
+            page, number, True)
+
+        data = {'tag': tag, 'topics': topics}
+        return render_template('tag/tag.html', **data)
 
 
 class TagFeedView(MethodView):
     def get(self, name):
-        setting = current_app.config.get('SITE', {
-            'title': '',
-            'description': ''
-        })
-        title = setting['title']
-        description = setting['description']
+        title = SITE['title']
+        subtitle = SITE['subtitle']
         feed = AtomFeed(
             '%s·%s' % (name, title),
             feed_url=request.url,
             url=request.url_root,
-            subtitle=description)
+            subtitle=subtitle)
         topics = Topic.query.filter_by(tags__name=name).limit(10)
         for topic in topics:
-            if topic.content_type == Topic.CONTENT_TYPE_MARKDOWN:
-                content = topic.content
-            else:
-                content = topic.content
-            feed.add(topic.title,
-                     content,
-                     content_type='html',
-                     author=topic.author.username,
-                     url=urljoin(
-                         request.url_root,
-                         url_for(
-                             'topic.topic', topicId=topic.id)),
-                     updated=topic.updated_at,
-                     published=topic.created_at)
+            feed.add(
+                topic.title,
+                topic.text,
+                content_type='html',
+                author=topic.author.username,
+                url=urljoin(request.url_root,
+                            url_for('topic.topic', pk=topic.id)),
+                updated=topic.updated_at,
+                published=topic.created_at)
         return feed.get_response()

+ 5 - 5
forums/api/topic/__init__.py

@@ -33,9 +33,9 @@ def init_app(app):
     site.add_url_rule('/topic', view_func=topic_list)
     site.add_url_rule('/topic/top', view_func=topic_top_list)
     site.add_url_rule('/topic/good', view_func=topic_good_list)
-    site.add_url_rule('/topic/<int:topicId>', view_func=topic)
-    site.add_url_rule('/topic/<int:topicId>/edit', view_func=edit_view)
-    site.add_url_rule('/topic/<int:topicId>/replies', view_func=reply_list)
-    site.add_url_rule('/replies/<int:replyId>', view_func=reply)
-    site.add_url_rule('/replies/<int:replyId>/like', view_func=like_view)
+    site.add_url_rule('/topic/<int:pk>', view_func=topic)
+    site.add_url_rule('/topic/<int:pk>/edit', view_func=edit_view)
+    site.add_url_rule('/topic/<int:pk>/replies', view_func=reply_list)
+    site.add_url_rule('/replies/<int:pk>', view_func=reply)
+    site.add_url_rule('/replies/<int:pk>/like', view_func=like_view)
     app.register_blueprint(site)

+ 11 - 11
forums/api/topic/permissions.py

@@ -18,8 +18,8 @@ from forums.permission import (ReplyPermission, RestfulView, TopicPermission,
 
 
 class Edit(RestfulView):
-    def get(self, topicId):
-        permission = TopicPermission(topicId)
+    def get(self, pk):
+        permission = TopicPermission(pk)
         if not permission.can():
             return self.callback()
         return True
@@ -33,15 +33,15 @@ class TopicList(RestfulView):
 
 class Topic(RestfulView):
     @is_confirmed
-    def put(self, topicId):
-        permission = TopicPermission(topicId)
+    def put(self, pk):
+        permission = TopicPermission(pk)
         if not permission.can():
             return self.callback()
         return True
 
     @is_confirmed
-    def delete(self, topicId):
-        permission = TopicPermission(topicId)
+    def delete(self, pk):
+        permission = TopicPermission(pk)
         if not permission.can():
             return self.callback()
         return True
@@ -49,27 +49,27 @@ class Topic(RestfulView):
 
 class ReplyList(RestfulView):
     @is_confirmed
-    def post(self, topicId):
+    def post(self, pk):
         return True
 
 
 class Reply(RestfulView):
     @is_confirmed
-    def put(self, replyId):
+    def put(self, pk):
         return True
 
     @is_confirmed
-    def delete(self, replyId):
+    def delete(self, pk):
         return True
 
 
 class Like(RestfulView):
     @is_confirmed
-    def post(self, replyId):
+    def post(self, pk):
         return True
 
     @is_confirmed
-    def delete(self, replyId):
+    def delete(self, pk):
         return True
 
 

+ 30 - 32
forums/api/topic/views.py

@@ -6,7 +6,7 @@
 # Author: jianglin
 # Email: xiyang0807@gmail.com
 # Created: 2016-12-15 22:07:39 (CST)
-# Last Update: Monday 2019-05-06 23:36:54 (CST)
+# Last Update: Wednesday 2019-05-08 15:18:15 (CST)
 #          By:
 # Description:
 # **************************************************************************
@@ -46,8 +46,8 @@ class TopicAskView(IsConfirmedMethodView):
 class TopicEditView(IsConfirmedMethodView):
     decorators = (edit_permission, )
 
-    def get(self, topicId):
-        topic = Topic.query.filter_by(id=topicId).first_or_404()
+    def get(self, pk):
+        topic = Topic.query.filter_by(id=pk).first_or_404()
         form = form_board()
         form.title.data = topic.title
         form.category.data = topic.board_id
@@ -61,22 +61,20 @@ class TopicListView(MethodView):
     decorators = (topic_list_permission, )
 
     def get(self):
-        query_dict = request.data
+        request_data = request.data
         page, number = self.pageinfo
         keys = ['title']
-        # order_by = gen_order_by(query_dict, keys)
-        # filter_dict = gen_filter_dict(query_dict, keys)
-        order_by = gen_topic_orderby(query_dict, keys)
-        filter_dict = gen_topic_filter(query_dict, keys)
+        orderby = gen_topic_orderby(request_data, keys)
+        params = gen_topic_filter(request_data, keys)
         title = _('All Topics')
         if request.path.endswith('good'):
-            filter_dict.update(is_good=True)
+            params.update(is_good=True)
             title = _('Good Topics')
         elif request.path.endswith('top'):
-            filter_dict.update(is_top=True)
+            params.update(is_top=True)
             title = _('Top Topics')
-        topics = Topic.query.filter_by(
-            **filter_dict).order_by(*order_by).paginate(page, number, True)
+        topics = Topic.query.filter_by(**params).order_by(*orderby).paginate(
+            page, number, True)
         data = {'title': title, 'topics': topics}
         return render_template('topic/topic_list.html', **data)
 
@@ -112,22 +110,22 @@ class TopicListView(MethodView):
         topic.board.post_count = 1
         topic.author.topic_count = 1
         topic.reply_count = 1
-        return redirect(url_for('topic.topic', topicId=topic.id))
+        return redirect(url_for('topic.topic', pk=topic.id))
 
 
 class TopicView(MethodView):
     decorators = (topic_permission, )
 
-    def get(self, topicId):
+    def get(self, pk):
         form = ReplyForm()
-        query_dict = request.data
-        topic = Topic.query.filter_by(id=topicId).first_or_404()
+        request_data = request.data
+        topic = Topic.query.filter_by(id=pk).first_or_404()
         page, number = self.pageinfo
         keys = ['title']
-        order_by = gen_order_by(query_dict, keys)
-        filter_dict = gen_filter_dict(query_dict, keys)
+        order_by = gen_order_by(request_data, keys)
+        params = gen_filter_dict(request_data, keys)
         replies = topic.replies.filter_by(
-            **filter_dict).order_by(*order_by).paginate(page, number, True)
+            **params).order_by(*order_by).paginate(page, number, True)
         data = {
             'title': topic.title,
             'form': form,
@@ -138,10 +136,10 @@ class TopicView(MethodView):
         return render_template('topic/topic.html', **data)
 
     @form_validate(form_board)
-    def put(self, topicId):
+    def put(self, pk):
         form = form_board()
         post_data = form.data
-        topic = Topic.query.filter_by(id=topicId).first_or_404()
+        topic = Topic.query.filter_by(id=pk).first_or_404()
         title = post_data.pop('title', None)
         content = post_data.pop('content', None)
         content_type = post_data.pop('content_type', None)
@@ -162,8 +160,8 @@ class ReplyListView(MethodView):
     decorators = (reply_list_permission, )
 
     @form_validate(ReplyForm, error=error_callback, f='')
-    def post(self, topicId):
-        topic = Topic.query.filter_by(id=topicId).first_or_404()
+    def post(self, pk):
+        topic = Topic.query.filter_by(id=pk).first_or_404()
         post_data = request.data
         user = request.user
         content = post_data.pop('content', None)
@@ -175,24 +173,24 @@ class ReplyListView(MethodView):
         # count
         topic.board.post_count = 1
         reply.author.reply_count = 1
-        return redirect(url_for('topic.topic', topicId=topic.id))
+        return redirect(url_for('topic.topic', pk=topic.id))
 
 
 class ReplyView(MethodView):
 
     decorators = (reply_permission, )
 
-    def put(self, replyId):
+    def put(self, pk):
         post_data = request.data
-        reply = Reply.query.filter_by(id=replyId).first_or_404()
+        reply = Reply.query.filter_by(id=pk).first_or_404()
         content = post_data.pop('content', None)
         if content is not None:
             reply.content = content
         reply.save()
         return HTTPResponse(HTTPResponse.NORMAL_STATUS).to_response()
 
-    def delete(self, replyId):
-        reply = Reply.query.filter_by(id=replyId).first_or_404()
+    def delete(self, pk):
+        reply = Reply.query.filter_by(id=pk).first_or_404()
         reply.delete()
         return HTTPResponse(HTTPResponse.NORMAL_STATUS).to_response()
 
@@ -201,9 +199,9 @@ class LikeView(MethodView):
 
     decorators = (like_permission, )
 
-    def post(self, replyId):
+    def post(self, pk):
         user = request.user
-        reply = Reply.query.filter_by(id=replyId).first_or_404()
+        reply = Reply.query.filter_by(id=pk).first_or_404()
         reply.likers.append(user)
         reply.save()
         MessageClient.like(reply)
@@ -211,9 +209,9 @@ class LikeView(MethodView):
         return HTTPResponse(
             HTTPResponse.NORMAL_STATUS, data=serializer.data).to_response()
 
-    def delete(self, replyId):
+    def delete(self, pk):
         user = request.user
-        reply = Reply.query.filter_by(id=replyId).first_or_404()
+        reply = Reply.query.filter_by(id=pk).first_or_404()
         reply.likers.remove(user)
         reply.save()
         serializer = Serializer(reply, many=False)

+ 38 - 4
forums/common/views.py

@@ -6,13 +6,14 @@
 # Author: jianglin
 # Email: xiyang0807@gmail.com
 # Created: 2017-03-13 13:29:37 (CST)
-# Last Update: Sunday 2018-03-04 22:37:00 (CST)
+# Last Update: Wednesday 2019-05-08 14:24:25 (CST)
 #          By:
 # Description:
 # **************************************************************************
-from flask import (request, flash, redirect, url_for, render_template)
+from flask import (request, flash, redirect, url_for, render_template,
+                   current_app)
 from flask_login import login_required, current_user
-from flask_maple.views import MethodView
+from flask_maple.views import MethodView as _MethodView
 from forums.permission import confirm_permission
 from forums.extension import cache
 
@@ -34,7 +35,37 @@ def is_confirmed(func):
     return _is_confirmed
 
 
-class BaseMethodView(MethodView):
+class MethodView(_MethodView):
+    @property
+    def pageinfo(self):
+        page = request.args.get('page', 1, type=int)
+        if hasattr(self, 'per_page'):
+            per_page = getattr(self, 'per_page')
+        else:
+            per_page = current_app.config.setdefault('PER_PAGE', 20)
+
+        number = request.args.get('number', per_page, type=int)
+        if number < -1:
+            number = per_page
+        if number > 100 or number == -1:
+            number = 100
+        return page, number
+
+    def dispatch_request(self, *args, **kwargs):
+        method = request.method
+        meth = getattr(self, method.lower(), None)
+
+        if meth is None and method == 'HEAD':
+            meth = getattr(self, 'get', None)
+
+        assert meth is not None, 'Unimplemented method %r' % request.method
+        return meth(*args, **kwargs)
+
+    def render_template(self, template, **kwargs):
+        return render_template(template, **kwargs)
+
+
+class BaseMethodView(_MethodView):
     @cache.cached(timeout=180, key_prefix=cache_key)
     def dispatch_request(self, *args, **kwargs):
         return super(BaseMethodView, self).dispatch_request(*args, **kwargs)
@@ -42,6 +73,9 @@ class BaseMethodView(MethodView):
     def render_template(self, template, **kwargs):
         return render_template(template, **kwargs)
 
+    def render(self, template, **kwargs):
+        return render_template(template, **kwargs)
+
 
 class IsAuthMethodView(BaseMethodView):
     decorators = [login_required]

+ 6 - 6
forums/count.py

@@ -34,8 +34,8 @@ class Count(object):
         return redis_data.hget(key, 'post') or 0
 
     @classmethod
-    def topic_reply_count(cls, topicId, value=None):
-        key = 'count:topic:%s' % str(topicId)
+    def topic_reply_count(cls, pk, value=None):
+        key = 'count:topic:%s' % str(pk)
         if value is not None:
             pipe = redis_data.pipeline()
             pipe.hincrby(key, 'replies', value)
@@ -43,8 +43,8 @@ class Count(object):
         return redis_data.hget(key, 'replies') or 0
 
     @classmethod
-    def topic_read_count(cls, topicId, value=None):
-        key = 'count:topic:%s' % str(topicId)
+    def topic_read_count(cls, pk, value=None):
+        key = 'count:topic:%s' % str(pk)
         expire_key = 'expire:topic:read:{}'.format(request.remote_addr)
         if not redis_data.exists(expire_key):
             # 设置三分钟之内,阅读次数不增加
@@ -55,8 +55,8 @@ class Count(object):
         return redis_data.hget(key, 'read') or 0
 
     @classmethod
-    def reply_liker_count(cls, replyId, value=None):
-        key = 'count:reply:%s' % str(replyId)
+    def reply_liker_count(cls, pk, value=None):
+        key = 'count:reply:%s' % str(pk)
         if value is not None:
             pipe = redis_data.pipeline()
             pipe.hincrby(key, 'liker', value)

+ 40 - 1
forums/default.py

@@ -6,8 +6,47 @@
 # Author: jianglin
 # Email: xiyang0807@gmail.com
 # Created: 2018-07-26 10:00:54 (CST)
-# Last Update: Thursday 2018-07-26 10:01:16 (CST)
+# Last Update: Wednesday 2019-05-08 16:24:22 (CST)
 #          By:
 # Description:
 # ********************************************************************************
+SITE = {'title': '紅楓林', 'subtitle': '爱生活,更爱自由', 'avatar': ''}
 SUBDOMAIN = {"forums": True, "docs": True}
+LANGUAGES = {'en': 'English', 'zh': 'Chinese'}
+INDEX = [{
+    "name": "Forums",
+    "url": "forums.forums",
+    "icon": "fa-comments",
+    "color": "#F86334"
+}, {
+    "name": "Wiki",
+    "url": "docs.list",
+    "icon": "fa-book",
+    "color": "#eeccaa"
+}, {
+    "name": "Blog",
+    "url": "docs.list",
+    "icon": "fa-tasks",
+    "color": "#337ab7"
+}, {
+    "name": "Good",
+    "url": "topic.good",
+    "icon": "fa-globe",
+    "color": "#017e66"
+}]
+HEADER = [{
+    "name": "Forums",
+    "url": "forums.forums"
+}, {
+    "name": "Wiki",
+    "url": "docs.list"
+}, {
+    "name": "Blog",
+    "url": "forums.forums"
+}, {
+    "name": "TagList",
+    "url": "tag.list"
+}, {
+    "name": "Good",
+    "url": "topic.good"
+}]

+ 4 - 4
forums/extension/babel.py

@@ -6,12 +6,13 @@
 # Author: jianglin
 # Email: xiyang0807@gmail.com
 # Created: 2018-02-11 14:52:25 (CST)
-# Last Update: Wednesday 2018-07-25 18:54:25 (CST)
+# Last Update: Wednesday 2019-05-08 16:25:29 (CST)
 #          By:
 # Description:
 # ********************************************************************************
-from flask import request, g, current_app
+from flask import request, g
 from flask_babel import Babel
+from forums.default import LANGUAGES
 
 babel = Babel()
 
@@ -24,8 +25,7 @@ def locale():
             return 'zh_Hans_CN'
         if g.user.is_authenticated:
             return user.setting.locale or 'zh'
-    return request.accept_languages.best_match(current_app.config['LANGUAGES']
-                                               .keys())
+        return request.accept_languages.best_match(LANGUAGES.keys())
 
 
 @babel.timezoneselector

+ 3 - 3
forums/jinja.py

@@ -6,12 +6,12 @@
 # Author: jianglin
 # Email: xiyang0807@gmail.com
 # Created: 2016-11-07 21:00:32 (CST)
-# Last Update: Thursday 2018-07-26 09:54:53 (CST)
+# Last Update: Wednesday 2019-05-08 16:26:18 (CST)
 #          By:
 # Description:
 # **************************************************************************
 from datetime import datetime
-from config import SITE
+from forums import default
 
 from bleach import clean
 from flask import Markup, g
@@ -82,7 +82,7 @@ def forums_count():
 
 def init_app(app):
 
-    app.jinja_env.globals['SITE'] = SITE
+    app.jinja_env.globals['DEFAULT'] = default
     app.jinja_env.globals['hot_tags'] = hot_tags
     app.jinja_env.globals['recent_tags'] = recent_tags
     app.jinja_env.globals['show_time'] = show_time

+ 3 - 3
static/assets/home.js

@@ -14,11 +14,11 @@ function Follow(obj,data,url){if(obj.hasClass('active')){$.ajax({type:"DELETE",u
 {alert('fail');}}});}else{$.ajax({type:"POST",url:url,data:data,contentType:'application/json;charset=UTF-8',success:function(response){if(response.status==='200')
 {obj.text('取消关注').addClass('active');}else
 {alert('fail');}}});}}
-$(document).ready(function(){$('button.topic-following').click(function(){var _$this=$(this);var url="/following/topics";var data=JSON.stringify({topicId:_$this.attr("data-id"),});Follow(_$this,data,url);});$('button.tag-following').click(function(){var _$this=$(this);var url="/following/tags";var data=JSON.stringify({tagId:_$this.attr("data-id"),});Follow(_$this,data,url);});$('button.user-following').click(function(){var _$this=$(this);var url="/following/users";var data=JSON.stringify({userId:_$this.attr("data-id"),});Follow(_$this,data,url);});$('button.collect-following').click(function(){var _$this=$(this);var url="/following/collects";var data=JSON.stringify({collectId:_$this.attr("data-id"),});Follow(_$this,data,url);});});function DoCollect(collect_url){$(document).ready(function(){$('button#edit-collect').click(function(){var data=JSON.stringify({name:$('#name').val(),description:$('#description').val(),is_hidden:$("input[name='is_hidden']:checked").val()});$.ajax({type:"PUT",url:collect_url,data:data,contentType:'application/json;charset=UTF-8',success:function(response){if(response.status==='200')
+$(document).ready(function(){$('button.topic-following').click(function(){var _$this=$(this);var url="/following/topics";var data=JSON.stringify({pk:_$this.attr("data-id"),});Follow(_$this,data,url);});$('button.tag-following').click(function(){var _$this=$(this);var url="/following/tags";var data=JSON.stringify({tagId:_$this.attr("data-id"),});Follow(_$this,data,url);});$('button.user-following').click(function(){var _$this=$(this);var url="/following/users";var data=JSON.stringify({userId:_$this.attr("data-id"),});Follow(_$this,data,url);});$('button.collect-following').click(function(){var _$this=$(this);var url="/following/collects";var data=JSON.stringify({collectId:_$this.attr("data-id"),});Follow(_$this,data,url);});});function DoCollect(collect_url){$(document).ready(function(){$('button#edit-collect').click(function(){var data=JSON.stringify({name:$('#name').val(),description:$('#description').val(),is_hidden:$("input[name='is_hidden']:checked").val()});$.ajax({type:"PUT",url:collect_url,data:data,contentType:'application/json;charset=UTF-8',success:function(response){if(response.status==='200')
 {window.location.href=collect_url;}}});});$('button#delete-collect').click(function(){$.ajax({type:"DELETE",url:collect_url,data:JSON.stringify(),contentType:'application/json;charset=UTF-8',success:function(response){if(response.status==='200')
-{window.location.href=collect_url;}}});});$('#delete-from-collect').click(function(){var _$this=$(this);var topicId=_$this.attr('data-id');var data=JSON.stringify({topicId:topicId});$.ajax({type:"DELETE",url:'/topic/'+topicId+'/collect',data:data,contentType:'application/json;charset=UTF-8',success:function(response){if(response.status==='200')
+{window.location.href=collect_url;}}});});$('#delete-from-collect').click(function(){var _$this=$(this);var pk=_$this.attr('data-id');var data=JSON.stringify({pk:pk});$.ajax({type:"DELETE",url:'/topic/'+pk+'/collect',data:data,contentType:'application/json;charset=UTF-8',success:function(response){if(response.status==='200')
 {_$this.parent().remove();}}});});});}
-$(document).ready(function(){$('.like-reply').click(function(){var _$this=$(this);var replyId=_$this.attr('data-id');var like_url="/replies/"+replyId+'/like';var data=JSON.stringify({});if(_$this.hasClass('like-active')){$.ajax({type:"DELETE",url:like_url,data:data,contentType:'application/json;charset=UTF-8',success:function(response){if(response.status==='200')
+$(document).ready(function(){$('.like-reply').click(function(){var _$this=$(this);var pk=_$this.attr('data-id');var like_url="/replies/"+pk+'/like';var data=JSON.stringify({});if(_$this.hasClass('like-active')){$.ajax({type:"DELETE",url:like_url,data:data,contentType:'application/json;charset=UTF-8',success:function(response){if(response.status==='200')
 {_$this.attr("title","赞");_$this.removeClass("like-active");_$this.addClass("like-no-active");}else{window.location.href=response.url;}}});}else{$.ajax({type:"POST",url:like_url,data:data,contentType:'application/json;charset=UTF-8',success:function(response){if(response.status==='200')
 {_$this.attr("title","取消赞");_$this.removeClass("like-no-active");_$this.addClass("like-active");}else
 {window.location.href=response.url;}}});}});$('.reply-author').click(function(){var _$this=$(this);var author=_$this.attr('data-id');$('#content').focus();$('#content').val('@'+author+' ');});$('#topic-preview').click(function(){var contentType=$('#content_type').val();if(contentType=="1"){$("#show-preview").html(marked($('#content').val()));}else if(contentType=="2"){var parser=new Org.Parser();var orgDocument=parser.parse($('#content').val());var orgHTMLDocument=orgDocument.convert(Org.ConverterHTML,{headerOffset:1,exportFromLineNumber:false,suppressSubScriptHandling:false,suppressAutoLink:false});$("#show-preview").html(orgHTMLDocument.toString());}else{$("#show-preview").html($('#content').val());}});$('#tokenfield').tokenfield({limit:4});$('#topic-put-btn').click(function(){var _$this=$(this);var url='/topic/'+_$this.attr("data-id");var data={csrf_token:$('input[name="csrf_token"]').val(),title:$('input[name="title"]').val(),tags:$('input[name="tags"]').val(),category:$('select[name="category"]').val(),content:$('textarea[name="content"]').val(),content_type:$('select[name="content_type"]').val()};$.ajax({type:"PUT",url:url,data:JSON.stringify(data),contentType:'application/json;charset=UTF-8',success:function(response){if(response.status==='200'){window.location.href=url;}else{if(response.description!=""){alert(response.description);}else{alert(response.message);}}}});});});

+ 4 - 4
static/styles/following.js

@@ -31,7 +31,7 @@ $(document).ready(function(){
     var _$this = $(this);
     var url = "/following/topics";
     var data = JSON.stringify({
-      topicId:_$this.attr("data-id"),
+      pk:_$this.attr("data-id"),
     });
     Follow(_$this,data,url);
   });
@@ -97,13 +97,13 @@ function DoCollect(collect_url) {
     });
     $('#delete-from-collect').click(function() {
       var _$this = $(this);
-      var topicId = _$this.attr('data-id');
+      var pk = _$this.attr('data-id');
       var data = JSON.stringify({
-        topicId:topicId
+        pk:pk
       });
       $.ajax ({
         type : "DELETE",
-        url : '/topic/' + topicId + '/collect',
+        url : '/topic/' + pk + '/collect',
         data:data,
         contentType: 'application/json;charset=UTF-8',
         success: function(response) {

+ 2 - 2
static/styles/topic.js

@@ -1,8 +1,8 @@
 $(document).ready(function(){
     $('.like-reply').click(function() {
         var _$this = $(this);
-        var replyId = _$this.attr('data-id');
-        var like_url = "/replies/" + replyId + '/like';
+        var pk = _$this.attr('data-id');
+        var like_url = "/replies/" + pk + '/like';
         var data = JSON.stringify({
         });
         if(_$this.hasClass('like-active')){

+ 1 - 3
templates/base/base.html

@@ -5,9 +5,7 @@
 {% import 'base/panel.html' as panel_base %}
 {% from 'base/head.html' import breadcrumb %}
 
-{% block title -%}
-  {{ title }} {{ SITE['title'] }} - {{ _(SITE['description']) }}
-{%- endblock title %}
+{% block title -%}{{ DEFAULT.SITE['title'] }} - {{ _(DEFAULT.SITE['subtitle']) }}{%- endblock title %}
 
 {% block style -%}
   <link href="https://cdn.bootcss.com/font-awesome/4.7.0/css/font-awesome.min.css" rel="stylesheet">

+ 14 - 14
templates/base/form.html

@@ -1,18 +1,18 @@
 {% macro forms(form) %}
-<div class="form-horizontal">
-  {{ form.hidden_tag() }}
-  {% for field in form if field.widget.input_type != 'hidden' %}
-  <div class="form-group">
-    <label class="col-sm-2 control-label">{{ field.label }}</label>
-    <div class="col-sm-10">
-      {{ field(class="form-control")}}
+  <div class="form-horizontal">
+    {{ form.hidden_tag() }}
+    {% for field in form if field.widget.input_type != 'hidden' %}
+      <div class="form-group">
+        <label class="col-sm-2 control-label">{{ field.label }}</label>
+        <div class="col-sm-10">
+          {{ field(class="form-control")}}
+        </div>
+      </div>
+    {% endfor %}
+    <div class="form-group">
+      <div class="col-sm-offset-2 col-sm-10">
+        <button class="btn btn-sm btn-primary" type="submit">{{ _('save') }}</button>
+      </div>
     </div>
   </div>
-  {% endfor %}
-  <div class="form-group">
-    <div class="col-sm-offset-2 col-sm-10">
-      <button class="btn btn-sm btn-primary" type="submit">{{ _('save') }}</button>
-    </div>
-  </div>
-</div>
 {%- endmacro %}

+ 11 - 11
templates/base/head.html

@@ -1,19 +1,19 @@
 {% macro breadcrumb(hrefs=None,active=None) -%}
-<ol class="breadcrumb" style="margin:0">
+  <ol class="breadcrumb" style="margin:0">
     {% if not active %}
-    <li><a href="{{ url_for('forums.forums') }}"><i class="fa fa-home" aria-hidden="true"></i>{{ _('Index') }}</a></li>
+      <li><a href="{{ url_for('forums.forums') }}"><i class="fa fa-home" aria-hidden="true"></i>{{ _('Index') }}</a></li>
     {% else %}
-    <li><a href="{{ url_for('forums.forums') }}"><span class="fa fa-home" aria-hidden="true"></span>{{ _('Index') }}</a></li>
-    {{ breadcrumb_list(hrefs) }}
-    <li class="active">{{ active }}</li>
+      <li><a href="{{ url_for('forums.forums') }}"><span class="fa fa-home" aria-hidden="true"></span>{{ _('Index') }}</a></li>
+      {{ breadcrumb_list(hrefs) }}
+      <li class="active">{{ active }}</li>
     {% endif %}
-</ol>
+  </ol>
 {%- endmacro %}
 
 {% macro breadcrumb_list(hrefs) -%}
-{% if hrefs %}
-{% for k,v in hrefs.items() %}
-<li><a href="{{ v }}">{{ k }}</a></li>
-{% endfor %}
-{% endif %}
+  {% if hrefs %}
+    {% for k,v in hrefs.items() %}
+      <li><a href="{{ v }}">{{ k }}</a></li>
+    {% endfor %}
+  {% endif %}
 {%- endmacro %}

+ 5 - 7
templates/base/header.html

@@ -51,9 +51,9 @@
         <img alt="Honmaple" src="{{url_for('static',filename='images/header.png')}}" style="width:48px;">
       </a>
       <div class="navbar-brand" style="padding-top:2;padding-left:16px;margin-top:-12px;">
-        <span style="font-size:20px;color:#EB5424"><b class="text-capitalize">{{ SITE['title'] }}</b></span>
+        <span style="font-size:20px;color:#EB5424"><b class="text-capitalize">{{ DEFAULT.SITE['title'] }}</b></span>
         <br/>
-        <small style="font-size:10px">{{ _(SITE['description']) }}</small>
+        <small style="font-size:10px">{{ _(DEFAULT.SITE['subtitle']) }}</small>
       </div>
       <button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#collapse-header" aria-expanded="false">
         <span class="sr-only"></span>
@@ -64,11 +64,9 @@
     </div>
     <div class="collapse navbar-collapse" id="collapse-header">
       <ul class="nav navbar-nav">
-        {{ navlist(url_for('forums.forums'),_('Forums')) }}
-        {{ navlist(url_for('docs.list'),_('Wiki')) }}
-        {{ navlist('https://honmaple.me',_('Blog')) }}
-        {{ navlist(url_for('tag.list'),_('TagList')) }}
-        {{ navlist(url_for('topic.good'),_('Good')) }}
+        {% for item in DEFAULT.HEADER %}
+          <li><a href="{% if item.url.startswith("http") %}{{ item.url }}{% else %}{{ url_for(item.url) }}{% endif %}">{{ _(item.name) }}</a></li>
+        {% endfor %}
       </ul>
       <ul class="nav navbar-nav navbar-right" style="margin-left:0px;">
         {{ dropdown() }}

+ 25 - 26
templates/base/link.html

@@ -1,72 +1,71 @@
 {% macro userlist() -%}
-<a href="{{ url_for('user.list') }}">{{ _('UserList') }}</a>
+  <a href="{{ url_for('user.list') }}">{{ _('UserList') }}</a>
 {%- endmacro %}
 
 {% macro user(user) -%}
-<a href="{{ url_for('user.user',username=user.username) }}">{{ user.username }}</a>
+  <a href="{{ url_for('user.user',username=user.username) }}">{{ user.username }}</a>
 {%- endmacro %}
 
 {% macro taglist() -%}
-<a href="{{ url_for('tag.list') }}">{{ _('TagList') }}</a>
+  <a href="{{ url_for('tag.list') }}">{{ _('TagList') }}</a>
 {%- endmacro %}
 
 {% macro tag(tag) -%}
-<a class="tag" href="{{ url_for('tag.tag',name=tag.name) }}">{{ tag.name }}</a>
+  <a class="tag" href="{{ url_for('tag.tag',name=tag.name) }}">{{ tag.name }}</a>
 {%- endmacro %}
 
 {% macro topiclist() -%}
-<a href="{{ url_for('topic.list') }}">{{ _('TopicList') }}</a>
+  <a href="{{ url_for('topic.list') }}">{{ _('TopicList') }}</a>
 {%- endmacro %}
 
 {% macro topic(topic) -%}
-<a href="{{ url_for('topic.topic',topicId=topic.id)}}">{{ topic.title }}</a>
+  <a href="{{ url_for('topic.topic',pk=topic.id)}}">{{ topic.title }}</a>
 {%- endmacro %}
 
 
 {% macro boardlist() -%}
-<a href="{{ url_for('board.list') }}">{{ _('BoardList') }}</a>
+  <a href="{{ url_for('board.list') }}">{{ _('BoardList') }}</a>
 {%- endmacro %}
 
 {% macro board(board) -%}
-<a href="{{ url_for('forums.board',pk=board.id) }}">{{ board.name }}</a>
+  <a href="{{ url_for('forums.board',pk=board.id) }}">{{ board.name }}</a>
 {%- endmacro %}
 
 {% macro avatar(text,width=64) -%}
-<img class="media-object img-circle" src="{{ url_for('avatar',text=text) }}" style="width:{{ width }}px;height:{{ width }}px">
+  <img class="media-object img-circle" src="{{ url_for('avatar',text=text) }}" style="width:{{ width }}px;height:{{ width }}px">
 {%- endmacro %}
 
 {% macro user_avatar(user,width=64) -%}
-{% set info = user.info %}
-{% if not info.avatar -%}
-<a href="{{ url_for('user.user',username=user.username) }}">
-  <img class="img-circle" src="{{ url_for('avatar',text=user.username) }}" style="width:{{ width }}px;height:{{ width }}px">
-</a>
-{% else %}
-<a href="{{ url_for('user.user',username=user.username) }}">
-  <img class="img-circle" src="{{ url_for('upload.avatar_file',filename=info.avatar) }}" style="width:{{ width }}px;height:{{ width }}px">
-</a>
-{%- endif %}
+  {% set info = user.info %}
+  {% if not info.avatar -%}
+    <a href="{{ url_for('user.user',username=user.username) }}">
+      <img class="img-circle" src="{{ url_for('avatar',text=user.username) }}" style="width:{{ width }}px;height:{{ width }}px">
+    </a>
+  {% else %}
+    <a href="{{ url_for('user.user',username=user.username) }}">
+      <img class="img-circle" src="{{ url_for('upload.avatar_file',filename=info.avatar) }}" style="width:{{ width }}px;height:{{ width }}px">
+    </a>
+  {%- endif %}
 {%- endmacro %}
 
 {% macro following_tag() -%}
-<a href="{{ url_for('follow.tag')}}">{{ _('Following Tags') }}</a>
+  <a href="{{ url_for('follow.tag')}}">{{ _('Following Tags') }}</a>
 {%- endmacro %}
 {% macro following_topic() -%}
-<a href="{{ url_for('follow.topic')}}">{{ _('Following Topics')}}</a>
+  <a href="{{ url_for('follow.topic')}}">{{ _('Following Topics')}}</a>
 {%- endmacro %}
 {% macro following_user() -%}
-<a href="{{ url_for('follow.user')}}">{{ _('Following Users')}}</a>
+  <a href="{{ url_for('follow.user')}}">{{ _('Following Users')}}</a>
 {%- endmacro %}
 {% macro following_collect() -%}
-<a href="{{ url_for('follow.collect')}}">{{ _('Following Collects')}}</a>
+  <a href="{{ url_for('follow.collect')}}">{{ _('Following Collects')}}</a>
 {%- endmacro %}
 
 
 {% macro collectlist() -%}
-<a href="{{ url_for('collect.list')}}">{{ _('CollectList')}}</a>
+  <a href="{{ url_for('collect.list')}}">{{ _('CollectList')}}</a>
 {%- endmacro %}
 
 {% macro collect(c) -%}
-<a href="{{ url_for('collect.collect',pk=c.id)}}">{{ c.name }}</a>
+  <a href="{{ url_for('collect.collect',pk=c.id)}}">{{ c.name }}</a>
 {%- endmacro %}
-

+ 3 - 0
templates/board/board.html

@@ -1,4 +1,7 @@
 {% extends 'base/base.html' %}
+
+{% block title -%}{{ board.name }} · {{ super() }}{%- endblock title %}
+
 {% block content %}
   {% if board.parent_id %}
     {{ breadcrumb(hrefs={board.parent.name:url_for('forums.board',pk=board.parent_id)},active=board.name) }}

+ 19 - 16
templates/board/board_list.html

@@ -1,19 +1,22 @@
 {% extends 'base/base.html' %}
+
+{% block title -%}{{ _("Board") }} · {{ super() }}{%- endblock title %}
+
 {% block content %}
-{% from 'board/_macro.html' import board_body %}
-{{ breadcrumb(active=_('Board')) }}
-{% for board in boards.items %}
-{% if not board.parents %}
-<div class="panel panel-primary">
-  <div class="panel-heading">
-    <a href="{{ url_for('forums.board',pk=board.id) }}" style="color:#fff"> {{ board.name }} </a>
-  </div>
-  {% for child in board.children -%}
-  {{ board_body(child) }}
-  {% else %}
-  {{ board_body(board) }}
-  {%- endfor %}
-</div>
-{% endif %}
-{% endfor %}
+  {% from 'board/_macro.html' import board_body %}
+  {{ breadcrumb(active=_('Board')) }}
+  {% for board in boards %}
+    {% if not board.parents %}
+      <div class="panel panel-primary">
+        <div class="panel-heading">
+          <a href="{{ url_for('forums.board',pk=board.id) }}" style="color:#fff"> {{ board.name }} </a>
+        </div>
+        {% for child in board.children -%}
+          {{ board_body(child) }}
+    {% else %}
+          {{ board_body(board) }}
+        {%- endfor %}
+      </div>
+    {% endif %}
+  {% endfor %}
 {% endblock %}

+ 1 - 1
templates/collect/collect.html

@@ -16,7 +16,7 @@
       </div>
       {% for topic in topics.items %}
       <div class="panel-body" style="border-bottom:1px solid #eee">
-        <a href="{{ url_for('topic.topic',topicId=topic.id)}}">{{ topic.title}}</a>
+        <a href="{{ url_for('topic.topic',pk=topic.id)}}">{{ topic.title}}</a>
         <span id="delete-from-collect" class="pull-right btn btn-sm btn-danger" data-id="{{ topic.id }}">{{_('delete')}}</span>
       </div>
       {% else %}

+ 46 - 42
templates/forums/_macro.html

@@ -1,58 +1,62 @@
 {% macro forums_title() -%}
-<div class="panel panel-default hidden-xs">
+  <div class="panel panel-default hidden-xs">
     <div class="panel-body" style="text-align: center;">
-        <div class="media" style="width: 480px; margin:0px auto; text-align: left;">
-            <div class="media-left">
-                <i class="icon-gift media-object" style="font-size: 55px; width: 55px; color: #333;"></i>
-            </div>
-            <div class="media-body" style="line-height: 200%; text-align: center;">
-                <div style="font-size: 15px">
-                    Honmaple {{ _('Office Source Code')}} <a href="https://github.com/honmaple/maple-bbs" target="_blank">Honmaple</a>
-                </div>
-                <code style="padding: 4px 10px;">git clone git@github.com:honmaple/maple-bbs.git</code>
-            </div>
+      <div class="media" style="width: 480px; margin:0px auto; text-align: left;">
+        <div class="media-left">
+          <i class="icon-gift media-object" style="font-size: 55px; width: 55px; color: #333;"></i>
+        </div>
+        <div class="media-body" style="line-height: 200%; text-align: center;">
+          <div style="font-size: 15px">
+            Honmaple {{ _('Office Source Code')}} <a href="https://github.com/honmaple/maple-bbs" target="_blank">Honmaple</a>
+          </div>
+          <code style="padding: 4px 10px;">git clone git@github.com:honmaple/maple-bbs.git</code>
         </div>
+      </div>
     </div>
-</div>
+  </div>
 {%- endmacro %}
 
-{% macro forums_item(name,url,icon,color="#337ab7") %}
-<div class="col-md-3">
-    <div class="panel panel-default">
-        <a href="{{ url }}">
+{% macro forums_item() %}
+  <div class="row hidden-sm hidden-xs">
+    {% for item in DEFAULT.INDEX %}
+      <div class="col-md-3">
+        <div class="panel panel-default">
+          <a href="{% if item.url.startswith("http") %}{{ item.url }}{% else %}{{ url_for(item.url) }}{% endif %}">
             <div class="panel-body text-center">
-                <i class="fa {{ icon }}" style="font-size:55px;color:{{ color }}"></i>
+              <i class="fa {{ item.icon }}" style="font-size:55px;color:{{ item.color }}"></i>
             </div>
-        </a>
-        <a href="{{ url }}">
+          </a>
+          <a href="{% if item.url.startswith("http") %}{{ item.url }}{% else %}{{ url_for(item.url) }}{% endif %}">
             <div class="panel-footer">
-                {{ name }}
-                <i class="pull-right fa fa-arrow-right"></i>
+              {{ _(item.name) }}
+              <i class="pull-right fa fa-arrow-right"></i>
             </div>
-        </a>
-    </div>
-</div>
+          </a>
+        </div>
+      </div>
+    {% endfor %}
+  </div>
 {%- endmacro %}
 
 {% macro topic_form() -%}
-<div class="panel-heading" style="font-size:12px;">
+  <div class="panel-heading" style="font-size:12px;">
     <div class="row">
-        <div class="col-sm-6">
-            {{_('Choice:')}}
-            {{ g.sort_form.display() }}
-            {{ _('Order:')}}
-            {{ g.sort_form.sort() }}
-            {{ g.sort_form.st() }}
-        </div>
-        <div class="col-sm-2 hidden-xs">
-            {{ _('Author') }}
-        </div>
-        <div class="col-sm-2 hidden-xs">
-            {{_('Replies/Read')}}
-        </div>
-        <div class="col-sm-2 hidden-xs">
-            {{_('Last reply')}}
-        </div>
+      <div class="col-sm-6">
+        {{_('Choice:')}}
+        {{ g.sort_form.display() }}
+        {{ _('Order:')}}
+        {{ g.sort_form.sort() }}
+        {{ g.sort_form.st() }}
+      </div>
+      <div class="col-sm-2 hidden-xs">
+        {{ _('Author') }}
+      </div>
+      <div class="col-sm-2 hidden-xs">
+        {{_('Replies/Read')}}
+      </div>
+      <div class="col-sm-2 hidden-xs">
+        {{_('Last reply')}}
+      </div>
     </div>
-</div>
+  </div>
 {%- endmacro %}

+ 11 - 8
templates/forums/about.html

@@ -1,14 +1,17 @@
 {% extends 'base/base.html' %}
+
+{% block title -%}{{ _("About") }} · {{ super() }}{%- endblock title %}
+
 {% block content %}
-{{ breadcrumb(active=_('About')) }}
-{% cache 300 %}
-<div class="panel panel-primary">
-    <div class="panel-heading">
+  {{ breadcrumb(active=_('About')) }}
+  {% cache 300 %}
+    <div class="panel panel-primary">
+      <div class="panel-heading">
         {{ _('About')}}
-    </div>
-    <div class="panel-body">
+      </div>
+      <div class="panel-body">
         about
+      </div>
     </div>
-</div>
-{% endcache %}
+  {% endcache %}
 {% endblock %}

+ 12 - 9
templates/forums/contact.html

@@ -1,14 +1,17 @@
 {% extends 'base/base.html' %}
+
+{% block title -%}{{ _("Contact") }} · {{ super() }}{%- endblock title %}
+
 {% block content %}
-{{ breadcrumb(active=_('Contact me')) }}
-{% cache 300 %}
-<div class="panel panel-primary">
-    <div class="panel-heading">
+  {{ breadcrumb(active=_('Contact me')) }}
+  {% cache 300 %}
+    <div class="panel panel-primary">
+      <div class="panel-heading">
         {{ _('Contact me') }}
+      </div>
+      <div class="panel-body">
+        root@honmaple.com
+      </div>
     </div>
-    <div class="panel-body">
-          root@honmaple.com
-    </div>
-</div>
-{% endcache %}
+  {% endcache %}
 {% endblock %}

+ 11 - 8
templates/forums/help.html

@@ -1,14 +1,17 @@
 {% extends 'base/base.html' %}
+
+{% block title -%}{{ _("Help") }} · {{ super() }}{%- endblock title %}
+
 {% block content %}
-{{ breadcrumb(active=_('Help')) }}
-{% cache 300 %}
-<div class="panel panel-primary">
-    <div class="panel-heading">
+  {{ breadcrumb(active=_('Help')) }}
+  {% cache 300 %}
+    <div class="panel panel-primary">
+      <div class="panel-heading">
         {{ _('Help') }}
-    </div>
-    <div class="panel-body">
+      </div>
+      <div class="panel-body">
         help
+      </div>
     </div>
-</div>
-{% endcache %}
+  {% endcache %}
 {% endblock %}

+ 25 - 27
templates/forums/index.html

@@ -1,36 +1,34 @@
 {% extends 'base/base.html' %}
+
 {% block content %}
-{% from 'forums/_macro.html' import forums_title,forums_item %}
-{% from 'topic/_list_macro.html' import form as topic_form %}
-{% from 'topic/_list_macro.html' import body as topic_body %}
-{% from 'topic/_list_macro.html' import no_topics %}
-{{ breadcrumb() }}
-{{ forums_title() }}
-<div class="row hidden-sm hidden-xs">
-    {{ forums_item(_('Forums'),url_for('forums.forums'),"fa-comments","#F86334")}}
-    {{ forums_item(_('Wiki'),url_for('docs.list'),"fa-book","#eeccaa")}}
-    {{ forums_item(_('Blog'),'http://honmaple.org',"fa-tasks")}}
-    {{ forums_item(_('Good'),url_for('topic.good'),"fa-globe","#017e66")}}
-</div>
-<div class="row">
+  {% from 'forums/_macro.html' import forums_title,forums_item %}
+  {% from 'topic/_list_macro.html' import form as topic_form %}
+  {% from 'topic/_list_macro.html' import body as topic_body %}
+  {% from 'topic/_list_macro.html' import no_topics %}
+  {{ breadcrumb() }}
+  {{ forums_title() }}
+  {{ forums_item() }}
+  <div class="row">
     <div class="col-md-9">
-        <div class="panel panel-default">
-            {{ topic_form() }}
-            {% for topic in topics.items %}
+      <div class="panel panel-default">
+        {{ topic_form() }}
+        {% if topics.items  %}
+          {% for topic in topics.items %}
             {{ topic_body(topic) }}
-            {% else %}
-            {{ no_topics() }}
-            {% endfor %}
-            <div class="panel-footer clearfix">
-                <a class="pull-right" href="{{ url_for('topic.good')}}">
-                    {{ _('more good topics') }}
-                    <i class="icon-arrow-right"></i>
-                </a>
-            </div>
+          {% endfor %}
+        {% else %}
+          {{ no_topics() }}
+        {% endif %}
+        <div class="panel-footer clearfix">
+          <a class="pull-right" href="{{ url_for('topic.good')}}">
+            {{ _('more good topics') }}
+            <i class="icon-arrow-right"></i>
+          </a>
         </div>
+      </div>
     </div>
     <div class="col-md-3" style="padding-left:0">
-        {{ panel_base.index() }}
+      {{ panel_base.index() }}
     </div>
-</div>
+  </div>
 {% endblock %}

+ 2 - 4
templates/maple/footer.html

@@ -57,9 +57,7 @@
     </p>
   </div>
   <blockquote>
-    <p>{{ _(SITE['description']) }}</p>
-    <footer>
-      © 2015-2018 honmaple.
-    </footer>
+    <p style="color:#888;">{{ _(DEFAULT.SITE['subtitle']) }}</p>
+    <footer>© 2015-2019 honmaple.</footer>
   </blockquote>
 </div>

+ 1 - 1
templates/search/result.html

@@ -10,7 +10,7 @@
     </div>
     {% for result in results.items %}
       <div class="panel-body text-center" style="padding:6px;border-bottom:1px solid #eee">
-        <a href="{{ url_for('topic.topic',topicId=result.id) }}">{{ result.title }}</a>
+        <a href="{{ url_for('topic.topic',pk=result.id) }}">{{ result.title }}</a>
       </div>
     {% else %}
       <div class="panel-body text-center">

+ 3 - 0
templates/tag/tag.html

@@ -1,4 +1,7 @@
 {% extends 'base/base.html' %}
+
+{% block title -%}{{ tag.name }} · {{ super() }}{%- endblock title %}
+
 {% block content %}
   {% from 'tag/_macro.html' import title %}
   {{ breadcrumb(hrefs={_('All Tags'):url_for('tag.list')},active=tag.name)}}

+ 3 - 0
templates/tag/tag_list.html

@@ -1,4 +1,7 @@
 {% extends 'base/base.html' %}
+
+{% block title -%}{{ _("Tags") }} · {{ super() }}{%- endblock title %}
+
 {% block content %}
   {{ breadcrumb(active=_('All Tags'))}}
   <div class="row">

+ 1 - 1
templates/topic/_list_macro.html

@@ -45,7 +45,7 @@
       {% if topic.is_top %}
       <span><i class="fa fa-thumb-tack text-danger">&nbsp</i></span>
       {% endif %}
-      <a href="{{url_for('topic.topic',topicId=topic.id)}}" style="color:#555">{{ topic.title }}</a>
+      <a href="{{url_for('topic.topic',pk=topic.id)}}" style="color:#555">{{ topic.title }}</a>
     </div>
     <span class="visible-xs-inline">
       <small style="font-size:10px;">由{{ link.user(author) }}</small>

+ 1 - 1
templates/topic/collect.html

@@ -14,7 +14,7 @@
       </div>
       {% else %}
       <div class="modal-body">
-        <form action="{{ url_for('collect.add_to_collect',topicId=topic.id) }}" method="POST">
+        <form action="{{ url_for('collect.add_to_collect',pk=topic.id) }}" method="POST">
           {{ form.hidden_tag() }}
           <p> 添加到收藏夹 </p>
           {% for collect in collects %}

+ 1 - 1
templates/topic/panel.html

@@ -6,7 +6,7 @@
   <button type="button" class="btn btn-info btn-block topic-following" data-id="{{topic.id}}">关注问题</button>
   {% endif %}
   {% if g.user == topic.author %}
-  <a class="btn btn-success btn-block" href="{{ url_for('topic.edit',topicId=topic.id)}}">
+  <a class="btn btn-success btn-block" href="{{ url_for('topic.edit',pk=topic.id)}}">
     编辑问题
   </a>
   {%- endif %}

+ 1 - 1
templates/topic/reply/form.html

@@ -2,7 +2,7 @@
   {% if g.user.is_authenticated %}
   <div class="panel-heading"> {{ _('Reply this topic') }} </div>
   <div class="panel-body">
-    <form action="{{ url_for('topic.reply_list',topicId=topic.id)}}" method="POST">
+    <form action="{{ url_for('topic.reply_list',pk=topic.id)}}" method="POST">
       {{ form.hidden_tag() }}
       {{ form.content(class='form-control',rows=4)}}
       <button class="btn btn-sm btn-primary" type="submit" style="margin-top:10px;">{{ _('Post reply') }}</button>

+ 3 - 3
templates/topic/reply/itemlist.html

@@ -5,8 +5,8 @@
   <div class="panel-heading">
     {{ _('Received %(total)s replies',total=replies.total) }}
     <ul class="pull-right list-inline reply-order">
-      <li><a href="{{ url_for('topic.topic',topicId=topic.id,orderby='time')}}"> <i class="icon icon-time"></i>{{_('time')}}</a></li>
-      <li><a href="{{ url_for('topic.topic',topicId=topic.id,orderby='like')}}"> <i class="icon icon-thumbs-up"></i>{{_('likers')}}</a></li>
+      <li><a href="{{ url_for('topic.topic',pk=topic.id,orderby='time')}}"> <i class="icon icon-time"></i>{{_('time')}}</a></li>
+      <li><a href="{{ url_for('topic.topic',pk=topic.id,orderby='like')}}"> <i class="icon icon-thumbs-up"></i>{{_('likers')}}</a></li>
     </ul>
   </div>
   {% if replies.items %}
@@ -39,7 +39,7 @@
     </div>
   </div>
   {% endfor %}
-  {{ p_footer(replies,'topic.topic',dict(topicId=topic.id))}}
+  {{ p_footer(replies,'topic.topic',dict(pk=topic.id))}}
   {% else %}
   {{ no_replies() }}
   {% endif %}

+ 20 - 20
templates/topic/topic.html

@@ -1,26 +1,26 @@
 {% extends 'base/base.html' %}
 {% block content %}
-{% set board = topic.board %}
-{% if board.parent_id %}
-{{ breadcrumb(hrefs={board.parent.name:url_for('forums.board',pk=board.parent_id),
-                     board.name:url_for('forums.board',pk=board.id)},active=topic.title) }}
-{% else %}
-{{ breadcrumb(hrefs={board.name:url_for('forums.board',pk=board.id)},active=topic.title) }}
-{% endif %}
-<div class="row">
-  <div class="col-md-9">
-    <div class="panel panel-default">
-      {% include "topic/item/heading.html" %}
-      {% include "topic/item/body.html" %}
+  {% set board = topic.board %}
+  {% if board.parent_id %}
+    {{ breadcrumb(hrefs={board.parent.name:url_for('forums.board',pk=board.parent_id),
+        board.name:url_for('forums.board',pk=board.id)},active=topic.title) }}
+  {% else %}
+    {{ breadcrumb(hrefs={board.name:url_for('forums.board',pk=board.id)},active=topic.title) }}
+  {% endif %}
+  <div class="row">
+    <div class="col-md-9">
+      <div class="panel panel-default">
+        {% include "topic/item/heading.html" %}
+        {% include "topic/item/body.html" %}
+      </div>
+      <div id="replies">
+        {% include "topic/reply/itemlist.html" %}
+      </div>
     </div>
-    <div id="replies">
-      {% include "topic/reply/itemlist.html" %}
+    <div class="col-md-3" style="padding-left:0">
+      {% include "topic/panel.html" %}
+      {% set ask_url = url_for('topic.ask',pk=topic.board_id) %}
+      {{ panel_base.board() }}
     </div>
   </div>
-  <div class="col-md-3" style="padding-left:0">
-    {% include "topic/panel.html" %}
-    {% set ask_url = url_for('topic.ask',pk=topic.board_id) %}
-    {{ panel_base.board() }}
-  </div>
-</div>
 {% endblock %}

+ 3 - 0
templates/topic/topic_list.html

@@ -1,4 +1,7 @@
 {% extends 'base/base.html' %}
+
+{% block title -%}{{ title }} · {{ super() }}{%- endblock title %}
+
 {% block content %}
   {% if request.path.endswith('top') %}
     {{ breadcrumb(hrefs={_('All Topics'):url_for('topic.list')},active=_('Top Topics')) }}