Browse Source

用户关注用户,增加私信功能,实现部分消息通知

消息通知 content::json,增加is_read字段

notice: reply,user,collect,like
honmaple 9 years ago
parent
commit
c70b6276be

+ 5 - 3
maple/__init__.py

@@ -6,7 +6,7 @@
 # Author: jianglin
 # Email: xiyang0807@gmail.com
 # Created: 2016-05-20 12:35:52 (CST)
-# Last Update:星期一 2016-6-27 15:0:21 (CST)
+# Last Update:星期三 2016-6-29 15:22:56 (CST)
 #          By:jianglin
 # Description:
 # **************************************************************************
@@ -61,8 +61,10 @@ def register_routes(app):
     app.register_blueprint(site, url_prefix='/t')
     from maple.docs.views import site
     app.register_blueprint(site, subdomain='docs')
-    import maple.auth.views
-    import maple.admin.admin
+    # import maple.auth.views
+    from maple.auth import views
+    from maple.admin import admin
+    # import maple.admin.admin
 
 
 app = create_app()

+ 3 - 2
maple/extensions.py

@@ -6,7 +6,7 @@
 # Author: jianglin
 # Email: xiyang0807@gmail.com
 # Created: 2016-05-20 13:02:50 (CST)
-# Last Update:星期一 2016-6-27 17:17:11 (CST)
+# Last Update:星期四 2016-6-30 20:54:16 (CST)
 #          By:
 # Description:
 # **************************************************************************
@@ -67,7 +67,7 @@ def register_babel(app):
 def register_maple(app):
     Bootstrap(app,
               css=('styles/monokai.css', 'styles/mine.css'),
-              js=('styles/upload.js', 'styles/order.js', 'styles/mine.js',
+              js=('styles/upload.js', 'styles/forums.js', 'styles/mine.js',
                   'styles/topic.js'),
               use_auth=True)
     Captcha(app)
@@ -130,3 +130,4 @@ def register_jinja2(app):
     app.jinja_env.filters['markdown'] = Filters.safe_markdown
     app.jinja_env.filters['safe_clean'] = safe_clean
     app.jinja_env.filters['is_collected'] = Filters.is_collected
+    app.jinja_env.filters['notice_count'] = Filters.notice_count

+ 6 - 1
maple/filters.py

@@ -6,7 +6,7 @@
 # Author: jianglin
 # Email: xiyang0807@gmail.com
 # Created: 2016-06-15 00:39:29 (CST)
-# Last Update:星期一 2016-6-27 12:33:39 (CST)
+# Last Update:星期四 2016-6-30 20:53:41 (CST)
 #          By:
 # Description:
 # **************************************************************************
@@ -100,6 +100,11 @@ class Filters(object):
                 return True
         return False
 
+    def notice_count(uid):
+        from maple.forums.models import Notice
+        count = Notice.query.filter_by(rece_id=uid, is_read=False).count()
+        return count
+
     class Title(object):
         title = setting['title']
         picture = setting['picture']

+ 67 - 0
maple/forums/controls.py

@@ -0,0 +1,67 @@
+#!/usr/bin/env python
+# -*- coding=UTF-8 -*-
+# **************************************************************************
+# Copyright © 2016 jianglin
+# File Name: controls.py
+# Author: jianglin
+# Email: xiyang0807@gmail.com
+# Created: 2016-06-30 19:39:13 (CST)
+# Last Update:星期四 2016-6-30 20:34:48 (CST)
+#          By:
+# Description:
+# **************************************************************************
+from flask import url_for
+from flask_login import current_user
+from .models import db
+from .models import Notice
+
+
+def reply(topic, reply):
+    url = url_for('topic.topic',
+                  uid=topic.uid,
+                  _anchor='reply-' + str(reply.id))
+    notice = Notice()
+    notice.category = 'reply'
+    notice.content = {'url': url,
+                      'content': reply.content[:100],
+                      'title': topic.title}
+    notice.rece_id = topic.author_id
+    notice.send_user = current_user
+    db.session.add(notice)
+    db.session.commit()
+
+
+def collect(topic):
+    url = url_for('topic.topic', uid=topic.uid)
+    notice = Notice()
+    notice.category = 'collect'
+    notice.content = {'url': url, 'title': topic.title}
+    notice.rece_id = topic.author_id
+    notice.send_user = current_user
+    db.session.add(notice)
+    db.session.commit()
+
+
+def like(reply):
+    topic = reply.topic
+    url = url_for('topic.topic',
+                  uid=topic.uid,
+                  _anchor='reply-' + str(reply.id))
+    notice = Notice()
+    notice.category = 'like'
+    notice.content = {'url': url,
+                      'title': topic.title,
+                      'content': reply.content[:100]}
+    notice.rece_id = reply.author_id
+    notice.send_user = current_user
+    db.session.add(notice)
+    db.session.commit()
+
+
+def user(userId):
+    notice = Notice()
+    notice.category = 'user'
+    notice.rece_id = userId
+    notice.send_user = current_user
+    db.session.add(notice)
+    db.session.commit()

+ 6 - 2
maple/forums/forms.py

@@ -6,12 +6,12 @@
 # Author: jianglin
 # Email: xiyang0807@gmail.com
 # Created: 2016-06-03 19:27:58 (CST)
-# Last Update:星期一 2016-6-27 14:59:44 (CST)
+# Last Update:星期二 2016-6-28 21:52:3 (CST)
 #          By:
 # Description:
 # **************************************************************************
 from flask_wtf import Form
-from wtforms import SelectField, StringField
+from wtforms import SelectField, StringField, TextAreaField
 from wtforms.validators import DataRequired
 from flask_babel import lazy_gettext as _
 
@@ -32,3 +32,7 @@ class SortForm(Form):
 
 class SearchForm(Form):
     search = StringField(_('search'), validators=[DataRequired()])
+
+
+class MessageForm(Form):
+    message = TextAreaField(_('message'), validators=[DataRequired()])

+ 8 - 12
maple/forums/models.py

@@ -6,12 +6,15 @@
 # Author: jianglin
 # Email: xiyang0807@gmail.com
 # Created: 2016-05-20 13:24:19 (CST)
-# Last Update:星期二 2016-6-28 1:4:23 (CST)
+# Last Update:星期四 2016-6-30 21:28:54 (CST)
 #          By:
 # Description:
 # **************************************************************************
 from maple import db
 from datetime import datetime
+from sqlalchemy.dialects.postgresql import JSON
+
+# from sqlalchemy.types import JSON
 
 
 class Board(db.Model):
@@ -76,26 +79,19 @@ class Notice(db.Model):
     id = db.Column(db.Integer, primary_key=True)
     publish = db.Column(db.DateTime, default=datetime.now())
     category = db.Column(db.String(81), nullable=False)
-    content = db.Column(db.Text)
+    content = db.Column(JSON)
+    is_read = db.Column(db.Boolean, default=False)
 
-    rece_id = db.Column(db.Integer,
-                        db.ForeignKey('users.id',
-                                      ondelete="CASCADE"))
+    rece_id = db.Column(db.Integer, db.ForeignKey('users.id'))
     rece_user = db.relationship("User",
                                 backref="rece_user",
                                 foreign_keys='Notice.rece_id',
-                                cascade='all,delete-orphan',
-                                single_parent=True,
                                 uselist=False)
 
-    send_id = db.Column(db.Integer,
-                        db.ForeignKey('users.id',
-                                      ondelete="CASCADE"))
+    send_id = db.Column(db.Integer, db.ForeignKey('users.id'))
     send_user = db.relationship("User",
                                 backref="send_user",
                                 foreign_keys='Notice.send_id',
-                                cascade='all,delete-orphan',
-                                single_parent=True,
                                 uselist=False)
 
     def __repr__(self):

+ 33 - 8
maple/forums/views.py

@@ -6,17 +6,20 @@
 # Author: jianglin
 # Email: xiyang0807@gmail.com
 # Created: 2016-05-20 13:18:19 (CST)
-# Last Update:星期六 2016-6-25 18:4:14 (CST)
+# Last Update:星期四 2016-6-30 20:32:38 (CST)
 #          By:
 # Description:
 # **************************************************************************
-from flask import Blueprint, render_template, g, request, abort
+from flask import (Blueprint, render_template, g, request, abort, redirect,
+                   flash, url_for)
 from flask_login import current_user, login_required
+from flask_maple.forms import flash_errors
 from maple import app, db
 from maple.helpers import is_num
 from maple.user.models import User
 from maple.forums.models import Notice, Board
 from maple.topic.models import Topic
+from .forms import MessageForm
 
 site = Blueprint('forums', __name__)
 
@@ -43,15 +46,16 @@ def forums():
     return render_template('forums/forums.html', **data)
 
 
-@site.route('/notices', defaults={'page': 1})
-@site.route('/notices/?page=<int:page>')
+@site.route('/notices')
 @login_required
-def notice(page):
-    notices = Notice.query.join(Notice.rece_user).filter(
-        User.username == current_user.username).paginate(
+def notice():
+    page = is_num(request.args.get('page'))
+    notices = Notice.query.filter_by(
+        rece_id=current_user.id).order_by(Notice.publish.desc()).paginate(
             page, app.config['PER_PAGE'],
             error_out=True)
-    return render_template('forums/notice.html', notices=notices)
+    data = {'notices': notices}
+    return render_template('forums/notice.html', **data)
 
 
 @site.route('/userlist')
@@ -63,6 +67,27 @@ def userlist():
     return render_template('forums/userlist.html', **data)
 
 
+@site.route('/messages/<int:receId>', methods=['POST'])
+@login_required
+def message(receId):
+    form = MessageForm()
+    rece_user = User.query.filter_by(id=receId).first_or_404()
+    if form.validate_on_submit() and request.method == "POST":
+        message = Notice()
+        message.category = 'privacy'
+        message.content = form.message.data
+        message.rece_user = rece_user
+        message.send_id = current_user.id
+        db.session.add(message)
+        db.session.commit()
+        flash('成功发送', category='success')
+        return redirect(url_for('user.user', user_url=rece_user.username))
+    else:
+        if form.errors:
+            flash_errors(form)
+    return redirect(url_for('user.user', user_url=rece_user.username))
+
+
 @site.route('/about')
 def about():
     return render_template('forums/about.html')

+ 33 - 2
maple/mine/controls.py

@@ -6,14 +6,40 @@
 # Author: jianglin
 # Email: xiyang0807@gmail.com
 # Created: 2016-06-15 09:44:01 (CST)
-# Last Update:星期三 2016-6-15 13:11:34 (CST)
+# Last Update:星期四 2016-6-30 20:43:59 (CST)
 #          By:
 # Description:
 # **************************************************************************
+from flask import flash
 from flask_login import current_user
 from maple import db
 from maple.topic.models import Collect, Topic, Tags, Reply
 from maple.user.models import User
+from maple.forums.controls import collect as notice_collect
+from maple.forums.controls import like as notice_like
+from maple.forums.controls import user as notice_user
+
+
+class CollectDetail(object):
+    def post(form, topicId):
+        topic = Topic.query.filter_by(uid=topicId).first_or_404()
+        for id in form:
+            collect = Collect.query.filter_by(id=id).first_or_404()
+            if topic in collect.topics:
+                flash('This topic has been collected in %s' % collect.name,
+                      'warning')
+            else:
+                collect.topics.append(topic)
+                db.session.commit()
+                if topic.author_id != current_user.id:
+                    notice_collect(topic)
+        return topic
+
+    def delete(topicId, collectId):
+        topic = Topic.query.filter_by(uid=topicId).first_or_404()
+        collect = Collect.query.filter_by(id=collectId).first_or_404()
+        collect.topics.remove(topic)
+        db.session.commit()
 
 
 class CollectModel(object):
@@ -54,6 +80,7 @@ class FollowModel(object):
             user = User.query.filter_by(id=id).first()
             current_user.following_users.append(user)
             db.session.commit()
+            notice_user(user.id)
         elif type == 'collect':
             collect = Collect.query.filter_by(id=id).first()
             current_user.following_collects.append(collect)
@@ -69,7 +96,9 @@ class FollowModel(object):
             current_user.following_topics.remove(topic)
             db.session.commit()
         elif type == 'user':
-            pass
+            user = User.query.filter_by(id=id).first()
+            current_user.following_users.remove(user)
+            db.session.commit()
         elif type == 'collect':
             collect = Collect.query.filter_by(id=id).first()
             current_user.following_collects.remove(collect)
@@ -81,6 +110,8 @@ class LikeModel(object):
         reply = Reply.query.filter_by(id=uid).first_or_404()
         current_user.likes.append(reply)
         db.session.commit()
+        if reply.author_id != current_user.id:
+            notice_like(reply)
 
     def delete_data(uid):
         reply = Reply.query.filter_by(id=uid).first_or_404()

+ 4 - 15
maple/mine/views.py

@@ -6,7 +6,7 @@
 # Author: jianglin
 # Email: xiyang0807@gmail.com
 # Created: 2016-05-20 18:04:43 (CST)
-# Last Update:星期一 2016-6-27 12:52:4 (CST)
+# Last Update:星期四 2016-6-30 20:0:46 (CST)
 #          By:
 # Description:
 # **************************************************************************
@@ -22,7 +22,7 @@ from maple.main.permission import (follow_permission, collect_permission,
 from maple.helpers import is_num
 from maple.topic.models import Topic, Collect
 from maple.mine.forms import CollectForm
-from .controls import CollectModel, FollowModel, LikeModel
+from .controls import CollectModel, FollowModel, LikeModel, CollectDetail
 
 site = Blueprint('mine', __name__)
 
@@ -95,15 +95,7 @@ def collect_following():
 def add_collect():
     form = request.form.getlist('add-to-collect')
     topicId = request.args.get('topicId')
-    topic = Topic.query.filter_by(uid=topicId).first_or_404()
-    for id in form:
-        collect = Collect.query.filter_by(id=id).first_or_404()
-        if topic in collect.topics:
-            flash('This topic has been collected in %s' % collect.name,
-                  'warning')
-        else:
-            collect.topics.append(topic)
-            db.session.commit()
+    topic = CollectDetail.post(form, topicId)
     return redirect(url_for('topic.topic', uid=topic.uid))
 
 
@@ -113,10 +105,7 @@ def delete_collect():
     data = request.get_json()
     topicId = data['topicId']
     collectId = data['collectId']
-    topic = Topic.query.filter_by(uid=topicId).first_or_404()
-    collect = Collect.query.filter_by(id=collectId).first_or_404()
-    collect.topics.remove(topic)
-    db.session.commit()
+    CollectDetail.delete(topicId, collectId)
     return jsonify(judge=True)
 
 

+ 1 - 1
maple/static/assets/home.js

@@ -25,7 +25,7 @@ else
 {$.ajax({type:"POST",url:"/user/follow",data:data,contentType:'application/json;charset=UTF-8',success:function(result){if(result.judge===true)
 {obj.text('取消关注').addClass('active');}else
 {alert('asd');}}});}}
-$(document).ready(function(){$('button.tagfollow').click(function(){var _$this=$(this);var data=JSON.stringify({id:_$this.attr("id"),type:'tag'});Follow(_$this,data);});$('button.topicfollow').click(function(){var _$this=$(this);var data=JSON.stringify({id:_$this.attr("id"),type:'topic'});Follow(_$this,data);});$('button.collectfollow').click(function(){var _$this=$(this);var data=JSON.stringify({id:_$this.attr("id"),type:'collect'});Follow(_$this,data);});});function DoCollect(collectData){$(document).ready(function(){$('button#edit-collect-form').click(function(){var data=JSON.stringify({name:$('#name').val(),description:$('#description').val(),is_privacy:$("input[name='is_privacy']:checked").val()});$.ajax({type:"PUT",url:collectData.edit_url,data:data,contentType:'application/json;charset=UTF-8',success:function(result){if(result.judge==true)
+$(document).ready(function(){$('button.tagfollow').click(function(){var _$this=$(this);var data=JSON.stringify({id:_$this.attr("id"),type:'tag'});Follow(_$this,data);});$('button.topicfollow').click(function(){var _$this=$(this);var data=JSON.stringify({id:_$this.attr("id"),type:'topic'});Follow(_$this,data);});$('button.collectfollow').click(function(){var _$this=$(this);var data=JSON.stringify({id:_$this.attr("id"),type:'collect'});Follow(_$this,data);});$('button.userfollow').click(function(){var _$this=$(this);var data=JSON.stringify({id:_$this.attr("id"),type:'user'});Follow(_$this,data);});});function DoCollect(collectData){$(document).ready(function(){$('button#edit-collect-form').click(function(){var data=JSON.stringify({name:$('#name').val(),description:$('#description').val(),is_privacy:$("input[name='is_privacy']:checked").val()});$.ajax({type:"PUT",url:collectData.edit_url,data:data,contentType:'application/json;charset=UTF-8',success:function(result){if(result.judge==true)
 {window.location=collectData.edit_url;}}});});$('button#delete-collect-form').click(function(){$.ajax({type:"DELETE",url:collectData.delete_url,data:JSON.stringify(),contentType:'application/json;charset=UTF-8',success:function(result){if(result.judge==true)
 {window.location=collectData.url;}}});});$('#delete-from-collect').click(function(){var _$this=$(this);var topicId=_$this.attr('data-id');var collectId=collectData.collectId;var data=JSON.stringify({collectId:collectId,topicId:topicId});$.ajax({type:"DELETE",url:collectData.delete,data:data,contentType:'application/json;charset=UTF-8',success:function(result){if(result.judge==true)
 {_$this.parent().remove();}}});});});}

BIN
maple/static/avatars/honmaple-14670891852944.png


+ 8 - 0
maple/static/styles/mine.js

@@ -52,6 +52,14 @@ $(document).ready(function(){
     });
     Follow(_$this,data);
   });
+  $('button.userfollow').click(function(){
+    var _$this = $(this);
+    var data = JSON.stringify({
+      id:_$this.attr("id"),
+      type:'user'
+    });
+    Follow(_$this,data);
+  });
 });
 function DoCollect(collectData) {
   $(document).ready(function(){

+ 11 - 1
maple/templates/base/base.html

@@ -72,7 +72,17 @@
     {% endif %}
     <a href="{{ url_for('tag.tag')}}" ><span class="btn btn-sm btn-primary pull-right">所有标签</span></a>
     <a href="{{ url_for('forums.userlist')}}"><span class="btn btn-sm btn-primary pull-right">用户列表</span></a>
-    <a href="{{ url_for('forums.notice')}}"><span class="btn btn-sm btn-primary pull-right">消息通知</span></a>
+    <a href="{{ url_for('forums.notice')}}"><span class="btn btn-sm btn-primary pull-right">
+        消息通知
+        {% if g.user.is_authenticated %}
+        {% set n = current_user.id | notice_count %}
+        {% if n != 0 -%}
+        <span class="badge">
+            {{ n }}
+        </span>
+        {% endif %}
+        {% endif %}
+    </span></a>
     {% block content %} {% endblock %}
 </div>
 {% endblock %}

+ 34 - 0
maple/templates/base/notice.html

@@ -0,0 +1,34 @@
+{% import 'base/link.html' as link_base %}
+{% macro privacy(notice) -%}
+<small style="color:#999;">由{{ link_base.user(notice.send_user) }} 发来的私信:</small>
+<small class="pull-right">{{ notice.publish | timesince }}</small>
+<p style="margin-bottom:0px">{{ notice.content['content'] }}</p>
+{%- endmacro %}
+{% macro reply(notice) -%}
+{% set content = notice.content %}
+<small style="color:#999;"> {{ link_base.user(notice.send_user)}} 回复了你创建的主题:
+    <a href="{{ content['url'] }}">{{ content['title'] }}</a>
+</small>
+<small class="pull-right"> {{ notice.publish | timesince }} </small>
+<p style="margin-bottom:0px">{{ content["content"] | safe_clean }}</p>
+{%- endmacro %}
+{% macro collect(notice) -%}
+{% set content = notice.content %}
+<small style="color:#999;"> {{ link_base.user(notice.send_user)}} 收藏了你创建的主题:
+    <a href="{{ content['url'] }}">{{ content['title'] }}</a>
+</small>
+<small class="pull-right"> {{ notice.publish | timesince }} </small>
+{%- endmacro %}
+{% macro like(notice) -%}
+{% set content = notice.content %}
+<small style="color:#999;"> {{ link_base.user(notice.send_user)}} 在
+    <a href="{{ content['url'] }}">{{ content['title'] }}</a> 赞了你回复
+</small>
+<small class="pull-right"> {{ notice.publish | timesince }} </small>
+<p style="margin-bottom:0px">{{ content["content"] | safe_clean }}</p>
+{%- endmacro %}
+{% macro user(notice) -%}
+{% set content = notice.content %}
+<small style="color:#999;"> {{ link_base.user(notice.send_user)}} 关注了你 </small>
+<small class="pull-right"> {{ notice.publish | timesince }} </small>
+{%- endmacro %}

+ 6 - 4
maple/templates/forums/notice.html

@@ -6,14 +6,16 @@
     <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">全部标记为已读</button>
                 消息通知
             </div>
             {% if notices.items %}
-            <div class="panel-body">
-                {% for notice in notices.items %}
-                {{ notice }}
-                {% endfor %}
+            {% 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">

+ 1 - 1
maple/templates/topic/replies.html

@@ -19,7 +19,7 @@
     {% if replies.items %}
     {% set num = 1 %}
     {% for reply in replies.items %}
-    <div class="panel-body media" style="border-bottom:1px solid #eee;margin:0">
+    <div class="panel-body media" id="reply-{{ reply.id }}" style="border-bottom:1px solid #eee;margin:0">
         <div class="media-left">
             <a href="{{ url_for('user.user',user_url=reply.author.username) }}">
                 <img class="media-object img-circle" src="{{ link_base.avatar(reply.author.infor)}}" alt="avatar" style="width:48px;height:48px">

+ 1 - 1
maple/templates/user/following_user.html

@@ -12,7 +12,7 @@
         <div class="panel-panel-default">
             {% for user in current_user.following_users %}
             <div class="panel-body" style="border-bottom:1px solid #eee">
-                {{ user.username}}
+                {{ link_base.user(user)}}
                 <span style="float:right">
                     <button class="btn btn-sm btn-default userfollow active" id="{{ user.id}}" style="padding:0 5px">取消关注</button>
                 </span>

+ 32 - 0
maple/templates/user/infor.html

@@ -25,4 +25,36 @@
             </tr>
         </table>
     </div>
+    {% if g.user.is_authenticated and current_user.username != g.user_url %}
+    <div class="list-group-item">
+        <span class="text-right" style="display:block">
+            {% if user in current_user.following_users %}
+            <button class="btn btn-sm btn-default userfollow active" id="{{ user.id}}">取消关注</button>
+            {% else %}
+            <button class="btn btn-sm btn-default userfollow" id="{{ user.id}}">关注他</button>
+            {% endif %}
+            <button class="btn btn-sm btn-default" id="{{ user.id}}" title="私信" data-toggle="modal" data-target="#send-message"><i class="icon-comments-alt" style="font-size:16px;"></i></button>
+        </span>
+    </div>
+    {% endif %}
+</div>
+<div class="modal fade" id="send-message" tabindex="-1" role="dialog" aria-labelledby="send-messageLabel">
+    <div class="modal-dialog" role="document">
+        <div class="modal-content">
+            <div class="modal-header">
+                <button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">&times;</span></button>
+                <h5 class="modal-title" id="send-messageLabel">发送私信</h5>
+            </div>
+            <form action="{{ url_for('forums.message',receId=user.id)}}" method="POST">
+                <div class="modal-body">
+                    {{ g.message_form.hidden_tag() }}
+                    {{ g.message_form.message(class="form-control",placeholder="仅支持纯文本,不超过1024字") }}
+                </div>
+                <div class="modal-footer" style="padding-top:5px;padding-bottom:5px;">
+                    <button type="button" class="btn btn-default" data-dismiss="modal">取消</button>
+                    <button type="submit" class="btn btn-primary">确认</button>
+                </div>
+            </form>
+        </div>
+    </div>
 </div>

+ 12 - 21
maple/templates/user/user.html

@@ -30,22 +30,16 @@
         <div  style="background:#fff;border:1px solid #ddd;border-radius:5px">
             {% if g.user.is_authenticated and current_user.username == g.user_url %}
             <ul class="nav nav-pills nav-stacked ">
-                <li role="presentation" class="topics"><a href="{{ url_for('user.topic')}}">我的主题</a></li>
-                <li role="presentation" class="replies"><a href="{{ url_for('user.reply')}}">我的回复</a></li>
-                <li role="presentation" class="collects"><a href="{{ url_for('user.collect')}}">我的收藏</a></li>
-            </ul>
-            <ul class="nav nav-pills nav-stacked" >
-                <li role="presentation" class="followings"><a href="{{ url_for('user.following')}}">我的关注</a></li>
-                <li role="presentation" class="followers"><a href="{{ url_for('user.follower')}}">我的粉丝</a></li>
+                {% set class_list = ['topics','replies','collects','followings','followers'] %}
+                {% set href_list = ['user.topic','user.reply','user.collect','user.following','user.follower'] %}
+                {% set show_list = ['我的主题','我的回复','我的收藏','我的关注','我的粉丝'] %}
+                {{ nav_list(class_list,href_list,show_list)}}
             </ul>
             {% else %}
             <ul class="nav nav-pills nav-stacked" >
                 <li role="presentation" class="topics"><a href="{{ url_for('user.topic')}}">{{ g.user_url}}的主题</a></li>
                 <li role="presentation" class="replies"><a href="{{ url_for('user.reply')}}">{{ g.user_url}}的回复</a></li>
                 <li role="presentation" class="collects"><a href="{{ url_for('user.collect')}}">{{ g.user_url}}的收藏</a></li>
-            </ul>
-            <ul class="nav nav-pills nav-stacked" >
-                <!-- <li role="presentation" class="followings"><a href="{{ url_for('user.following')}}">{{ g.user_url}}的关注</a></li> -->
                 <li role="presentation" class="followers"><a href="{{ url_for('user.follower')}}">{{ g.user_url}}的粉丝</a></li>
             </ul>
             {% endif %}
@@ -53,17 +47,14 @@
     </div>
     <div class="col-md-9">
         {% set setting = user.setting %}
-        {% if type == 'topic' %}
-        {% include 'user/topic.html' %}
-        {% elif type == 'reply' %}
-        {% include 'user/reply.html' %}
-        {% elif type == 'notebook' %}
-        {% include 'user/notebook.html' %}
-        {% elif type == 'follower' %}
-        {% include 'user/follower.html' %}
-        {% elif type == 'collect' %}
-        {% include 'user/collect.html' %}
-        {% endif %}
+        {% include "user/" + type + ".html" %}
     </div>
 </div>
 {% endblock %}
+
+{% macro nav_list(class,href,show) -%}
+{% set len = class | length %}
+{% for i in range(len) %}
+<li role="presentation" class="{{ class[i] }}"><a href="{{ url_for(href[i])}}">{{show[i]}}</a></li>
+{% endfor %}
+{%- endmacro %}

+ 6 - 2
maple/topic/controls.py

@@ -6,7 +6,7 @@
 # Author: jianglin
 # Email: xiyang0807@gmail.com
 # Created: 2016-06-15 10:22:42 (CST)
-# Last Update:星期一 2016-6-27 14:36:20 (CST)
+# Last Update:星期四 2016-6-30 19:49:45 (CST)
 #          By:
 # Description:
 # **************************************************************************
@@ -14,6 +14,7 @@ from flask_login import current_user
 from maple import db
 from maple.helpers import make_uid
 from maple.main.models import RedisData
+from maple.forums.controls import reply as notice_reply
 from .models import Topic, Tags, Reply
 from re import split as sp
 
@@ -92,6 +93,9 @@ class ReplyModel(object):
         reply.topic_id = uid
         db.session.add(reply)
         db.session.commit()
-        reply.topic.board.count.all_topics += 1
+        topic = reply.topic
+        topic.board.count.all_topics += 1
+        if topic.author_id != current_user.id:
+            notice_reply(topic, reply)
         db.session.commit()
         RedisData.set_replies(uid)

+ 6 - 1
maple/topic/models.py

@@ -6,7 +6,7 @@
 # Author: jianglin
 # Email: xiyang0807@gmail.com
 # Created: 2016-05-20 13:32:12 (CST)
-# Last Update:星期一 2016-6-27 23:1:42 (CST)
+# Last Update:星期二 2016-6-28 11:53:41 (CST)
 #          By:
 # Description:
 # **************************************************************************
@@ -26,6 +26,9 @@ class Tags(db.Model):
     tagname = db.Column(db.String(64), nullable=False)
     summary = db.Column(db.Text)
 
+    def __str__(self):
+        return self.tagname
+
     def __repr__(self):
         return '<Tags %r>' % self.tagname
 
@@ -131,6 +134,8 @@ class Collect(db.Model):
                              secondary='collect_topic',
                              lazy='dynamic',
                              backref="collects")
+    def __str__(self):
+        return self.name
 
     def __repr__(self):
         return "<Collect %r>" % self.name

+ 10 - 17
maple/user/forms.py

@@ -6,7 +6,7 @@
 # Author: jianglin
 # Email: xiyang0807@gmail.com
 # Created: 2016-05-20 18:08:44 (CST)
-# Last Update:星期五 2016-6-24 23:36:35 (CST)
+# Last Update:星期二 2016-6-28 21:51:0 (CST)
 #          By:
 # Description:
 # **************************************************************************
@@ -30,20 +30,13 @@ class PasswordForm(Form):
     password_nn = PasswordField('重复新密码:', [DataRequired()])
 
 
+choices = [(1, '所有人'), (2, '已登陆用户'), (3, '仅自己')]
+
+
 class PrivacyForm(Form):
-    online_status = SelectField('登录状态',
-                                coerce=int,
-                                choices=[(1, '所有人'), (2, '已登陆用户'), (3, '仅自己')])
-    topic_list = SelectField('主题列表',
-                             coerce=int,
-                             choices=[(1, '所有人'), (2, '已登陆用户'), (3, '仅自己')])
-
-    rep_list = SelectField('回复列表',
-                           coerce=int,
-                           choices=[(1, '所有人'), (2, '已登陆用户'), (3, '仅自己')])
-    ntb_list = SelectField('笔记列表',
-                           coerce=int,
-                           choices=[(1, '所有人'), (2, '已登陆用户'), (3, '仅自己')])
-    collect_list = SelectField('收藏列表',
-                               coerce=int,
-                               choices=[(1, '所有人'), (2, '已登陆用户'), (3, '仅自己')])
+    online_status = SelectField('登录状态', coerce=int, choices=choices)
+    topic_list = SelectField('主题列表', coerce=int, choices=choices)
+
+    rep_list = SelectField('回复列表', coerce=int, choices=choices)
+    ntb_list = SelectField('笔记列表', coerce=int, choices=choices)
+    collect_list = SelectField('收藏列表', coerce=int, choices=choices)

+ 14 - 14
maple/user/models.py

@@ -6,7 +6,7 @@
 # Author: jianglin
 # Email: xiyang0807@gmail.com
 # Created: 2016-05-20 13:24:19 (CST)
-# Last Update:星期一 2016-6-27 22:46:38 (CST)
+# Last Update:星期四 2016-6-30 21:14:5 (CST)
 #          By:
 # Description:
 # **************************************************************************
@@ -32,14 +32,11 @@ class Follow(db.Model):
     following_user_id = db.Column(db.Integer,
                                   db.ForeignKey('users.id'))
     following_tag_id = db.Column(db.Integer,
-                                 db.ForeignKey('tags.id',
-                                               ondelete="CASCADE"))
+                                 db.ForeignKey('tags.id'))
     following_collect_id = db.Column(db.Integer,
-                                     db.ForeignKey('collects.id',
-                                                   ondelete="CASCADE"))
+                                     db.ForeignKey('collects.id'))
     followinf_topic_id = db.Column(db.Integer,
-                                   db.ForeignKey('topics.id',
-                                                 ondelete="CASCADE"))
+                                   db.ForeignKey('topics.id'))
 
 
 class User(db.Model, UserMixin):
@@ -60,24 +57,27 @@ class User(db.Model, UserMixin):
     following_tags = db.relationship('Tags',
                                      secondary='follows',
                                      primaryjoin="User.id==follows.c.follower_id",
-                                     lazy='dynamic',
-                                     backref="followers",
+                                     # lazy='dynamic',
+                                     backref=db.backref(
+                                         'followers', lazy='dynamic'),
                                      # cascade='all,delete-orphan',
                                      # single_parent=True,
                                      )
     following_topics = db.relationship('Topic',
                                        secondary='follows',
                                        primaryjoin="User.id==follows.c.follower_id",
-                                       lazy='dynamic',
-                                       backref="followers",
+                                       # lazy='dynamic',
+                                       backref=db.backref(
+                                           'followers', lazy='dynamic'),
                                        # cascade='all,delete-orphan',
                                        # single_parent=True,
                                        )
     following_collects = db.relationship('Collect',
                                          secondary='follows',
                                          primaryjoin="User.id==follows.c.follower_id",
-                                         lazy='dynamic',
-                                         backref="followers",
+                                         backref=db.backref(
+                                             'followers', lazy='dynamic'),
+                                         # lazy='dynamic',
                                          # cascade='all,delete-orphan',
                                          # single_parent=True,
                                          )
@@ -87,7 +87,7 @@ class User(db.Model, UserMixin):
                                       secondaryjoin="User.id==follows.c.following_user_id",
                                       backref=db.backref(
                                           'followers', lazy='dynamic'),
-                                      lazy='dynamic'
+                                      # lazy='dynamic'
                                       )
 
     setting_id = db.Column(db.Integer,

+ 8 - 2
maple/user/views.py

@@ -6,7 +6,7 @@
 # Author: jianglin
 # Email: xiyang0807@gmail.com
 # Created: 2016-05-20 18:04:43 (CST)
-# Last Update:星期六 2016-6-25 13:30:4 (CST)
+# Last Update:星期二 2016-6-28 22:1:34 (CST)
 #          By:
 # Description:
 # **************************************************************************
@@ -16,10 +16,16 @@ from maple import app
 from maple.helpers import is_num
 from maple.topic.models import Topic, Reply, Collect
 from maple.user.models import User
+from maple.forums.forms import MessageForm
 
 site = Blueprint('user', __name__)
 
 
+@site.before_request
+def before():
+    g.message_form = MessageForm()
+
+
 @site.url_value_preprocessor
 def pull_user_url(endpoint, values):
     g.user_url = values.pop('user_url')
@@ -54,7 +60,7 @@ def topic():
         abort(404)
     if orderby == 'vote':
         topics = Topic.query.join(Topic.author).filter(
-            User.username == g.user_url).order_by(Topic.vote).paginate(
+            User.username == g.user_url).order_by(Topic.vote.desc()).paginate(
                 page, app.config['PER_PAGE'],
                 error_out=True)
     else: