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

增加topic投票,上传用户头像,topic可按投票排序

honmaple 9 лет назад
Родитель
Сommit
bc6f51c27b

+ 3 - 1
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-17 13:35:31 (CST)
+# Last Update:星期六 2016-6-25 1:0:54 (CST)
 #          By:jianglin
 # Description:
 # **************************************************************************
@@ -55,6 +55,8 @@ def register_routes(app):
     app.register_blueprint(site, url_prefix='/user')
     from maple.setting.views import site
     app.register_blueprint(site, url_prefix='/setting')
+    from maple.upload.views import site as upload_site
+    app.register_blueprint(upload_site)
     from maple.tag.views import site
     app.register_blueprint(site, url_prefix='/t')
     from maple.docs.views import site

+ 2 - 1
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-19 16:23:11 (CST)
+# Last Update:星期六 2016-6-25 11:13:8 (CST)
 #          By:
 # Description:
 # **************************************************************************
@@ -67,6 +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'),
               use_auth=True)
     Captcha(app)
     Error(app)

+ 5 - 5
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-19 16:26:44 (CST)
+# Last Update:星期一 2016-6-20 21:2:58 (CST)
 #          By:
 # Description:
 # **************************************************************************
@@ -52,13 +52,13 @@ class Filters(object):
         diff = now - dt
         if diff.days > 10:
             return dt.strftime('%Y-%m-%d %H:%M')
-        if diff.days <= 10 and diff.days > 0:
+        elif diff.days <= 10 and diff.days > 0:
             periods = ((diff.days, "day", "days"), )
-        if diff.days <= 0 and diff.seconds > 3600:
+        elif diff.days <= 0 and diff.seconds > 3600:
             periods = ((diff.seconds / 3600, "hour", "hours"), )
-        if diff.seconds <= 3600 and diff.seconds > 90:
+        elif diff.seconds <= 3600 and diff.seconds > 90:
             periods = ((diff.seconds / 60, "minute", "minutes"), )
-        if diff.seconds <= 90:
+        else:
             return default
 
         for period, singular, plural in periods:

+ 2 - 2
maple/main/permission.py

@@ -6,7 +6,7 @@
 # Author: jianglin
 # Email: xiyang0807@gmail.com
 # Created: 2016-06-09 19:53:35 (CST)
-# Last Update:星期三 2016-6-15 17:50:37 (CST)
+# Last Update:星期六 2016-6-25 11:4:20 (CST)
 #          By:
 # Description:
 # **************************************************************************
@@ -64,7 +64,7 @@ class TopicPermission(BasePermission):
     def put(self, uid):
         permission = EditTopicPermission(uid)
         if not permission.can():
-            flash('你没有权限')
+            flash('你没有权限','warning')
             return redirect(url_for('topic.topic', uid=uid))
 
     @login_required

+ 1 - 1
maple/setting/controls.py

@@ -6,7 +6,7 @@
 # Author: jianglin
 # Email: xiyang0807@gmail.com
 # Created: 2016-06-15 10:03:28 (CST)
-# Last Update:星期三 2016-6-15 10:18:32 (CST)
+# Last Update:星期六 2016-6-25 0:55:31 (CST)
 #          By:
 # Description:
 # **************************************************************************

+ 11 - 20
maple/setting/forms.py

@@ -6,33 +6,24 @@
 # Author: jianglin
 # Email: xiyang0807@gmail.com
 # Created: 2016-05-21 22:46:35 (CST)
-# Last Update:星期三 2016-6-15 10:9:7 (CST)
+# Last Update:星期六 2016-6-25 0:53:46 (CST)
 #          By:
 # Description:
 # **************************************************************************
 from flask.ext.wtf import Form
-from wtforms import StringField, PasswordField, BooleanField,\
-    TextAreaField, SelectField
-from wtforms.validators import Length, DataRequired, Email, EqualTo
+from wtforms import StringField, PasswordField, TextAreaField, SelectField
+from wtforms.validators import Length, DataRequired, EqualTo
+
+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)
 
 
 class ProfileForm(Form):

+ 9 - 6
maple/setting/views.py

@@ -6,15 +6,16 @@
 # Author: jianglin
 # Email: xiyang0807@gmail.com
 # Created: 2016-05-20 18:04:43 (CST)
-# Last Update:星期四 2016-6-16 18:53:30 (CST)
+# Last Update:星期六 2016-6-25 11:7:20 (CST)
 #          By:jianglin
 # Description: user setting include password , infor and privacy
 # **************************************************************************
-from flask import (Blueprint, render_template, request, url_for, redirect, g,
+from flask import (Blueprint, render_template, request, url_for, redirect,
                    flash)
 from flask_maple.forms import flash_errors
 from flask_login import current_user, login_required
-from maple.setting.forms import ProfileForm, PasswordForm, PrivacyForm
+from maple.setting.forms import (ProfileForm, PasswordForm, PrivacyForm)
+from maple.upload.forms import AvatarForm
 from .controls import SettingModel
 
 site = Blueprint('setting', __name__)
@@ -25,6 +26,7 @@ site = Blueprint('setting', __name__)
 @login_required
 def setting():
     form = ProfileForm()
+    avatarform = AvatarForm()
     infor = current_user.infor
     if form.validate_on_submit() and request.method == "POST":
         SettingModel.profile(form)
@@ -36,7 +38,8 @@ def setting():
         form.introduce.data = infor.introduce
         form.school.data = infor.school
         form.word.data = infor.word
-        return render_template('setting/setting.html', form=form)
+        data = {'form': form, 'avatarform': avatarform}
+        return render_template('setting/setting.html', **data)
 
 
 @site.route('/password', methods=['GET', 'POST'])
@@ -45,10 +48,10 @@ def password():
     form = PasswordForm()
     if form.validate_on_submit() and request.method == "POST":
         if SettingModel.password(form):
-            flash('The password has been updated,Please login')
+            flash('The password has been updated,Please login', 'info')
             return redirect(url_for('auth.login'))
         else:
-            flash('password is error')
+            flash('password is error', 'danger')
             return redirect(url_for('setting.password'))
     else:
         if form.errors:

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

@@ -13,4 +13,14 @@ else
 {$("#showerror").show();$("#error").text(result.error);$("#changeCode").attr("src",url.captcha+"?code="+Math.random());}}});});$('button#forget').click(function(){$.ajax({type:"POST",url:url.forget,data:JSON.stringify({confirm_email:$('#confirm_email').val(),captcha:$("#captcha").val()}),contentType:'application/json;charset=UTF-8',success:function(result){if(result.judge==true)
 {window.location=url.index;}
 else
-{$("#showerror").show();$("#error").text(result.error);$("#changeCode").attr("src",url.captcha+"?code="+Math.random());}}});});});
+{$("#showerror").show();$("#error").text(result.error);$("#changeCode").attr("src",url.captcha+"?code="+Math.random());}}});});});function loadFile(event){var _file=document.getElementById("avatar");var i=_file.value.lastIndexOf('.');var len=_file.value.length;var extEndName=_file.value.substring(i+1,len);var extName="JPG,PNG";if(extName.indexOf(extEndName.toUpperCase())==-1){alert("您只能上传"+extName+"格式的文件");$('#avatar').val('');}else{var reader=new FileReader();reader.onload=function(){var icon='<i class="icon-exchange"></i>'+'\n';var img='<img src="'+reader.result+'" title="avatar" class="avatar img-circle">';$("#show-avatar").html(icon+img);};reader.readAsDataURL(event.target.files[0]);}}
+function SortFuntion(){var data=JSON.stringify({display:$('#display').val(),sort:$('#sort').val(),st:$('#st').val(),type:sortData.type,uid:sortData.uid,page:sortData.page});$.ajax({type:"POST",url:"/order",data:data,contentType:'application/json;charset=UTF-8',success:function(result){$('div.topiclist').html(result);}});}
+$(document).ready(function(){$('#display').change(function(){SortFuntion();});$('#sort').change(function(){SortFuntion();});$('#st').change(function(){SortFuntion();});});function Follow(obj,data){if(obj.hasClass('active'))
+{$.ajax({type:"DELETE",url:"/user/follow",data:data,contentType:'application/json;charset=UTF-8',success:function(result){if(result.judge===true)
+{obj.text('关注').removeClass('active');}
+else
+{alert('asd');}}});}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);});});

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


+ 19 - 0
maple/static/styles/upload.js

@@ -0,0 +1,19 @@
+function loadFile(event) {
+  var _file=document.getElementById("avatar");
+  var i=_file.value.lastIndexOf('.');
+  var len=_file.value.length;
+  var extEndName=_file.value.substring(i+1,len);
+  var extName="JPG,PNG";
+  if(extName.indexOf(extEndName.toUpperCase())==-1){
+    alert("您只能上传"+extName+"格式的文件");
+    $('#avatar').val('');
+  }else{
+    var reader = new FileReader();
+    reader.onload = function(){
+      var icon = '<i class="icon-exchange"></i>' + '\n';
+      var img = '<img src="' + reader.result + '" title="avatar" class="avatar img-circle">';
+      $("#show-avatar").html(icon + img);
+    };
+    reader.readAsDataURL(event.target.files[0]);
+  }
+}

+ 8 - 10
maple/templates/base/base.html

@@ -3,11 +3,6 @@
 {% from 'base/paginate.html' import footer as p_footer %}
 {% import 'base/link.html' as link_base %}
 {% from 'base/head.html' import breadcrumb %}
-{% block script %}
-{{ super()}}
-<script type="text/javascript" src="{{ url_for('static',filename='styles/order.js')}}"></script>
-<script type="text/javascript" src="{{ url_for('static',filename='styles/mine.js')}}"></script>
-{% endblock %}
 {% block main %}
 <nav class="navbar navbar-default navbar-fixed-top" style="background:#fff">
     <div class="container-fluid col-md-offset-1 col-md-10">
@@ -23,7 +18,7 @@
         </div>
         <div class="collapse navbar-collapse">
             <ul class="nav navbar-nav">
-                <li><a href="{{ url_for('forums.forums')}}">社区{{ _('社区')}}</a></li>
+                <li><a href="{{ url_for('forums.forums')}}">{{ _('社区')}}</a></li>
                 <li><a href="{{ url_for('docs.docs')}}">文档</a></li>
                 <li><a href="#">博客</a></li>
                 <li><a href="{{ url_for('topic.good')}}">精华文章</a></li>
@@ -36,18 +31,21 @@
     </div>
 </nav>
 <div class="col-md-offset-1 col-md-10" style="padding:0;margin-top:60px">
-    {% with messages = get_flashed_messages() %}
+    {% with messages = get_flashed_messages(with_categories=true) %}
     {% if messages %}
-    <div class="alert alert-info" style="padding:8px">
+    {% 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>
-            {% for message in messages %}
             <li style="list-style-type:none">{{ message }} </li>
-            {% endfor %}
         </ul>
     </div>
+    {% endfor %}
     {% endif %}
     {% endwith %}
     {% if g.user.is_authenticated %}

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

@@ -5,7 +5,7 @@
     <div class="form-group">
         <label class="col-sm-2 control-label">{{ field.label }}</label>
         <div class="col-sm-10">
-            {{ field(class='form-control')}}
+            {{ field(class="form-control")}}
         </div>
     </div>
     {% endfor %}

+ 7 - 0
maple/templates/base/link.html

@@ -33,3 +33,10 @@
 {% macro following_collect() -%}
 <a href="{{ url_for('mine.follow',type="collect")}}">关注的收藏夹</a>
 {%- endmacro %}
+{% macro avatar(infor) -%}
+{% if not infor.avatar -%}
+{{ url_for('static',filename='images/Moo.png') }}
+{% else %}
+{{ url_for('upload.avatar_file',filename=infor.avatar) }}
+{%- endif %}
+{%- endmacro %}

+ 0 - 1
maple/templates/base/sort.html

@@ -1,2 +1 @@
-{% from 'base/link.html' import user %}
 {% include 'topic/topic_list_base.html' %}

+ 29 - 2
maple/templates/setting/setting.html

@@ -2,6 +2,12 @@
 {% import 'base/link.html' as link %}
 {% block content %}
 {{ breadcrumb(active='资料修改')}}
+<style>
+ .avatar {
+     width: 100px;
+     height: 100px;
+ }
+</style>
 <div class="row">
     <div class="col-md-3" style="padding-right:0">
         <div class="list-group">
@@ -18,9 +24,30 @@
                 资料修改
             </div>
             <div class="panel-body" style="border-bottom:1px solid #f6e1e1;">
+                <form action="{{ url_for('upload.avatar')}}" method="POST" enctype=multipart/form-data>
+                    {{ form.hidden_tag() }}
+                    <div class="form-horizontal">
+                        <div class="form-group">
+                            <label class="col-sm-2 control-label">{{ avatarform.avatar.label }}</label>
+                            <div class="col-sm-10">
+                                <span>
+                                    <img alt="header" class="avatar img-circle" src="{{ link_base.avatar(current_user.infor)}}"/>
+                                </span>
+                                <span id="show-avatar">
+                                </span>
+                                {{ avatarform.avatar(class="form-control",onchange="loadFile(event)")}}
+                            </div>
+                        </div>
+                        <div class="form-group">
+                            <div class="col-sm-offset-2 col-sm-10">
+                                <button type="submit" class="btn btn-default btn-sm">确认上传</button>
+                            </div>
+                        </div>
+                    </div>
+                </form>
                 <form action="{{ url_for('setting.setting')}}" method="POST">
-                {% from 'base/form.html' import forms %}
-                {{ forms(form) }}
+                    {% from 'base/form.html' import forms %}
+                    {{ forms(form) }}
                 </form>
             </div>
         </div>

+ 64 - 8
maple/templates/topic/content.html

@@ -6,7 +6,6 @@ board.board:url_for('board.board',parent_b=board.parent_board,child_b=board.boar
 {% set last_reply = topic.replies.first() %}
 <style>
  .vote {
-     text-decoration: none;
      font-size: 10px;
      line-height: 1;
      padding: 2px 8px;
@@ -17,8 +16,51 @@ board.board:url_for('board.board',parent_b=board.parent_board,child_b=board.boar
      vertical-align: baseline;
      text-align: center;
      background-color: #fff;
+     text-decoration: none;
  }
 </style>
+<script type="text/javascript">
+ function upVoteTopic(topicId) {
+     if (g.csrftoken) {
+         var data = JSON.stringify({
+         });
+         $.ajax ({
+             type : "POST",
+             url : "{{ url_for('topic.vote_up',topicId=topic.uid)}}",
+             data:data,
+             contentType: 'application/json;charset=UTF-8',
+             success: function(result) {
+                 if (result.judge)
+                 {
+                     $('.votes').html(result.html);
+                 } else
+                 {
+                     window.location.href = result.url;
+                 }
+             }});
+     }
+ }
+ function downVoteTopic(topicId) {
+     if (g.csrftoken) {
+         var data = JSON.stringify({
+         });
+         $.ajax ({
+             type : "POST",
+             url : "{{ url_for('topic.vote_down',topicId=topic.uid)}}",
+             data:data,
+             contentType: 'application/json;charset=UTF-8',
+             success: function(result) {
+                 if (result.judge)
+                 {
+                     $('.votes').html(result.html);
+                 } else
+                 {
+                     window.location.href = result.url;
+                 }
+             }});
+     }
+ }
+</script>
 {% from 'base/paginate.html' import footer as p_footer %}
 <div class="row">
     <div class="col-md-9">
@@ -27,12 +69,26 @@ board.board:url_for('board.board',parent_b=board.parent_board,child_b=board.boar
                 <div class="media-body">
                     <h3 class="media-heading">{{ topic.title}}</h3>
                     <small style="color:#999">
-                        <span class="vote">
-                            <i class="icon-chevron-up"></i>
-                        </span>
-                        <span class="vote">
-                            <i class="icon-chevron-down"></i>
-                        </span>
+                        <div class="votes">
+                            {% if topic.vote and topic.vote > 0 -%}
+                            <a class="vote" href="javascript:void(0)" onclick="upVoteTopic({{ topic.uid }});" style="text-decoration:none;">
+                                <i class="icon-chevron-up">{{ topic.vote}}</i>
+                            </a>
+                            {% else %}
+                            <a class="vote" href="javascript:void(0)" onclick="upVoteTopic({{ topic.uid }});" style="text-decoration:none;">
+                                <i class="icon-chevron-up"></i>
+                            </a>
+                            {%- endif %}
+                            {% if topic.vote and topic.vote < 0 %}
+                            <a class="vote" href="javascript:void(0)" onclick="downVoteTopic({{ topic.uid }});" style="text-decoration:none;">
+                                <i class="icon-chevron-down">{{ topic.vote}}</i>
+                            </a>
+                            {% else %}
+                            <a class="vote" href="javascript:void(0)" onclick="downVoteTopic({{ topic.uid }});" style="text-decoration:none;">
+                                <i class="icon-chevron-down"></i>
+                            </a>
+                            {%- endif %}
+                        </div>
                         {% for tag in topic.tags %}
                         {{ link_base.tag(tag) }}
                         {% endfor %}
@@ -47,7 +103,7 @@ board.board:url_for('board.board',parent_b=board.parent_board,child_b=board.boar
                 </div>
                 <div class="media-right">
                     <a href="{{ url_for('user.user',user_url=topic.author.username)}}">
-                        <img class="media-object img-circle" src="{{ url_for('static',filename='images/Moo.png')}}" alt="..." style="width:64px;height:64px">
+                        <img class="media-object img-circle" src="{{ link_base.avatar(topic.author.infor) }}" alt="avatar" style="width:64px;height:64px">
                     </a>
                 </div>
             </div>

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

@@ -66,8 +66,8 @@
     {% for reply in replies.items %}
     <div class="panel-body media" style="border-bottom:1px solid #eee;margin:0">
         <div class="media-left">
-            <a href="#">
-                <img class="media-object img-circle" src="{{ url_for('static',filename='images/Moo.png')}}" alt="..." style="width:48px;height:48px">
+            <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">
             </a>
         </div>
         <div class="media-body">

+ 3 - 2
maple/templates/topic/topic_list_base.html

@@ -1,12 +1,13 @@
 {% import 'base/link.html' as link_base  %}
 {% if topics.items %}
 {% for topic in topics.items %}
+{% set author = topic.author %}
 <div class="panel-body" style="padding:6px;border-bottom:1px solid #eee">
     <div class="row">
         <div class="col-md-6 media">
             <div class="media-left">
-                <a href="{{ url_for('user.user',user_url=topic.author.username) }}">
-                    <img class="media-object img-circle" src="{{ url_for('static',filename='images/Moo.png')}}" alt="..." style="width:48px;height:48px">
+                <a href="{{ url_for('user.user',user_url=author.username) }}">
+                    <img class="media-object img-circle" src="{{ link_base.avatar(author.infor) }}" alt="avatar" style="width:48px;height:48px">
                 </a>
             </div>
             <div class="media-body">

+ 2 - 2
maple/templates/user/infor.html

@@ -1,12 +1,12 @@
 <div class="list-group">
     <div class="media list-group-item">
         <div class="media-left">
-            <img class="media-object img-circle" src="{{ url_for('static',filename='images/Moo.png')}}" alt="..." style="width:64px;height:64px">
+            <img class="media-object img-circle" src="{{ link_base.avatar(user.infor) }}" alt="avatar" style="width:64px;height:64px">
         </div>
         <div class="media-body">
             <h4 class="media-heading">{{ user.username}}</h4>
             <small style="color:#999">
-                <span>第{{ user.id}}号会员</span>/
+                <span>第{{ user.id }}号会员</span>/
                 <span>{{user.register_time}}</span>
                 <br/>
                 <span>13篇主题</span> |

+ 7 - 2
maple/templates/user/topic.html

@@ -3,8 +3,13 @@
         <span style="float:right">
             排序:
             <div class="btn-group btn-group-xs" role="group">
+                {% if request.args.get('orderby') == 'vote' %}
+                <a href="{{ url_for('user.topic',orderby='publish')}}" class="btn btn-default">时间</a>
+                <a href="{{ url_for('user.topic',orderby='vote')}}" class="btn btn-default active">投票</a>
+                {% else %}
                 <a href="" class="btn btn-default active">时间</a>
-                <a href="" class="btn btn-default">投票</a>
+                <a href="{{ url_for('user.topic',orderby='vote')}}" class="btn btn-default">投票</a>
+                {% endif %}
             </div>
         </span>
     </div>
@@ -32,7 +37,7 @@
     {% endif %}
     {% else %}
     <div class="panel-body text-center">
-       没有主题
+        没有主题
     </div>
     {% endif %}
 </div>

+ 24 - 22
maple/templates/user/user.html

@@ -24,30 +24,32 @@
 {% from 'base/paginate.html' import footer as p_footer %}
 {{ breadcrumb(active=g.user_url)}}
 <div class="row">
-    <div class="col-md-3" style="padding-right:0">
+    <div class="col-md-3" style="padding-right:0;">
         {% set user = g.user_url | get_user_infor %}
         {% include 'user/infor.html' %}
-        {% 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>
-        </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 %}
+        <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>
+            </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 %}
+        </div>
     </div>
     <div class="col-md-9">
         {% set setting = user.setting %}

+ 22 - 1
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-16 13:9:11 (CST)
+# Last Update:星期六 2016-6-25 13:4:49 (CST)
 #          By:
 # Description:
 # **************************************************************************
@@ -52,6 +52,27 @@ class TopicModel(object):
         RedisData.set_topics()
         return topic
 
+    def vote(uid, count):
+        if count > 0:
+            html = '''
+                    <a class="vote" href="javascript:void(0)" onclick="upVoteTopic(%s);" style="text-decoration:none;">
+                        <i class="icon-chevron-up">%d</i>
+                    </a>
+                    <a class="vote" href="javascript:void(0)" onclick="downVoteTopic(%s);" style="text-decoration:none;">
+                        <i class="icon-chevron-down"></i>
+                    </a>
+            ''' % (uid, count, uid)
+        else:
+            html = '''
+                    <a class="vote" href="javascript:void(0)" onclick="upVoteTopic(%s);" style="text-decoration:none;">
+                        <i class="icon-chevron-up"></i>
+                    </a>
+                    <a class="vote" href="javascript:void(0)" onclick="downVoteTopic(%s);" style="text-decoration:none;">
+                        <i class="icon-chevron-down">%d</i>
+                    </a>
+            ''' % (uid, uid, count)
+        return html
+
 
 class ReplyModel(object):
     def post_data(form, uid):

+ 2 - 2
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-19 16:6:52 (CST)
+# Last Update:星期六 2016-6-25 11:30:55 (CST)
 #          By:
 # Description:
 # **************************************************************************
@@ -38,6 +38,7 @@ class Topic(db.Model):
     content = db.Column(db.Text, nullable=False)
     publish = db.Column(db.DateTime, default=datetime.now())
     updated = db.Column(db.DateTime)
+    vote = db.Column(db.Integer, default=0)
 
     tags = db.relationship('Tags',
                            secondary=tag_topic,
@@ -133,7 +134,6 @@ class Like(db.Model):
     reply_id = db.Column(db.Integer, db.ForeignKey('replies.id'))
     like_time = db.Column(db.DateTime, default=datetime.now())
 
-
 # class TopicCount(db.Model):
 #     __tablename__ = 'topic_counts'
 #     id = db.Column(db.Integer, primary_key=True)

+ 31 - 3
maple/topic/views.py

@@ -6,16 +6,16 @@
 # Author: jianglin
 # Email: xiyang0807@gmail.com
 # Created: 2016-05-20 13:47:04 (CST)
-# Last Update:星期四 2016-6-16 19:6:20 (CST)
+# Last Update:星期六 2016-6-25 13:15:29 (CST)
 #          By:
 # Description:
 # **************************************************************************
 from flask import (Blueprint, render_template, redirect, url_for, request, g,
-                   session, Markup, abort)
+                   jsonify, session, Markup, abort)
 from flask.views import MethodView
 from flask_login import login_required
 from flask_maple.forms import flash_errors
-from maple import app
+from maple import app, db
 from maple.main.models import RedisData
 from maple.main.permission import topic_permission, reply_permission
 from maple.helpers import is_num
@@ -65,6 +65,34 @@ def preview():
         abort(404)
 
 
+@site.route('/up/<topicId>', methods=['POST'])
+def vote_up(topicId):
+    if not g.user.is_authenticated:
+        return jsonify(judge=False, url=url_for('auth.login'))
+    topic = Topic.query.filter_by(uid=topicId).first_or_404()
+    if not topic.vote:
+        topic.vote = 1
+    else:
+        topic.vote += 1
+    db.session.commit()
+    html = TopicModel.vote(topicId, topic.vote)
+    return jsonify(judge=True, html=html)
+
+
+@site.route('/down/<topicId>', methods=['POST'])
+def vote_down(topicId):
+    if not g.user.is_authenticated:
+        return jsonify(judge=False, url=url_for('auth.login'))
+    topic = Topic.query.filter_by(uid=topicId).first_or_404()
+    if not topic.vote:
+        topic.vote = -1
+    else:
+        topic.vote -= 1
+    db.session.commit()
+    html = TopicModel.vote(topicId, topic.vote)
+    return jsonify(judge=True, html=html)
+
+
 class TopicAPI(MethodView):
     decorators = [topic_permission]
 

+ 12 - 0
maple/upload/__init__.py

@@ -0,0 +1,12 @@
+#!/usr/bin/env python
+# -*- coding=UTF-8 -*-
+# **************************************************************************
+# Copyright © 2016 jianglin
+# File Name: __init__.py
+# Author: jianglin
+# Email: xiyang0807@gmail.com
+# Created: 2016-06-25 00:50:47 (CST)
+# Last Update:星期六 2016-6-25 0:50:49 (CST)
+#          By:
+# Description:
+# **************************************************************************

+ 45 - 0
maple/upload/controls.py

@@ -0,0 +1,45 @@
+#!/usr/bin/env python
+# -*- coding=UTF-8 -*-
+# **************************************************************************
+# Copyright © 2016 jianglin
+# File Name: controls.py
+# Author: jianglin
+# Email: xiyang0807@gmail.com
+# Created: 2016-06-25 00:54:15 (CST)
+# Last Update:星期六 2016-6-25 10:39:1 (CST)
+#          By:
+# Description:
+# **************************************************************************
+from flask import request
+from flask_login import current_user
+from werkzeug import secure_filename
+from maple import db, app
+from time import time
+from random import randint
+from PIL import Image
+import os
+
+
+class UploadModel(object):
+    def avatar(form):
+        file = request.files[form.avatar.name]
+        filename = secure_filename(file.filename)
+        filename = current_user.username + '-' + str(int(time())) + str(
+            randint(1000, 9999))
+        img = Image.open(file)
+        size = 150, 150
+        img.thumbnail(size, Image.ANTIALIAS)
+        avatar_path = os.path.join(app.static_folder,
+                                   app.config['AVATAR_FOLDER'])
+        avatar = os.path.join(avatar_path, filename + '.png')
+        if not os.path.exists(avatar_path):
+            os.mkdir(avatar_path)
+        img.save(avatar)
+        img.close()
+        infor = current_user.infor
+        ef = os.path.join(avatar_path, infor.avatar)
+        if os.path.exists(ef):
+            os.remove(ef)
+        # file.save(os.path.join(app.static_folder, filename + '.png'))
+        infor.avatar = filename + '.png'
+        db.session.commit()

+ 20 - 0
maple/upload/forms.py

@@ -0,0 +1,20 @@
+#!/usr/bin/env python
+# -*- coding=UTF-8 -*-
+# **************************************************************************
+# Copyright © 2016 jianglin
+# File Name: forms.py
+# Author: jianglin
+# Email: xiyang0807@gmail.com
+# Created: 2016-06-25 00:52:30 (CST)
+# Last Update:星期六 2016-6-25 0:54:3 (CST)
+#          By:
+# Description:
+# **************************************************************************
+from flask_wtf import Form
+from flask_wtf.file import FileField, FileAllowed, FileRequired
+
+
+class AvatarForm(Form):
+    avatar = FileField('上传头像:',
+                       validators=[FileRequired(), FileAllowed(
+                           ['jpg', 'png'], '上传文件只能为图片且图片格式为jpg,png')])

+ 44 - 0
maple/upload/views.py

@@ -0,0 +1,44 @@
+#!/usr/bin/env python
+# -*- coding=UTF-8 -*-
+# **************************************************************************
+# Copyright © 2016 jianglin
+# File Name: views.py
+# Author: jianglin
+# Email: xiyang0807@gmail.com
+# Created: 2016-06-25 00:50:56 (CST)
+# Last Update:星期六 2016-6-25 10:55:45 (CST)
+#          By:
+# Description:
+# **************************************************************************
+from flask import (Blueprint, url_for, redirect, flash, send_from_directory)
+from flask_maple.forms import flash_errors
+from flask_login import login_required
+from maple import app
+from .forms import AvatarForm
+from .controls import UploadModel
+import os
+
+site = Blueprint('upload', __name__)
+
+
+@site.route('/avatar', methods=['POST'])
+@login_required
+def avatar():
+    form = AvatarForm()
+    if form.validate_on_submit():
+        UploadModel.avatar(form)
+        flash('上传成功', 'success')
+        return redirect(url_for('setting.setting'))
+    else:
+        if form.errors:
+            flash_errors(form)
+        return redirect(url_for('setting.setting'))
+
+
+@site.route('/avatars/<filename>')
+def avatar_file(filename):
+    avatar_path = os.path.join(app.static_folder, app.config['AVATAR_FOLDER'])
+    if not os.path.exists(os.path.join(avatar_path, filename)):
+        avatar_path = os.path.join(app.static_folder, 'images/')
+        filename = 'Moo.png'
+    return send_from_directory(avatar_path, filename)

+ 1 - 1
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-5-20 23:30:7 (CST)
+# Last Update:星期五 2016-6-24 23:36:35 (CST)
 #          By:
 # Description:
 # **************************************************************************

+ 2 - 1
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-16 18:17:47 (CST)
+# Last Update:星期六 2016-6-25 0:13:28 (CST)
 #          By:
 # Description:
 # **************************************************************************
@@ -134,6 +134,7 @@ class UserInfor(db.Model):
     # confirmed_time = db.Column(db.DateTime, nullable=True)
     # registered_time = db.Column(db.DateTime, nullable=False)
     # score = db.Column(db.Integer, nullable=False, default=100)
+    avatar = db.Column(db.String)
     word = db.Column(db.Text, nullable=True)
     introduce = db.Column(db.Text, nullable=True)
     school = db.Column(db.String, nullable=True)

+ 15 - 5
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-14 23:20:14 (CST)
+# Last Update:星期六 2016-6-25 13:30:4 (CST)
 #          By:
 # Description:
 # **************************************************************************
@@ -47,11 +47,21 @@ def user():
 
 @site.route('/topics')
 def topic():
+    orderby = request.args.get('orderby')
     page = is_num(request.args.get('page'))
-    topics = Topic.query.join(Topic.author).filter(
-        User.username == g.user_url).paginate(page,
-                                              app.config['PER_PAGE'],
-                                              error_out=True)
+    all_order = ['vote', 'publish']
+    if orderby and orderby not in all_order:
+        abort(404)
+    if orderby == 'vote':
+        topics = Topic.query.join(Topic.author).filter(
+            User.username == g.user_url).order_by(Topic.vote).paginate(
+                page, app.config['PER_PAGE'],
+                error_out=True)
+    else:
+        topics = Topic.query.join(Topic.author).filter(
+            User.username == g.user_url).paginate(page,
+                                                  app.config['PER_PAGE'],
+                                                  error_out=True)
     data = {'type': 'topic', 'topics': topics}
     return render_template('user/user.html', **data)
 

+ 1 - 0
run.py

@@ -27,3 +27,4 @@ if __name__ == '__main__':
     #  app.logger.info("Logging is set up.")
     app.run()
     print(app.url_map)
+    print(app.config["BASEDIR"])