Browse Source

add notice(增加消息通知)

honmaple 8 years ago
parent
commit
86e93a7933

+ 1 - 1
forums/__init__.py

@@ -6,7 +6,7 @@
 # Author: jianglin
 # Author: jianglin
 # Email: xiyang0807@gmail.com
 # Email: xiyang0807@gmail.com
 # Created: 2017-01-25 20:10:50 (CST)
 # Created: 2017-01-25 20:10:50 (CST)
-# Last Update:星期三 2017-3-29 11:25:18 (CST)
+# Last Update:星期五 2017-3-31 17:37:56 (CST)
 #          By:
 #          By:
 # Description:
 # Description:
 # **************************************************************************
 # **************************************************************************

+ 42 - 0
forums/admin/message.py

@@ -0,0 +1,42 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+# **************************************************************************
+# Copyright © 2017 jianglin
+# File Name: message.py
+# Author: jianglin
+# Email: xiyang0807@gmail.com
+# Created: 2017-04-01 18:52:43 (CST)
+# Last Update:星期六 2017-4-1 18:55:37 (CST)
+#          By:
+# Description:
+# **************************************************************************
+from .views import BaseView
+from forums.extension import db
+from forums.api.message.models import MessageText, Message
+
+
+class MessageTextView(BaseView):
+    pass
+
+
+class MessageView(BaseView):
+    pass
+    # column_searchable_list = ['name']
+    # form_excluded_columns = ('topics', 'followers')
+
+
+def register_message(admin):
+    admin.add_view(
+        MessageView(
+            Message,
+            db.session,
+            name='管理通知',
+            endpoint='admin_message',
+            category='管理通知'))
+    admin.add_view(
+        MessageTextView(
+            MessageText,
+            db.session,
+            name='管理内容',
+            endpoint='admin_message_text',
+            category='管理通知'))

+ 3 - 1
forums/admin/urls.py

@@ -6,7 +6,7 @@
 # Author: jianglin
 # Author: jianglin
 # Email: xiyang0807@gmail.com
 # Email: xiyang0807@gmail.com
 # Created: 2016-10-28 10:15:42 (CST)
 # Created: 2016-10-28 10:15:42 (CST)
-# Last Update:星期三 2017-3-29 13:13:11 (CST)
+# Last Update:星期六 2017-4-1 18:55:17 (CST)
 #          By:
 #          By:
 # Description:
 # Description:
 # **************************************************************************
 # **************************************************************************
@@ -15,8 +15,10 @@ from .forums import register_forums
 # from .permission import register_permission
 # from .permission import register_permission
 from .user import register_user
 from .user import register_user
 from .topic import register_topic
 from .topic import register_topic
+from .message import register_message
 
 
 register_forums(admin)
 register_forums(admin)
 register_user(admin)
 register_user(admin)
 register_topic(admin)
 register_topic(admin)
+register_message(admin)
 # register_permission(admin)
 # register_permission(admin)

+ 3 - 1
forums/api/collect/views.py

@@ -6,7 +6,7 @@
 # Author: jianglin
 # Author: jianglin
 # Email: xiyang0807@gmail.com
 # Email: xiyang0807@gmail.com
 # Created: 2017-03-28 16:15:08 (CST)
 # Created: 2017-03-28 16:15:08 (CST)
-# Last Update:星期三 2017-3-29 19:1:59 (CST)
+# Last Update:星期六 2017-4-1 20:38:59 (CST)
 #          By:
 #          By:
 # Description:
 # Description:
 # **************************************************************************
 # **************************************************************************
@@ -25,6 +25,7 @@ from forums.api.topic.models import Topic
 from forums.common.serializer import Serializer
 from forums.common.serializer import Serializer
 from forums.common.utils import gen_filter_dict, gen_order_by
 from forums.common.utils import gen_filter_dict, gen_order_by
 from forums.common.views import IsAuthMethodView as MethodView
 from forums.common.views import IsAuthMethodView as MethodView
+from forums.api.message.models import MessageClient
 
 
 from .models import Collect
 from .models import Collect
 
 
@@ -106,6 +107,7 @@ class AddToCollectView(MethodView):
                     topics__id=topic.id, author_id=user.id).exists():
                     topics__id=topic.id, author_id=user.id).exists():
                 collect.topics.append(topic)
                 collect.topics.append(topic)
                 collect.save()
                 collect.save()
+            MessageClient.collect(topic)
         return redirect(url_for('topic.topic', topicId=topic.id))
         return redirect(url_for('topic.topic', topicId=topic.id))
 
 
     # def delete(self, topicId):
     # def delete(self, topicId):

+ 6 - 2
forums/api/follow/views.py

@@ -6,18 +6,19 @@
 # Author: jianglin
 # Author: jianglin
 # Email: xiyang0807@gmail.com
 # Email: xiyang0807@gmail.com
 # Created: 2016-12-22 21:49:05 (CST)
 # Created: 2016-12-22 21:49:05 (CST)
-# Last Update:星期三 2017-3-29 12:40:41 (CST)
+# Last Update:星期六 2017-4-1 19:52:14 (CST)
 #          By:
 #          By:
 # Description:
 # Description:
 # **************************************************************************
 # **************************************************************************
 from flask import render_template, request
 from flask import render_template, request
 
 
 from forums.api.tag.models import Tags
 from forums.api.tag.models import Tags
-from forums.api.topic.models import  Topic
+from forums.api.topic.models import Topic
 from forums.api.collect.models import Collect
 from forums.api.collect.models import Collect
 from forums.api.user.models import User
 from forums.api.user.models import User
 from forums.common.response import HTTPResponse
 from forums.common.response import HTTPResponse
 from forums.common.views import IsAuthMethodView as MethodView
 from forums.common.views import IsAuthMethodView as MethodView
+from forums.api.message.models import MessageClient
 
 
 
 
 class FollowingTagsView(MethodView):
 class FollowingTagsView(MethodView):
@@ -71,6 +72,8 @@ class FollowingTopicsView(MethodView):
             topic = Topic.query.filter_by(id=topic_id).first_or_404()
             topic = Topic.query.filter_by(id=topic_id).first_or_404()
             user.following_topics.append(topic)
             user.following_topics.append(topic)
             user.save()
             user.save()
+            # notice
+            MessageClient.follow(topic)
         return HTTPResponse(HTTPResponse.NORMAL_STATUS).to_response()
         return HTTPResponse(HTTPResponse.NORMAL_STATUS).to_response()
 
 
     def delete(self):
     def delete(self):
@@ -102,6 +105,7 @@ class FollowingUsersView(MethodView):
             if not f_user.is_followed(user):
             if not f_user.is_followed(user):
                 user.following_users.append(f_user)
                 user.following_users.append(f_user)
                 user.save()
                 user.save()
+            MessageClient.follow(f_user)
         return HTTPResponse(HTTPResponse.NORMAL_STATUS).to_response()
         return HTTPResponse(HTTPResponse.NORMAL_STATUS).to_response()
 
 
     def delete(self):
     def delete(self):

+ 1 - 1
forums/api/forums/models.py

@@ -6,7 +6,7 @@
 # Author: jianglin
 # Author: jianglin
 # Email: xiyang0807@gmail.com
 # Email: xiyang0807@gmail.com
 # Created: 2017-03-25 18:48:33 (CST)
 # Created: 2017-03-25 18:48:33 (CST)
-# Last Update:星期四 2017-3-30 14:49:19 (CST)
+# Last Update:星期五 2017-3-31 15:53:1 (CST)
 #          By:
 #          By:
 # Description:
 # Description:
 # **************************************************************************
 # **************************************************************************

+ 12 - 0
forums/api/message/__init__.py

@@ -0,0 +1,12 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+# **************************************************************************
+# Copyright © 2017 jianglin
+# File Name: __init__.py
+# Author: jianglin
+# Email: xiyang0807@gmail.com
+# Created: 2017-04-01 18:33:33 (CST)
+# Last Update:星期六 2017-4-1 18:33:34 (CST)
+#          By:
+# Description:
+# **************************************************************************

+ 280 - 0
forums/api/message/models.py

@@ -0,0 +1,280 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+# **************************************************************************
+# Copyright © 2017 jianglin
+# File Name: models.py
+# Author: jianglin
+# Email: xiyang0807@gmail.com
+# Created: 2017-04-01 18:33:37 (CST)
+# Last Update:星期六 2017-4-1 20:49:46 (CST)
+#          By:
+# Description:
+# **************************************************************************
+from flask import url_for
+from flask_login import current_user
+from forums.extension import db
+from forums.filters import safe_markdown
+from forums.common.models import CommonTimeMixin
+
+
+class MessageText(CommonTimeMixin, db.Model):
+    __tablename__ = 'message_text'
+
+    MESSAGE_TYPE_PUBLIC = '0'
+    MESSAGE_TYPE_TOPIC = '1'
+    MESSAGE_TYPE_REPLY = '2'
+    MESSAGE_TYPE_PRIVATE = '3'
+
+    MESSAGE_TYPE = (('0', '系统消息'), ('1', '主题相关'), ('2', '回复相关'), ('3', '私信'))
+
+    STATUS_SUBMIT = '0'
+    STATUS_PUBLISH = '1'
+    STATUS_UNDO = '2'
+
+    STATUS = (('0', '未发布'), ('1', '已发布'), ('2', '撤销发布'))
+
+    READ_STATUS_UNREAD = '0'
+    READ_STATUS_READ = '1'
+    READ_STATUS = (('0', '未读'), ('1', '已读'))
+
+    title = db.Column(db.String(128), nullable=False, doc='站内信标题')
+    content = db.Column(db.String(1024), nullable=False, doc='站内信内容')
+    status = db.Column(
+        db.String(128), nullable=False, default=STATUS_SUBMIT, doc='站内信状态')
+    message_type = db.Column(
+        db.String(128),
+        nullable=False,
+        default=MESSAGE_TYPE_PUBLIC,
+        doc='站内信类型')
+    sender_id = db.Column(db.Integer, db.ForeignKey('users.id'))
+    sender = db.relationship(
+        'User',
+        backref=db.backref(
+            'send_messages', lazy='dynamic'),
+        lazy='joined',
+        uselist=False)
+
+    @classmethod
+    def get_choice_dict(cls):
+        return dict(messagetext=dict(
+            status=dict(cls.STATUS),
+            message_type=dict(cls.MESSAGE_TYPE),
+            read_status=dict(cls.READ_STATUS)))
+
+    def __str__(self):
+        return self.title
+
+    def __repr__(self):
+        return "<MessageText %r>" % self.title
+
+    @property
+    def read_status(self):
+        '''
+        判断站内信是否已读
+        '''
+        message = Message.query.filter_by(message_text_id=self.id).first()
+        if message:
+            return '已读' if message.status == Message.STATUS_READ else '已删除'
+        return '未读'
+
+
+class Message(CommonTimeMixin, db.Model):
+    __tablename__ = 'message'
+
+    STATUS_UNREAD = '0'
+    STATUS_READ = '1'
+    STATUS_DELETE = '2'
+
+    STATUS = (('0', '未读'), ('1', '已读'), ('2', '删除'))
+
+    status = db.Column(
+        db.String(128), nullable=False, default=STATUS_UNREAD, doc='站内信状态')
+    message_text_id = db.Column(db.Integer, db.ForeignKey('message_text.id'))
+    message_text = db.relationship(
+        MessageText,
+        backref=db.backref(
+            "messages", cascade='all,delete', lazy='dynamic'),
+        uselist=False,
+        lazy='joined')
+    receiver_id = db.Column(db.Integer, db.ForeignKey('users.id'))
+    receiver = db.relationship(
+        'User',
+        backref=db.backref(
+            'receive_messages', lazy='dynamic'),
+        lazy='joined',
+        uselist=False)
+
+    def __str__(self):
+        return self.status
+
+    def __repr__(self):
+        return "<Message %r>" % self.status
+
+    @property
+    def title(self):
+        return safe_markdown(self.message_text.title)
+        # return self.message_text.title
+
+    @property
+    def content(self):
+        return self.message_text.content
+
+    @classmethod
+    def get_choice_dict(cls):
+        return dict(message=dict(status=dict(cls.STATUS)))
+
+
+class MessageClient(object):
+    def system():
+        '''
+        系统消息
+        '''
+
+    @classmethod
+    def topic(cls, reply, sender=None):
+        '''
+        回复主题
+        '''
+        if sender is None:
+            sender = current_user
+        topic = reply.topic
+        receiver = topic.author
+        if sender.id == receiver.id:
+            return
+        title = '[{}]({})回复了你创建的主题:[{}]({})'.format(
+            sender.username,
+            url_for(
+                'user.user', username=sender.username),
+            topic.title,
+            url_for(
+                'topic.topic', topicId=topic.id))
+        content = reply.content
+        message_text = MessageText(
+            sender_id=sender.id, title=title, content=content)
+        message_text.save()
+        message = Message(receiver=receiver, message_text=message_text)
+        message.save()
+        receiver.message_count = 1
+
+    @classmethod
+    def collect(cls, topic, sender=None):
+        '''
+        收藏
+        '''
+        if sender is None:
+            sender = current_user
+        receiver = topic.author
+        if sender.id == receiver.id:
+            return
+        title = '[{}]({})收藏了你创建的主题:[{}]({})'.format(
+            sender.username,
+            url_for(
+                'user.user', username=sender.username),
+            topic.title,
+            url_for(
+                'topic.topic', topicId=topic.id))
+        content = 'a'
+        message_text = MessageText(
+            sender_id=sender.id, title=title, content=content)
+        message_text.save()
+        message = Message(receiver=receiver, message_text=message_text)
+        message.save()
+        receiver.message_count = 1
+
+    @classmethod
+    def follow(cls, following, sender=None):
+        '''
+        关注用户,关注主题,关注收藏
+        '''
+        if sender is None:
+            sender = current_user
+        if following.__class__.__name__ == 'Topic':
+            receiver = following.author
+            title = '[{}]({})关注了你创建的主题:[{}]({})'.format(
+                sender.username,
+                url_for(
+                    'user.user', username=sender.username),
+                following.title,
+                url_for(
+                    'topic.topic', topicId=following.id))
+        elif following.__class__.__name__ == 'Collect':
+            receiver = following.author
+            title = '[{}]({})关注了你创建的收藏:[{}]({})'.format(
+                sender.username,
+                url_for(
+                    'user.user', username=sender.username),
+                following.title,
+                url_for(
+                    'collect.collect', pk=following.id))
+        elif following.__class__.__name__ == 'User':
+            receiver = following
+            title = '[{}]({})关注了你'.format(
+                sender.username,
+                url_for(
+                    'user.user', username=sender.username))
+        if sender.id == receiver.id:
+            return
+        content = 'a'
+        message_text = MessageText(
+            sender_id=sender.id, title=title, content=content)
+        message_text.save()
+        message = Message(receiver=receiver, message_text=message_text)
+        message.save()
+        receiver.message_count = 1
+
+    @classmethod
+    def reply(cls, reply, sender=None):
+        '''
+        子回复
+        '''
+        if sender is None:
+            sender = current_user
+        receiver = reply.author
+        if sender.id == receiver.id:
+            return
+        topic = reply.topic
+        title = '[{}]({})在[{}]({})回复了你'.format(
+            sender.username,
+            url_for(
+                'user.user', username=sender.username),
+            topic.title,
+            url_for(
+                'topic.topic', topicId=topic.id))
+        content = reply.content
+        message_text = MessageText(
+            sender_id=sender.id, title=title, content=content)
+        message_text.save()
+        message = Message(receiver=receiver, message_text=message_text)
+        message.save()
+        receiver.message_count = 1
+
+    @classmethod
+    def like(cls, reply, sender=None):
+        '''
+        点赞
+        '''
+        if sender is None:
+            sender = current_user
+        receiver = reply.author
+        if sender.id == receiver.id:
+            return
+        topic = reply.topic
+        title = '[{}]({})在[{}]({})赞了你的回复'.format(
+            sender.username,
+            url_for(
+                'user.user', username=sender.username),
+            topic.title,
+            url_for(
+                'topic.topic', topicId=topic.id))
+        content = reply.content
+        message_text = MessageText(
+            sender_id=sender.id, title=title, content=content)
+        message_text.save()
+        message = Message(receiver=receiver, message_text=message_text)
+        message.save()
+        receiver.message_count = 1
+
+    def private(cls, message, sender=None):
+        '''
+        私信
+        '''

+ 20 - 0
forums/api/message/urls.py

@@ -0,0 +1,20 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+# **************************************************************************
+# Copyright © 2017 jianglin
+# File Name: urls.py
+# Author: jianglin
+# Email: xiyang0807@gmail.com
+# Created: 2017-04-01 18:34:38 (CST)
+# Last Update:星期六 2017-4-1 20:6:3 (CST)
+#          By:
+# Description:
+# **************************************************************************
+from flask import Blueprint
+from .views import MessageListView
+
+site = Blueprint('message', __name__, url_prefix='/message')
+
+message_list = MessageListView.as_view('list')
+
+site.add_url_rule('', view_func=message_list)

+ 32 - 0
forums/api/message/views.py

@@ -0,0 +1,32 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+# **************************************************************************
+# Copyright © 2017 jianglin
+# File Name: views.py
+# Author: jianglin
+# Email: xiyang0807@gmail.com
+# Created: 2017-04-01 18:34:07 (CST)
+# Last Update:星期六 2017-4-1 20:48:15 (CST)
+#          By:
+# Description:
+# **************************************************************************
+from flask import render_template, request
+
+from forums.common.views import IsAuthMethodView as MethodView
+from forums.count import Count
+
+from .models import Message, MessageText
+
+
+class MessageListView(MethodView):
+    def get(self):
+        query_dict = request.data
+        user = request.user
+        status = query_dict.pop('status', '0')
+        page, number = self.page_info
+        messages = Message.query.filter_by(
+            receiver_id=user.id,
+            status=status).order_by('-created_at').paginate(page, number, True)
+        data = {'title': 'Notice', 'messages': messages}
+        Count.user_message_count(user.id, clear=True)
+        return render_template('forums/message.html', **data)

+ 12 - 0
forums/api/search/__init__.py

@@ -0,0 +1,12 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+# **************************************************************************
+# Copyright © 2017 jianglin
+# File Name: __init__.py
+# Author: jianglin
+# Email: xiyang0807@gmail.com
+# Created: 2017-03-31 17:25:57 (CST)
+# Last Update:星期五 2017-3-31 17:25:58 (CST)
+#          By:
+# Description:
+# **************************************************************************

+ 18 - 0
forums/api/search/urls.py

@@ -0,0 +1,18 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+# **************************************************************************
+# Copyright © 2017 jianglin
+# File Name: urls.py
+# Author: jianglin
+# Email: xiyang0807@gmail.com
+# Created: 2017-03-31 17:27:30 (CST)
+# Last Update:星期五 2017-3-31 17:28:36 (CST)
+#          By:
+# Description:
+# **************************************************************************
+from flask import Blueprint
+from .views import SearchView
+
+site = Blueprint('search', __name__)
+
+site.add_url_rule('/search', view_func=SearchView.as_view('search'))

+ 27 - 0
forums/api/search/views.py

@@ -0,0 +1,27 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+# **************************************************************************
+# Copyright © 2017 jianglin
+# File Name: views.py
+# Author: jianglin
+# Email: xiyang0807@gmail.com
+# Created: 2017-03-31 17:26:28 (CST)
+# Last Update:星期五 2017-3-31 17:48:23 (CST)
+#          By:
+# Description:
+# **************************************************************************
+from flask import request
+from forums.common.views import BaseMethodView as MethodView
+from forums.api.topic.models import Topic
+
+
+class SearchView(MethodView):
+    def get(self):
+        query_dict = request.data
+        search = query_dict.pop('key', None)
+        results = Topic.query.whoosh_search('第一').all()
+        print(results)
+        return ''
+
+    def post(self):
+        pass

+ 2 - 1
forums/api/topic/models.py

@@ -6,7 +6,7 @@
 # Author: jianglin
 # Author: jianglin
 # Email: xiyang0807@gmail.com
 # Email: xiyang0807@gmail.com
 # Created: 2016-12-15 20:52:07 (CST)
 # Created: 2016-12-15 20:52:07 (CST)
-# Last Update:星期四 2017-3-30 15:5:44 (CST)
+# Last Update:星期五 2017-3-31 17:30:1 (CST)
 #          By:
 #          By:
 # Description:
 # Description:
 # **************************************************************************
 # **************************************************************************
@@ -31,6 +31,7 @@ topic_follower = db.Table(
 
 
 class Topic(db.Model, ModelMixin):
 class Topic(db.Model, ModelMixin):
     __tablename__ = 'topics'
     __tablename__ = 'topics'
+    __searchable__ = ['title', 'content']
 
 
     CONTENT_TYPE_TEXT = '0'
     CONTENT_TYPE_TEXT = '0'
     CONTENT_TYPE_MARKDOWN = '1'
     CONTENT_TYPE_MARKDOWN = '1'

+ 5 - 1
forums/api/topic/views.py

@@ -6,7 +6,7 @@
 # Author: jianglin
 # Author: jianglin
 # Email: xiyang0807@gmail.com
 # Email: xiyang0807@gmail.com
 # Created: 2016-12-15 22:07:39 (CST)
 # Created: 2016-12-15 22:07:39 (CST)
-# Last Update:星期四 2017-3-30 16:39:56 (CST)
+# Last Update:星期六 2017-4-1 19:50:27 (CST)
 #          By:
 #          By:
 # Description:
 # Description:
 # **************************************************************************
 # **************************************************************************
@@ -31,6 +31,7 @@ from .models import Reply, Topic
 from .permissions import (like_permission, reply_list_permission,
 from .permissions import (like_permission, reply_list_permission,
                           reply_permission, topic_list_permission,
                           reply_permission, topic_list_permission,
                           topic_permission, edit_permission)
                           topic_permission, edit_permission)
+from forums.api.message.models import MessageClient
 
 
 
 
 class TopicAskView(IsConfirmedMethodView):
 class TopicAskView(IsConfirmedMethodView):
@@ -174,6 +175,8 @@ class ReplyListView(MethodView):
         reply = Reply(content=content, topic_id=topic.id)
         reply = Reply(content=content, topic_id=topic.id)
         reply.author = user
         reply.author = user
         reply.save()
         reply.save()
+        # notice
+        MessageClient.topic(reply)
         # count
         # count
         topic.board.post_count = 1
         topic.board.post_count = 1
         reply.author.reply_count = 1
         reply.author.reply_count = 1
@@ -208,6 +211,7 @@ class LikeView(MethodView):
         reply = Reply.query.filter_by(id=replyId).first_or_404()
         reply = Reply.query.filter_by(id=replyId).first_or_404()
         reply.likers.append(user)
         reply.likers.append(user)
         reply.save()
         reply.save()
+        MessageClient.like(reply)
         serializer = Serializer(reply, many=False)
         serializer = Serializer(reply, many=False)
         return HTTPResponse(
         return HTTPResponse(
             HTTPResponse.NORMAL_STATUS, data=serializer.data).to_response()
             HTTPResponse.NORMAL_STATUS, data=serializer.data).to_response()

+ 6 - 3
forums/api/urls.py

@@ -6,7 +6,7 @@
 # Author: jianglin
 # Author: jianglin
 # Email: xiyang0807@gmail.com
 # Email: xiyang0807@gmail.com
 # Created: 2017-01-25 20:12:58 (CST)
 # Created: 2017-01-25 20:12:58 (CST)
-# Last Update:星期二 2017-3-28 17:40:36 (CST)
+# Last Update:星期六 2017-4-1 18:45:19 (CST)
 #          By:
 #          By:
 # Description:
 # Description:
 # **************************************************************************
 # **************************************************************************
@@ -19,8 +19,10 @@ from .setting.urls import site as setting_site
 from .follow.urls import site as follow_site
 from .follow.urls import site as follow_site
 from .upload.urls import site as upload_site
 from .upload.urls import site as upload_site
 from .collect.urls import site as collect_site
 from .collect.urls import site as collect_site
+from .message.urls import site as message_site
+
+# from .search.urls import site as search_site
 # from .permission.urls import site as perm_site
 # from .permission.urls import site as perm_site
-# from .mine.urls import site as mine_site
 
 
 
 
 def api_routers(app):
 def api_routers(app):
@@ -33,5 +35,6 @@ def api_routers(app):
     app.register_blueprint(follow_site)
     app.register_blueprint(follow_site)
     app.register_blueprint(upload_site)
     app.register_blueprint(upload_site)
     app.register_blueprint(collect_site)
     app.register_blueprint(collect_site)
+    app.register_blueprint(message_site)
+    # app.register_blueprint(search_site)
     # app.register_blueprint(perm_site)
     # app.register_blueprint(perm_site)
-    # app.register_blueprint(mine_site)

+ 10 - 1
forums/api/user/models.py

@@ -6,7 +6,7 @@
 # Author: jianglin
 # Author: jianglin
 # Email: xiyang0807@gmail.com
 # Email: xiyang0807@gmail.com
 # Created: 2016-12-15 21:09:08 (CST)
 # Created: 2016-12-15 21:09:08 (CST)
-# Last Update:星期四 2017-3-30 15:10:19 (CST)
+# Last Update:星期六 2017-4-1 20:28:26 (CST)
 #          By:
 #          By:
 # Description:
 # Description:
 # **************************************************************************
 # **************************************************************************
@@ -88,6 +88,15 @@ class User(db.Model, UserMixin, ModelMixin):
     def reply_count(self, value):
     def reply_count(self, value):
         return Count.user_reply_count(self.id, value)
         return Count.user_reply_count(self.id, value)
 
 
+    @property
+    def message_count(self):
+        # return self.receive_messages.filter_by(status='0').count()
+        return Count.user_message_count(self.id)
+
+    @message_count.setter
+    def message_count(self, value):
+        return Count.user_message_count(self.id, value)
+
     def __str__(self):
     def __str__(self):
         return self.username
         return self.username
 
 

+ 2 - 2
forums/common/response.py

@@ -6,7 +6,7 @@
 # Author: jianglin
 # Author: jianglin
 # Email: xiyang0807@gmail.com
 # Email: xiyang0807@gmail.com
 # Created: 2016-10-25 21:07:00 (CST)
 # Created: 2016-10-25 21:07:00 (CST)
-# Last Update:星期三 2017-1-25 21:43:35 (CST)
+# Last Update:星期六 2017-4-1 18:51:49 (CST)
 #          By:
 #          By:
 # Description:
 # Description:
 # **************************************************************************
 # **************************************************************************
@@ -65,7 +65,7 @@ class HTTPResponse(object):
             'description': self.description,
             'description': self.description,
         }
         }
         if self.pageinfo is not None:
         if self.pageinfo is not None:
-            response.update(pageinfo=self.pageinfo)
+            response.update(pageinfo=self.pageinfo.as_dict())
         return response
         return response
 
 
     def to_response(self):
     def to_response(self):

+ 12 - 1
forums/count.py

@@ -6,7 +6,7 @@
 # Author: jianglin
 # Author: jianglin
 # Email: xiyang0807@gmail.com
 # Email: xiyang0807@gmail.com
 # Created: 2017-03-29 21:28:52 (CST)
 # Created: 2017-03-29 21:28:52 (CST)
-# Last Update:星期四 2017-3-30 14:59:51 (CST)
+# Last Update:星期六 2017-4-1 20:47:11 (CST)
 #          By:
 #          By:
 # Description: 一些统计信息
 # Description: 一些统计信息
 # **************************************************************************
 # **************************************************************************
@@ -76,3 +76,14 @@ class Count(object):
             pipe.hincrby(key, 'replies', value)
             pipe.hincrby(key, 'replies', value)
             pipe.execute()
             pipe.execute()
         return redis_data.hget(key, 'replies') or 0
         return redis_data.hget(key, 'replies') or 0
+
+    @classmethod
+    def user_message_count(cls, userId, value=None, clear=False):
+        key = 'count:user:%s' % str(userId)
+        if value is not None:
+            pipe = redis_data.pipeline()
+            pipe.hincrby(key, 'message', value)
+            pipe.execute()
+        if clear:
+            redis_data.hset(key, 'message', 0)
+        return redis_data.hget(key, 'message') or 0

+ 3 - 2
forums/filters.py

@@ -6,7 +6,7 @@
 # Author: jianglin
 # Author: jianglin
 # Email: xiyang0807@gmail.com
 # Email: xiyang0807@gmail.com
 # Created: 2016-11-07 21:00:32 (CST)
 # Created: 2016-11-07 21:00:32 (CST)
-# Last Update:星期四 2017-3-30 15:10:35 (CST)
+# Last Update:星期六 2017-4-1 20:16:51 (CST)
 #          By:
 #          By:
 # Description:
 # Description:
 # **************************************************************************
 # **************************************************************************
@@ -21,7 +21,7 @@ from misaka import HtmlRenderer, Markdown
 
 
 
 
 def safe_clean(text):
 def safe_clean(text):
-    tags = ['b', 'i', 'font', 'br', 'blockquote', 'div', 'h2', 'a']
+    tags = ['b', 'i', 'font', 'br', 'blockquote', 'div', 'h2', 'a', 'p']
     attrs = {'*': ['style', 'id', 'class'], 'font': ['color'], 'a': ['href']}
     attrs = {'*': ['style', 'id', 'class'], 'font': ['color'], 'a': ['href']}
     styles = ['color']
     styles = ['color']
     return Markup(clean(text, tags=tags, attributes=attrs, styles=styles))
     return Markup(clean(text, tags=tags, attributes=attrs, styles=styles))
@@ -68,6 +68,7 @@ def show_time():
     else:
     else:
         return 'UTC:' + format_datetime(datetime.utcnow())
         return 'UTC:' + format_datetime(datetime.utcnow())
 
 
+
 def hot_tags():
 def hot_tags():
     from forums.api.tag.models import Tags
     from forums.api.tag.models import Tags
     tags = Tags.query.limit(9).all()
     tags = Tags.query.limit(9).all()

+ 2 - 2
manager.py

@@ -6,7 +6,7 @@
 # Author: jianglin
 # Author: jianglin
 # Email: xiyang0807@gmail.com
 # Email: xiyang0807@gmail.com
 # Created: 2016-10-25 22:08:39 (CST)
 # Created: 2016-10-25 22:08:39 (CST)
-# Last Update:星期三 2017-3-29 23:38:31 (CST)
+# Last Update:星期六 2017-4-1 18:47:53 (CST)
 #          By:
 #          By:
 # Description:
 # Description:
 # **************************************************************************
 # **************************************************************************
@@ -35,7 +35,7 @@ def init_db():
     """
     """
     Drops and re-creates the SQL schema
     Drops and re-creates the SQL schema
     """
     """
-    db.drop_all()
+    # db.drop_all()
     db.configure_mappers()
     db.configure_mappers()
     db.create_all()
     db.create_all()
     db.session.commit()
     db.session.commit()

+ 1 - 1
static/assets/home.js

@@ -21,7 +21,7 @@ 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')
 {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
 {obj.text('取消关注').addClass('active');}else
 {alert('fail');}}});}}
 {alert('fail');}}});}}
-$(document).ready(function(){$('button.topic-following').click(function(){var _$this=$(this);var url="/user/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="/user/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="/user/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="/user/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({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')
 {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;}}});});$('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 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')
 {_$this.parent().remove();}}});});});}
 {_$this.parent().remove();}}});});});}

+ 4 - 4
static/styles/following.js

@@ -29,7 +29,7 @@ function Follow(obj,data,url){
 $(document).ready(function(){
 $(document).ready(function(){
   $('button.topic-following').click(function(){
   $('button.topic-following').click(function(){
     var _$this = $(this);
     var _$this = $(this);
-    var url = "/user/following/topics";
+    var url = "/following/topics";
     var data = JSON.stringify({
     var data = JSON.stringify({
       topicId:_$this.attr("data-id"),
       topicId:_$this.attr("data-id"),
     });
     });
@@ -37,7 +37,7 @@ $(document).ready(function(){
   });
   });
   $('button.tag-following').click(function(){
   $('button.tag-following').click(function(){
     var _$this = $(this);
     var _$this = $(this);
-    var url = "/user/following/tags";
+    var url = "/following/tags";
     var data = JSON.stringify({
     var data = JSON.stringify({
       tagId:_$this.attr("data-id"),
       tagId:_$this.attr("data-id"),
     });
     });
@@ -45,7 +45,7 @@ $(document).ready(function(){
   });
   });
   $('button.user-following').click(function(){
   $('button.user-following').click(function(){
     var _$this = $(this);
     var _$this = $(this);
-    var url = "/user/following/users";
+    var url = "/following/users";
     var data = JSON.stringify({
     var data = JSON.stringify({
       userId:_$this.attr("data-id"),
       userId:_$this.attr("data-id"),
     });
     });
@@ -53,7 +53,7 @@ $(document).ready(function(){
   });
   });
   $('button.collect-following').click(function(){
   $('button.collect-following').click(function(){
     var _$this = $(this);
     var _$this = $(this);
-    var url = "/user/following/collects";
+    var url = "/following/collects";
     var data = JSON.stringify({
     var data = JSON.stringify({
       collectId:_$this.attr("data-id"),
       collectId:_$this.attr("data-id"),
     });
     });

+ 48 - 34
templates/base/base.html

@@ -4,57 +4,71 @@
 {% import 'base/link.html' as link %}
 {% import 'base/link.html' as link %}
 {% import 'base/panel.html' as panel_base %}
 {% import 'base/panel.html' as panel_base %}
 {% from 'base/head.html' import breadcrumb %}
 {% from 'base/head.html' import breadcrumb %}
+
+{% block title -%}
+  {{ title }} {{ SITE['title'] }} - {{ _(SITE['description']) }}
+{%- endblock title %}
+
 {% block script -%}
 {% block script -%}
-{{ super() }}
+  {{ super() }}
 {%- endblock script %}
 {%- endblock script %}
 
 
 {% block style -%}
 {% block style -%}
-{{ super() }}
-<link href="http://cdn.bootcss.com/font-awesome/4.7.0/css/font-awesome.min.css" rel="stylesheet">
+  {{ super() }}
+  <link href="http://cdn.bootcss.com/font-awesome/4.7.0/css/font-awesome.min.css" rel="stylesheet">
 {%- endblock style %}
 {%- endblock style %}
 
 
 {% block main %}
 {% block main %}
-{% include "base/header.html" %}
-<div class="col-md-offset-1 col-md-10" style="padding:0;margin-top:60px">
+  {% include "base/header.html" %}
+  <div class="col-md-offset-1 col-md-10" style="padding:0;margin-top:60px">
     {% with messages = get_flashed_messages(with_categories=true) %}
     {% with messages = get_flashed_messages(with_categories=true) %}
-    {% if messages %}
-    {% for category,message in messages %}
-    {% if category == 'message' -%}
-    {% set category = 'info' %}
-    {%- endif %}
-    <div class="alert alert-{{ category }}" style="padding:8px">
-        <button type="button" class="close" data-dismiss="alert" aria-label="Close">
-            <span aria-hidden="true">&times;</span>
-        </button>
-        <ul>
-            <li>{{ message }} </li>
-        </ul>
-    </div>
-    {% endfor %}
-    {% endif %}
+      {% if messages %}
+        {% for category,message in messages %}
+          {% if category == 'message' -%}
+            {% set category = 'info' %}
+          {%- endif %}
+          <div class="alert alert-{{ category }}" style="padding:8px">
+            <button type="button" class="close" data-dismiss="alert" aria-label="Close">
+              <span aria-hidden="true">&times;</span>
+            </button>
+            <ul>
+              <li>{{ message }} </li>
+            </ul>
+          </div>
+        {% endfor %}
+      {% endif %}
     {% endwith %}
     {% endwith %}
     {{ dropdown() }}
     {{ dropdown() }}
     {% block content %}{% endblock %}
     {% block content %}{% endblock %}
-</div>
+  </div>
 {% endblock %}
 {% endblock %}
 
 
 {% macro dropdown() -%}
 {% macro dropdown() -%}
-{% if g.user.is_authenticated %}
-<div class="btn-group pull-right">
-    <button type="button" class="btn btn-primary btn-sm dropdown-toggle" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
+  {% if g.user.is_authenticated %}
+    <div class="btn-group pull-right">
+      <button type="button" class="btn btn-primary btn-sm dropdown-toggle" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
         {{ g.user.username }} <span class="caret"></span>
         {{ g.user.username }} <span class="caret"></span>
-    </button>
-    <ul class="dropdown-menu">
+      </button>
+      <ul class="dropdown-menu">
         <li><a href="{{ url_for('user.user',username=g.user.username) }}">{{ _('Home Page') }}</a></li>
         <li><a href="{{ url_for('user.user',username=g.user.username) }}">{{ _('Home Page') }}</a></li>
         <li><a href="{{ url_for('setting.setting') }}">{{ _('Setting')}}</a></li>
         <li><a href="{{ url_for('setting.setting') }}">{{ _('Setting')}}</a></li>
         <li role="separator" class="divider"></li>
         <li role="separator" class="divider"></li>
         <li><a href="{{ url_for('auth.logout') }}">{{ _('Logout')}}</a></li>
         <li><a href="{{ url_for('auth.logout') }}">{{ _('Logout')}}</a></li>
-    </ul>
-</div>
-{% else  %}
-<a href="{{ url_for('auth.register') }}" class="btn btn-sm btn-primary pull-right">{{ _('Register') }}</a>
-<a href="{{ url_for('auth.login') }}" class="btn btn-sm btn-primary pull-right">{{ _('Login') }}</a>
-{% endif %}
-<a href="{{ url_for('tag.list') }}" class="btn btn-sm btn-primary pull-right">{{ _('TagList') }}</a>
-<a href="{{ url_for('user.list') }}" class="btn btn-sm btn-primary pull-right">{{ _('UserList') }}</a>
+      </ul>
+    </div>
+    <a href="{{ url_for('message.list') }}" class="btn btn-sm btn-primary pull-right">
+      {{ _('NoticeList') }}
+      {%- set n = current_user.message_count -%}
+      {%- if n and n != '0' -%}
+        <span class="badge" style="padding:2px 5px;">
+          {{ n }}
+        </span>
+      {%- endif -%}
+    </a>
+  {% else  %}
+    <a href="{{ url_for('auth.register') }}" class="btn btn-sm btn-primary pull-right">{{ _('Register') }}</a>
+    <a href="{{ url_for('auth.login') }}" class="btn btn-sm btn-primary pull-right">{{ _('Login') }}</a>
+  {% endif %}
+  <a href="{{ url_for('tag.list') }}" class="btn btn-sm btn-primary pull-right">{{ _('TagList') }}</a>
+  <a href="{{ url_for('user.list') }}" class="btn btn-sm btn-primary pull-right">{{ _('UserList') }}</a>
 {%- endmacro %}
 {%- endmacro %}

+ 35 - 0
templates/forums/message.html

@@ -0,0 +1,35 @@
+{% extends 'base/base.html' %}
+{% block content %}
+  {{ breadcrumb(active=_('Notices'))}}
+  <div class="row">
+    <div class="col-md-9">
+      <div class="panel panel-default">
+        <div class="panel-heading">
+          <button class="pull-right btn btn-sm btn-default ingore-all" style="padding:0 5px">{{ _('mark all to is read')}}</button>
+          {{ _('Notices') }}
+        </div>
+        {% if messages.items %}
+          {% for message in messages.items %}
+            <div class="panel-body" style="border-bottom:1px solid #eee;">
+              <small class="pull-right"> {{ message.created_at | timesince }} </small>
+              <small>{{ message.title }}</small>
+              <p style="margin-bottom:0px">
+                {{ message.content }}
+              </p>
+            </div>
+          {% endfor %}
+          {{ p_footer(messages, 'message.list')}}
+        {% else %}
+          <div class="panel-body">
+            <span class="text-center" style="display:block;width:100%;color:#999">
+              {{ _('No Notices')}}
+            </span>
+          </div>
+        {% endif %}
+      </div>
+    </div>
+    <div class="col-md-3" style="padding-left:0">
+      {{ panel_base.index() }}
+    </div>
+  </div>
+{% endblock %}

+ 0 - 32
templates/forums/notice.html

@@ -1,32 +0,0 @@
-{% extends 'base/base.html' %}
-{% block content %}
-{{ breadcrumb(active=_('Notices'))}}
-<div class="row">
-    <div class="col-md-9">
-        <div class="panel panel-default">
-            <div class="panel-heading">
-                <button class="pull-right btn btn-sm btn-default ingore-all" style="padding:0 5px">{{ _('mark all to is read')}}</button>
-                {{ _('Notices') }}
-            </div>
-            {% if notices.items %}
-            {% for notice in notices.items %}
-            <div class="panel-body" style="border-bottom:1px solid #eee;">
-                {% import 'base/notice.html' as notice_base %}
-                {{ notice_base[notice.category](notice) }}
-            </div>
-            {% endfor %}
-            {{ p_footer(notices, 'forums.notice')}}
-            {% else %}
-            <div class="panel-body">
-                <span class="text-center" style="display:block;width:100%;color:#999">
-                    {{ _('No Notices')}}
-                </span>
-            </div>
-            {% endif %}
-        </div>
-    </div>
-    <div class="col-md-3" style="padding-left:0">
-        {{ panel_base.index() }}
-    </div>
-</div>
-{% endblock %}

+ 26 - 26
templates/tag/_macro.html

@@ -1,30 +1,30 @@
 {% macro title(tag) -%}
 {% macro title(tag) -%}
-<div class="media">
-  <div class="media-left">
-    <a href="{{ request.path }}">
-      <img class="media-object img-circle" src="{{ url_for('avatar',text=tag.name)}}" alt="avatar" style="width:56px;height:56px">
-    </a>
-  </div>
-  <div class="media-body">
-    <h4 class="media-heading"><strong class="text-capitalize">{{ tag.name }}</strong></h4>
-    {% set description = tag.description %}
-    {% if description -%}
-    {{ description }}
-    {%- endif %}
-  </div>
-  <div class="media-right">
-    <span class="rss">
-      <a href="{{ url_for('tag.feed',name=tag.name)}}">
-        <i class="icon-rss" style="padding:2px;white-space:nowrap;">Rss</i>
+  <div class="media">
+    <div class="media-left">
+      <a href="{{ request.path }}">
+        <img class="media-object img-circle" src="{{ url_for('avatar',text=tag.name)}}" alt="avatar" style="width:56px;height:56px">
       </a>
       </a>
-    </span>
-    {% if g.user.is_authenticated %}
-    {% if tag.is_followed() %}
-    <button class="btn btn-sm btn-default tag-following active" data-id="{{ tag.id}}" style="padding:0 5px">取消关注</button>
-    {% else %}
-    <button class="btn btn-sm btn-default tag-following" data-id="{{ tag.id}}" style="padding:0 5px">关注</button>
-    {% endif %}
-    {% endif %}
+    </div>
+    <div class="media-body">
+      <h4 class="media-heading"><strong class="text-capitalize">{{ tag.name }}</strong></h4>
+      {% set description = tag.description %}
+      {% if description -%}
+        {{ description }}
+      {%- endif %}
+    </div>
+    <div class="media-right">
+      <span class="rss">
+        <a href="{{ url_for('tag.feed',name=tag.name)}}">
+          <i class="icon-rss" style="padding:2px;white-space:nowrap;">Rss</i>
+        </a>
+      </span>
+      {% if g.user.is_authenticated %}
+        {% if tag.is_followed() %}
+          <button class="btn btn-sm btn-default tag-following active" data-id="{{ tag.id}}" style="padding:0 5px">取消关注</button>
+        {% else %}
+          <button class="btn btn-sm btn-default tag-following" data-id="{{ tag.id}}" style="padding:0 5px">关注</button>
+        {% endif %}
+      {% endif %}
+    </div>
   </div>
   </div>
-</div>
 {%- endmacro %}
 {%- endmacro %}

+ 14 - 14
templates/tag/tag.html

@@ -1,20 +1,20 @@
 {% extends 'base/base.html' %}
 {% extends 'base/base.html' %}
 {% block content %}
 {% block content %}
-{% from 'tag/_macro.html' import title %}
-{{ breadcrumb(hrefs={_('All Tags'):url_for('tag.list')},active=tag.name)}}
-<div class="row">
-  <div class="col-md-9">
-    <div class="panel panel-default">
-      <div class="panel-body" style="border-bottom: 1px solid #ddd;">
-        {{ title(tag) }}
+  {% from 'tag/_macro.html' import title %}
+  {{ breadcrumb(hrefs={_('All Tags'):url_for('tag.list')},active=tag.name)}}
+  <div class="row">
+    <div class="col-md-9">
+      <div class="panel panel-default">
+        <div class="panel-body" style="border-bottom: 1px solid #ddd;">
+          {{ title(tag) }}
+        </div>
+        {% include "topic/_topic.html" %}
+        {{ p_footer(topics,'tag.tag',dict(name=tag.name))}}
       </div>
       </div>
-      {% include "topic/_topic.html" %}
-      {{ p_footer(topics,'tag.tag',dict(name=tag.name))}}
+    </div>
+    <div class="col-md-3" style="padding-left:0">
+      {% from 'tag/panel.html' import tag as tag_panel %}
+      {{ tag_panel(tag) }}
     </div>
     </div>
   </div>
   </div>
-  <div class="col-md-3" style="padding-left:0">
-    {% from 'tag/panel.html' import tag as tag_panel %}
-    {{ tag_panel(tag) }}
-  </div>
-</div>
 {% endblock %}
 {% endblock %}

+ 17 - 17
templates/tag/tag_list.html

@@ -1,25 +1,25 @@
 {% extends 'base/base.html' %}
 {% extends 'base/base.html' %}
 {% block content %}
 {% block content %}
-{{ breadcrumb(active=_('All Tags'))}}
-<div class="row">
+  {{ breadcrumb(active=_('All Tags'))}}
+  <div class="row">
     <div class="col-md-9">
     <div class="col-md-9">
-        <div class="panel panel-primary">
-            <div class="panel-heading">
-                {{ _('All Tags') }}
-            </div>
-            <div class="panel-body">
-                {% for tag in tags.items %}
-                <a class="tag" href="{{ url_for('tag.tag',name=tag.name)}}">{{ tag.name }}</a>
-                {% else %}
-                <span class="text-center">
-                    {{ _('No Tags') }}
-                </span>
-                {% endfor %}
-            </div>
+      <div class="panel panel-primary">
+        <div class="panel-heading">
+          {{ _('All Tags') }}
         </div>
         </div>
+        <div class="panel-body">
+          {% for tag in tags.items %}
+            <a class="tag" href="{{ url_for('tag.tag',name=tag.name)}}">{{ tag.name }}</a>
+          {% else %}
+            <span class="text-center">
+              {{ _('No Tags') }}
+            </span>
+          {% endfor %}
+        </div>
+      </div>
     </div>
     </div>
     <div class="col-md-3" style="padding-left:0">
     <div class="col-md-3" style="padding-left:0">
-        {{ panel_base.tag_list() }}
+      {{ panel_base.tag_list() }}
     </div>
     </div>
-</div>
+  </div>
 {% endblock %}
 {% endblock %}