【7】使用css/js/html模板来实现一个注册、登录和管理的功能
分支:auth
static添加文件
css文件夹:
app.css 自定义css样式【*】
bootstrap.min.cs bootstrap样式
compomemts文件夹: 插件用到的样式
animate.min.css 弹出提示框要到的样式
bootstrap-datepicker3.min.css 日期选择控件用到的样式
select2.min.css 下拉选择框用到的样式
fonts文件夹
bootstrap用到的字体
images文件夹
用到的一些图片
js文件夹
bootstrap.min.js bootstrap
common.js 一些通用的方法【*】
jquery-2.1.4.min.js bootstrap依赖jquery
auth文件夹: 用户管理界面用到的js
account.js【*】
compomemts文件夹:
bootstrap-datepicker.min.js 日期控件
bootstrap-notify.min.js 提示控件
jquery.bootstrap.min.js jquery
jquery.twbsPagination.min.js 分页控件
json2.js 处理json
select2.min.js 下拉框
【*】需要自己动手更改的部分
templates文件夹
base.htm模板文件
1 <!DOCTYPE html> 2 <html lang="en"> 3 <head> 4 <meta charset="UTF-8"> 5 <meta http-equiv="X-UA-Compatible" content="IE=edge"> 6 <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no"> 7 <meta name="description" content="Jakey's Blog"> 8 <meta name="keywords" content="Jakey's Blog"> 9 <meta name="author" content="Jakey.Chen"> 10 <link rel='shortcut icon' type='image/x-icon' href="{{ static_url('favicon.ico') }}"/> 11 <title>Jakey's Blog</title> 12 13 <link rel="stylesheet" href="/static/css/bootstrap.min.css"> 14 <link rel="stylesheet" href="/static/css/app.css"> 15 <link rel="stylesheet" href="/static/css/components/animate.min.css"> 16 17 <script src="/static/js/jquery-2.1.4.min.js"></script> 18 <script src="/static/js/bootstrap.min.js"></script> 19 <script src="/static/js/common.js"></script> 20 <script src="/static/js/components/bootstrap-notify.min.js"></script> 21 <script src="/static/js/components/jquery.bootstrap.min.js"></script> 22 </head> 23 24 </head> 25 26 <body> 27 {%block header%} 28 {%end%} 29 30 {%block content%} 31 {%end%} 32 33 {%block footer%} 34 {%end%} 35 </body> 36 </html>
footer.htm 页脚
1 <!-- footer --> 2 <footer class="main-footer"> 3 <div class="container"> 4 <div class="row"> 5 <div class="col-sm-4"> 6 <div class="widget"> 7 <h4 class="title">友情链接</h4> 8 <div class="content friend-links"> 9 <a href="http://www.cnblogs.com" title="博客园" onclick="_hmt.push(['_trackEvent', 'link', 'click', '博客园'])" target="_blank">博客园</a> 10 <a href="http://www.bootcss.com/" title="Bootstrap中文网" onclick="_hmt.push(['_trackEvent', 'link', 'click', 'Bootstrap中文网'])" target="_blank">Bootstrap中文网</a> 11 </div> 12 </div> 13 </div> 14 15 <div class="col-sm-4"> 16 <div class="widget"> 17 <h4 class="title">使用到的技术</h4> 18 <div class="content tag-cloud"> 19 <a href="http://www.bootcss.com/" title="Bootstrap 3.3.5" onclick="_hmt.push(['_trackEvent', 'link', 'click', 'Bootstrap中文网 3.3.5'])" target="_blank">Bootstrap</a> 20 <a href="http://www.jquery123.com/" title="jQuery 2.1.4" onclick="_hmt.push(['_trackEvent', 'link', 'click', 'jQuery中文文档'])" target="_blank">jQuery</a> 21 <a href="https://www.python.org/" title="Python 2.7" onclick="_hmt.push(['_trackEvent', 'link', 'click', 'Python官网'])" target="_blank">Python</a> 22 <a href="http://www.mysql.com/" title="MySQL 5.5" onclick="_hmt.push(['_trackEvent', 'link', 'click', 'MySQL官网'])" target="_blank">MySQL</a> 23 <a href="http://www.tornadoweb.org/en/stable/" title="TornadoWeb 4.2" onclick="_hmt.push(['_trackEvent', 'link', 'click', 'TornadoWeb官网'])" target="_blank">Tornado</a> 24 <a href="http://www.ubuntu.org.cn/server" title="Ubuntu Server 14.04 LTS" onclick="_hmt.push(['_trackEvent', 'link', 'click', 'Ubuntu Server'])" target="_blank">Ubuntu Server</a> 25 </div> 26 </div> 27 </div> 28 29 <div class="col-sm-4"> 30 <div class="widget"> 31 <h4 class="title">联系我们</h4> 32 <div class="content friend-links"> 33 <a href="mailto:Jakey.Chen@tpk.com" class='text-muted '>Jakey.Chen</a> 34 </div> 35 <div class="content friend-links"> 36 <a href="mailto:281743668@qq.com" class='text-muted '>Orochimaru</a> 37 </div> 38 </div> 39 </div> 40 </div> 41 </div> 42 </footer> 43 44 <div class="copyright"> 45 <div class="container"> 46 <div class="row"> 47 <div class="col-sm-12"> 48 <span>Copyright © <a href="http://git.oschina.net">开源中国</a></span> | 49 <span><a href="http://git.oschina.net/jakey.chen/Blog" target="_blank">Jakey.Chen</a></span> 50 </div> 51 </div> 52 </div> 53 </div>
header.htm 页眉导航
1 <!-- header navbar-inverse navbar-fixed-top--> 2 <div class="container"> 3 <nav class="navbar navbar-inverse navbar-fixed-top"> 4 <div class="container-fluid"> 5 <div class="container"> 6 <div class="navbar-header"> 7 <button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#navbar" aria-expanded="false" aria-controls="navbar"> 8 <span class="sr-only">Toggle navigation</span> 9 <span class="icon-bar"></span> 10 <span class="icon-bar"></span> 11 <span class="icon-bar"></span> 12 </button> 13 <a class="navbar-brand" href="/"><span class="glyphicon glyphicon-cloud" aria-hidden="true"> <strong>BLOG</strong></span></a> 14 </div> 15 16 <div id="navbar" class="navbar-collapse collapse"> 17 <ul class="nav navbar-nav"> 18 {% if admin is 1%} 19 <li><a href="/manage/blogs" aria-hidden="true">日 志</a></li> 20 <li><a href="/manage/comments" aria-hidden="true">评 论</a></li> 21 <li><a href="/account/info" aria-hidden="true">用 户</a></li> 22 {% end %} 23 </ul> 24 25 {% if not user %} 26 <ul class="nav navbar-nav navbar-right"> 27 <li><a href="/">注 册</a></li> 28 <li><a href="/">登 录</a></li> 29 </ul> 30 {% else %} 31 <ul class="nav navbar-nav navbar-right"> 32 <li><a href="/help"><span class="glyphicon glyphicon-question-sign" aria-hidden="true"> 帮助</span></a></li> 33 34 <li class="dropdown"> 35 <a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-haspopup="true" aria-expanded="false"><span class="glyphicon glyphicon-user" id="current_user" aria-hidden="true"> {{user}}</span></a> 36 <ul class="dropdown-menu"> 37 <li><a href="/changepasswd"><span class="glyphicon glyphicon-th-list" aria-hidden="true"> 修 改 密 码</span></a></li> 38 <li><a href="/login"><span class="glyphicon glyphicon-repeat" aria-hidden="true"> 切 换 账 户</span></a></li> 39 <li><a href="/logout"><span class="glyphicon glyphicon-off" aria-hidden="true"> 退 出 登 录</span></a></li> 40 </ul> 41 </li> 42 </ul> 43 {% end %} 44 </div> 45 </div> 46 </div> 47 </nav> 48 </div>
index.htm 主页
1 {% extends "base.htm" %} 2 3 {%block header%} 4 {%include 'header.htm'%} 5 {%end%} 6 7 {%block content%} 8 <div class="bs-docs-container"> 9 <div id="myCarousel" class="carousel slide" data-ride="carousel"> 10 <ol class="carousel-indicators"> 11 <li data-target="#myCarousel" data-slide-to="0" class="active"></li> 12 <li data-target="#myCarousel" data-slide-to="1"></li> 13 <li data-target="#myCarousel" data-slide-to="2"></li> 14 </ol> 15 16 <div class="carousel-inner" role="listbox"> 17 <div class="item active"> 18 <img class="first-slide img-full" src="{{ static_url('images/s-2.jpg') }}" alt="First slide"> 19 <div class="container"> 20 <div class="carousel-caption"> 21 <h1>Younger World Better Future</h1> 22 <p>更好的世界,更好的未来。</p> 23 <p><a class="btn btn-lg btn-danger" href="/register" role="button">注册账号</a></p> 24 </div> 25 </div> 26 </div> 27 28 <div class="item"> 29 <img class="second-slide img-full" src="{{ static_url('images/s-3.jpg') }}" alt="Second slide"> 30 <div class="container"> 31 <div class="carousel-caption"> 32 <h1>Beyond Coding, Social Collaboration</h1> 33 <p>不只是编码,我们更注重社会化协作!</p> 34 <p><a class="btn btn-lg btn-primary" href="/login" role="button">已有账号?登陆 >></a></p> 35 </div> 36 </div> 37 </div> 38 39 <div class="item"> 40 <img class="third-slide img-full" src="{{ static_url('images/s-4.jpg') }}" alt="Third slide"> 41 <div class="container"> 42 <div class="carousel-caption"> 43 <h1>Share Games,Share Dreams.</h1> 44 <p>分享青春,共筑未来。</p> 45 <p><a class="btn btn-lg btn-success" href="mailto:Jakey.Chen@tpk.com" role="button">联系我们</a></p> 46 </div> 47 </div> 48 </div> 49 </div> 50 51 <a class="left carousel-control" href="#myCarousel" role="button" data-slide="prev"> 52 <span class="glyphicon glyphicon-chevron-left" aria-hidden="true"></span> 53 <span class="sr-only">Previous</span> 54 </a> 55 56 <a class="right carousel-control" href="#myCarousel" role="button" data-slide="next"> 57 <span class="glyphicon glyphicon-chevron-right" aria-hidden="true"></span> 58 <span class="sr-only">Next</span> 59 </a> 60 </div> 61 </div> 62 {%end%} 63 64 {%block footer%} 65 {%include 'footer.htm'%} 66 {%end%}
auth文件夹里面存放关于注册登录等的html
register.htm 注册页面
1 {% extends "../base.htm" %} 2 3 {%block header%} 4 {%include '../header.htm'%} 5 {%end%} 6 7 {%block content%} 8 <div class="bs-docs-container"> 9 <div id="myCarousel" class="carousel slide" data-ride="carousel"> 10 <div class="carousel-inner" role="listbox"> 11 <div class="item active"> 12 <img class="first-slide img-full" src="{{ static_url('images/auth/bg_3.jpg') }}" alt="First slide"> 13 14 <div class="container"> 15 <div class="carousel-caption"> 16 <h1 id="register_info" style="color: red">{{error}}</h1> 17 <form class="form-signin" role="form" name="register_form" action="/register" method="POST"> 18 {% raw xsrf_form_html() %} 19 <h2 class="form-signin-heading">用 户 注 册</h2> 20 <p></p> 21 22 <input type="email" name="input_email" class="form-control" value='{{input_email}}' placeholder="邮 箱" required autofocus> 23 <p></p> 24 25 <input type="text" name="input_user" class="form-control" value='{{input_user}}' placeholder="用 户 名" required> 26 27 <input type="password" name="input_passwd" class="form-control" placeholder="密 码" required> 28 <p></p> 29 30 <button class="btn btn-lg btn-primary btn-block" type="submit">注 册</button> 31 </form> 32 </div> 33 </div> 34 </div> 35 </div> 36 </div> 37 </div> 38 {%end%} 39 40 {%block footer%} 41 {%include '../footer.htm'%} 42 {%end%}
login.htm 登录界面
1 {% extends "../base.htm" %} 2 3 {%block header%} 4 {%include '../header.htm'%} 5 {%end%} 6 7 {%block content%} 8 <div class="bs-docs-container"> 9 <div id="myCarousel" class="carousel slide" data-ride="carousel"> 10 <div class="carousel-inner" role="listbox"> 11 <div class="item active"> 12 <img class="first-slide img-full" src="{{ static_url('images/auth/bg_3.jpg') }}" alt="First slide"> 13 14 <div class="container"> 15 <div class="carousel-caption"> 16 <h1 id="register_info" style="color: red">{{error}}</h1> 17 <form class="form-signin" role="form" name="register_form" action="/register" method="POST"> 18 {% raw xsrf_form_html() %} 19 <h2 class="form-signin-heading">用 户 注 册</h2> 20 <p></p> 21 22 <input type="email" name="input_email" class="form-control" value='{{input_email}}' placeholder="邮 箱" required autofocus> 23 <p></p> 24 25 <input type="text" name="input_user" class="form-control" value='{{input_user}}' placeholder="用 户 名" required> 26 27 <input type="password" name="input_passwd" class="form-control" placeholder="密 码" required> 28 <p></p> 29 30 <button class="btn btn-lg btn-primary btn-block" type="submit">注 册</button> 31 </form> 32 </div> 33 </div> 34 </div> 35 </div> 36 </div> 37 </div> 38 {%end%} 39 40 {%block footer%} 41 {%include '../footer.htm'%} 42 {%end%}
changepasswd.htm 修改密码界面
1 {% extends "../base.htm" %} 2 3 {%block header%} 4 {%include '../header.htm'%} 5 {%end%} 6 7 {%block content%} 8 <div class="bs-docs-container"> 9 <div id="myCarousel" class="carousel slide" data-ride="carousel"> 10 <div class="carousel-inner" role="listbox"> 11 <div class="item active"> 12 <img class="first-slide img-full" src="{{ static_url('images/auth/bg_1.jpg') }}" alt="First slide"> 13 14 <div class="container"> 15 <div class="carousel-caption"> 16 <h1 id="changepasswd_info" style="color: red">{{error}}</h1> 17 <form class="form-signin" role="form" name="register_form" action="/changepasswd" method="POST"> 18 {% raw xsrf_form_html() %} 19 <h2 class="form-signin-heading">修 改 密 码</h2> 20 <p></p> 21 22 <input type="text" name="input_user" class="form-control" placeholder="NickName" value='{{user}}' required readonly> 23 <p></p> 24 25 <input type="password" name="input_old_passwd" class="form-control" placeholder="旧密码" value="" required autofocus> 26 <p></p> 27 28 <input type="password" name="input_new_passwd" class="form-control" placeholder="新密码" value="" required> 29 <p></p> 30 31 <button class="btn btn-lg btn-primary btn-block" type="submit">修 改</button> 32 </form> 33 </div> 34 </div> 35 </div> 36 </div> 37 </div> 38 </div> 39 40 {%end%} 41 42 {%block footer%} 43 {%include '../footer.htm'%} 44 {%end%}
account.htm 用户管理界面
1 {% extends "../base.htm" %} 2 3 {%block header%} 4 {%include '../header.htm'%} 5 {%end%} 6 7 {%block content%} 8 <script src="{{ static_url('js/knockout/knockout-2.1.0.js') }}"></script> 9 <script src="{{ static_url('js/knockout/knockout.mapping-2.4.1.js') }}"></script> 10 <script src="{{ static_url('js/auth/account.js') }}"></script> 11 <script src="{{ static_url('js/components/jquery.twbsPagination.min.js') }}"></script> 12 13 <div class="bs-docs-container"> 14 <div class="container"> 15 <div class="row"> 16 <div class="col-md-12"> 17 <div class="row" style="margin-top: 10px; margin-bottom: 10px"> 18 <div class="col-lg-6"> 19 <div class="input-group"> 20 <span class="input-group-btn"> 21 <div href="#modal_adduser" role="button" class="btn btn-info" data-toggle="modal"><span class="glyphicon glyphicon-plus"> 增加</span></div> 22 </span> 23 </div> 24 </div> 25 </div> 26 27 <div style="min-height: 550px"> 28 <table class="table table-hover table-bordered"> 29 <thead> 30 <tr> 31 <th colspan="7"> 32 <h3 class="table_title" id="table_title">用 户 列 表</h3> 33 </th> 34 </tr> 35 36 <tr class="table_header"> 37 <td>序号</td> 38 {% if admin is 1%} 39 <td>ID</td> 40 {% end %} 41 <td>用户名</td> 42 <td>邮箱</td> 43 <td>权限</td> 44 <td>状态</td> 45 <td></td> 46 </tr> 47 </thead> 48 <tbody> 49 <!-- ko foreach: $data --> 50 <tr data-bind="css: { 'danger': status() == 0, '': status() == 1 }"> 51 <td data-bind="text: $index() + 1"></td> 52 {% if admin is 1%} 53 <td > 54 <span id="user_id" data-bind="text: id" /> 55 </td> 56 {% end %} 57 <td > 58 <span id="user_name" data-bind="text: name" /> 59 </td> 60 <td > 61 <span id="email" data-bind="text: email" /> 62 </td> 63 <td > 64 <select id="admin" data-bind="value: admin"> 65 <option value="0">普通用户</option> 66 <option value="1">管理员</option> 67 </select> 68 </td> 69 <td > 70 <select id="status" data-bind="value: status"> 71 <option value="0">禁用</option> 72 <option value="1">可用</option> 73 </select> 74 </td> 75 <td> 76 <button class="btn btn-link" id="deleteButton" data-bind="click:function(name){update_user(name)}"><span class="glyphicon glyphicon-edit">更新</span></button> 77 78 <button class="btn btn-link" id="deleteButton" data-bind="click:function(name){delete_user(name)}"><span class="glyphicon glyphicon-trash">删除</span></button> 79 </td> 80 </tr> 81 <!-- /ko --> 82 </tbody> 83 </table> 84 </div> 85 <div id="pagination_box" class="pull-right"> 86 <ul id="pagination_zc" class="pagination-sm"></ul> 87 </div> 88 </div> 89 </div> 90 </div> 91 92 <!-- 模态框 --> 93 <div class="modal fade" id="modal_adduser" tabindex="-1" role="dialog" aria-labelledby="myModalLabel" aria-hidden="true"> 94 <div class="modal-dialog" > 95 <div class="modal-content"> 96 <div class="modal-header"> 97 <h4 class="modal-title" id="modal_title">新增用户</h4> 98 </div> 99 <div class="modal-body"> 100 <form class="form-horizontal"> 101 <fieldset> 102 <div class="control-group"> 103 <label class="control-label">邮 箱</label> 104 <div class="controls"> 105 <input class="input-xlarge" placeholder="邮箱" id="add_email" type="email"/> 106 </div> 107 </div> 108 <div class="control-group"> 109 <label class="control-label">用户名</label> 110 <div class="controls"> 111 <input class="input-xlarge" placeholder="用户名" id="add_usename" type="text"/> 112 </div> 113 </div> 114 <div class="control-group"> 115 <label class="control-label">密 码</label> 116 <div class="controls"> 117 <input class="input-xlarge" placeholder="密码" id="add_password" type="password"/> 118 </div> 119 </div> 120 <div class="control-group"> 121 <label class="control-label">权 限</label> 122 <div class="controls"> 123 <select class="input-xlarge" id="permission"> 124 <option value="1">管理员</option> 125 <option value="0">普通用户</option> 126 </select> 127 </div> 128 </div> 129 </fieldset> 130 </form> 131 </div> 132 <div class="modal-footer"> 133 <button class="btn" data-dismiss="modal" aria-hidden="true"><span class="glyphicon glyphicon-remove"> 关闭</span></button> 134 <button class="btn btn-info" data-dismiss="modal" aria-hidden="true" id="btn_add_user"><span class="glyphicon glyphicon-floppy-save"> 保存</span></button> 135 </div> 136 </div> 137 </div> 138 </div> 139 </div> 140 {%end%} 141 142 {%block footer%} 143 {%include '../footer.htm'%} 144 {%end%}
主函数 main.py
1 #!/usr/bin/env python 2 # coding:utf-8 3 4 import logging.config 5 6 import yaml 7 import torndb 8 import tornado.ioloop 9 import tornado.options 10 import tornado.httpserver 11 import tornado.web 12 from tornado.options import define, options 13 14 from url import url 15 from application import settings 16 17 define("port", default="7777", help="run on the given port", type=int) 18 define("mysql_host", default="localhost:3306", help="database host") 19 define("mysql_user", default="jakey", help="database user") 20 define("mysql_password", default="123", help="database password") 21 define("mysql_database", default="blog", help="database name") 22 23 # logging.config.dictConfig(yaml.load(open('logging.yaml', 'r'))) 24 25 26 class Application(tornado.web.Application): 27 28 def __init__(self): 29 tornado.web.Application.__init__(self, url, **settings) 30 31 self.db = torndb.Connection( 32 host=options.mysql_host, 33 database=options.mysql_database, 34 user=options.mysql_user, 35 password=options.mysql_password) 36 37 if __name__ == '__main__': 38 tornado.options.parse_command_line() 39 http_server = tornado.httpserver.HTTPServer(Application()) 40 http_server.listen(options.port) 41 tornado.ioloop.IOLoop.instance().start()
url.py
1 #!/usr/bin/env python 2 # coding:utf-8 3 4 import tornado.web 5 import application 6 7 url = [(r"^/(favicon\.ico)", tornado.web.StaticFileHandler, 8 dict(path=application.settings['static_path']))] 9 10 url += [(r"^/", "handlers.index.IndexHandler")] 11 12 url += [(r'^/register', "handlers.auth.RegisterHandler")] 13 url += [(r'^/login', "handlers.auth.LoginHandler")] 14 url += [(r'^/logout', "handlers.auth.LogoutHandler")] 15 url += [(r'^/changepasswd', "handlers.auth.ChangePasswdHandler")] 16 url += [(r'^/account/(\w+)', "handlers.auth.AccountHandler")]
base.py
1 #!/usr/bin/env python 2 # coding: utf-8 3 4 from datetime import date, datetime 5 import json 6 import tornado.web 7 import tornado.gen 8 9 class BaseHandler(tornado.web.RequestHandler): 10 ''' 11 所有Handler的基类 12 ''' 13 @property 14 def db(self): 15 ''' 16 数据库对象,用于操作数据库 17 ''' 18 return self.application.db 19 20 def json(self, status, info): 21 self.write({ 22 "status": status, 23 "info": info 24 }) 25 26 def get_current_user(self): 27 ''' 28 获取当前用户 29 ''' 30 return self.get_secure_cookie("user") 31 32 def get_current_permission(self): 33 ''' 34 获取当前用户是否为管理员(1--管理员) 35 ''' 36 if self.get_current_user(): 37 lst = self.db.query('''select 38 admin 39 from 40 users 41 where 42 name=%s''', self.current_user) 43 return int(lst[0].get('admin', 0)) 44 else: 45 return 0
auth.py
1 #!/usr/bin/env python 2 #-*- coding:utf-8 -*- 3 4 import tornado.web 5 import logging 6 import datetime 7 import base64 8 9 from base import BaseHandler 10 11 12 class RegisterHandler(BaseHandler): 13 14 ''' 15 注册处理类 16 ''' 17 18 def get(self, *args, **kwargs): 19 self.error = {"exists": "用户名或者邮箱已被使用!"} 20 user = None 21 error = self.get_argument("error", default="") 22 input_user = self.get_argument("user", default="") 23 input_email = self.get_argument("email", default="") 24 self.render("auth/register.htm", 25 user=user, 26 error=self.error.get(error, ""), 27 input_user=input_user, 28 input_email=input_email, 29 admin=0) 30 31 def post(self): 32 username = self.get_body_argument("input_user", default="") 33 email = self.get_body_argument("input_email", default="") 34 password = self.get_body_argument("input_passwd", default="") 35 passwd = base64.b64encode(password) 36 37 # 判断用户名或者邮箱是否已被使用 38 if not self._checkusername_action(username, email): 39 self.db.execute('''insert into users 40 ( 41 name, 42 email, 43 password, 44 image, 45 admin, 46 created_at 47 ) 48 values 49 ( 50 %s, 51 %s, 52 %s, 53 'none', 54 '0', 55 %s 56 )''', 57 username, 58 email, 59 passwd, 60 datetime.datetime.now()) 61 self.redirect("/login") 62 else: 63 self.redirect( 64 "/register?error=exists&user={0}&email={1}".format(username, email)) 65 66 def _checkusername_action(self, username, email): 67 ''' 68 检查是否有该用户 69 ''' 70 user = self.db.query( 71 "select id from users where (name=%s or email=%s)", username, email) 72 if len(user) == 0: 73 return False 74 else: 75 return True 76 77 78 class LoginHandler(BaseHandler): 79 80 ''' 81 登录处理类 82 ''' 83 84 def get(self, *args, **kwargs): 85 self.error = { 86 "not_exists": "用户名或者邮箱不存在!", 87 "disable": "该用户名已经停用,若有疑问请联系管理员!", 88 "passwd_error": "密码错误!" 89 } 90 user = None 91 error = self.get_argument("error", default="") 92 input_user = self.get_argument("user", default="") 93 self.render("auth/login.htm", 94 user=user, 95 input_user=input_user, 96 error=self.error.get(error, ""), 97 admin=0) 98 99 def post(self): 100 username = self.get_body_argument("input_user") 101 password = self.get_body_argument("input_passwd") 102 cbox_remember = self.get_body_argument("cbox_remember", default="off") 103 passwd = base64.b64encode(password) 104 105 if not self._checkusername_action(username): 106 if not self._has_cn(username): 107 self.redirect( 108 "/login?error=not_exists&user={0}".format(username)) 109 else: 110 self.redirect("/login?error=not_exists") 111 112 if not self._checkpasswd_action(username, passwd): 113 if not self._has_cn(username): 114 self.redirect( 115 "/login?error=passwd_error&user={0}".format(username)) 116 else: 117 self.redirect("/login?error=passwd_error") 118 else: 119 if self.user[0].status == 0: 120 if not self._has_cn(username): 121 self.redirect( 122 "/login?error=disable&user={0}".format(username)) 123 else: 124 self.redirect("/login?error=disable") 125 else: 126 if cbox_remember == "on": 127 self.set_secure_cookie( 128 "user", self.user[0].name, expires_days=30) 129 else: 130 self.set_secure_cookie( 131 "user", self.user[0].name, expires_days=1) 132 self.redirect("/") 133 134 def _checkusername_action(self, username): 135 ''' 136 检查是否有该用户 137 ''' 138 user = self.db.query( 139 "select id from users where (name=%s or email=%s)", username, username) 140 if len(user) == 0: 141 return False 142 else: 143 return True 144 145 def _checkpasswd_action(self, username, password): 146 ''' 147 检查用户密码是否正确 148 ''' 149 user = self.db.query( 150 "select id,name,status from users where (name=%s and password=%s)", username, password) 151 if len(user) == 0: 152 return False 153 else: 154 self.user = user 155 return True 156 157 def _has_cn(self, text): 158 ''' 159 万恶的中文 160 ''' 161 import re 162 zhPattern = re.compile(u'[\u4e00-\u9fa5]+') 163 return zhPattern.search(text) 164 165 166 class LogoutHandler(BaseHandler): 167 168 ''' 169 退出登录,清除cookie 170 ''' 171 172 def get(self): 173 self.clear_cookie('user') 174 self.redirect("/") 175 176 177 class ChangePasswdHandler(BaseHandler): 178 179 ''' 180 修改用户密码 181 ''' 182 183 @tornado.web.authenticated 184 def get(self, *args, **kwargs): 185 self.error = {"passwd_error": "密码错误!"} 186 error = self.get_argument("error", default="") 187 188 self.render("auth/changepasswd.htm", 189 user=self.current_user, 190 error=self.error.get(error, ""), 191 admin=self.get_current_permission()) 192 193 @tornado.web.authenticated 194 def post(self): 195 username = self.get_body_argument("input_user") 196 old_password = self.get_body_argument("input_old_passwd") 197 new_password = self.get_body_argument("input_new_passwd") 198 old_passwd = base64.b64encode(old_password) 199 new_passwd = base64.b64encode(new_password) 200 201 if not self._checkpasswd_action(username, old_passwd): 202 self.redirect("/changepasswd?error=passwd_error") 203 else: 204 self.db.execute('''update 205 users 206 set 207 password = %s 208 where 209 name = %s''', new_passwd, username) 210 self.clear_cookie("user") 211 self.redirect("/login") 212 213 def _checkpasswd_action(self, username, password): 214 user = self.db.query( 215 "select id,name from users where (name=%s and password=%s)", username, password) 216 if len(user) == 0: 217 return False 218 else: 219 return True 220 221 222 class AccountHandler(BaseHandler): 223 224 ''' 225 用户管理(新增用户,权限更改) 226 ''' 227 228 @tornado.web.authenticated 229 def get(self, *args, **kwargs): 230 self.render("auth/account.htm", 231 user=self.current_user, 232 admin=self.get_current_permission()) 233 234 @tornado.web.authenticated 235 def post(self, *args, **kwargs): 236 action = "_%s_action" % args[0] 237 if hasattr(self, action): 238 getattr(self, action)() 239 else: 240 self.json("fail", "no action!") 241 242 def _query_all_action(self): 243 ''' 244 查询用户表 245 ''' 246 page_record = 10 247 current_page = self.get_body_argument("current_page", default="1") 248 page_dict = dict() 249 250 try: 251 ret = self.db.query('''select count(id) as count from users''') 252 if ret[0].count%page_record == 0: 253 total_pages = ret[0].count//page_record 254 else: 255 total_pages = ret[0].count//page_record + 1 256 page_dict["total_pages"] = str(total_pages) 257 page_dict["total_count"] = str(ret[0].count) 258 ret = self.db.query('''select 259 id, 260 name, 261 email, 262 admin, 263 status 264 from 265 users 266 order by admin desc limit %s, %s''', 267 (int(current_page)-1)*page_record, page_record) 268 page_dict["current_page"] = current_page 269 page_dict["current_data"] = ret 270 self.json("success", page_dict) 271 except Exception as e: 272 self.json("error", str(e)) 273 274 def _add_user_action(self): 275 ''' 276 新增用户 277 ''' 278 username = self.get_body_argument("username", default="") 279 email = self.get_body_argument("email", default="") 280 password = self.get_body_argument("password", default="") 281 admin = self.get_body_argument("permission_id", default="2") 282 passwd = base64.b64encode(password) 283 284 # 判断用户名或者邮箱是否已被使用 285 if not self._checkusername_action(username, email): 286 self.db.execute('''insert into users 287 ( 288 name, 289 email, 290 password, 291 admin, 292 status, 293 image, 294 created_at 295 ) 296 values 297 ( 298 %s, 299 %s, 300 %s, 301 %s, 302 1, 303 'none', 304 %s 305 )''', 306 username, 307 email, 308 passwd, 309 admin, 310 datetime.datetime.now()) 311 ret = self.db.execute('''SELECT LAST_INSERT_ID()'''); 312 user_dict = dict() 313 user_dict["id"] = str(ret) 314 user_dict["admin"] = admin 315 user_dict["email"] = email 316 user_dict["status"] = "1" 317 user_dict["name"] = username 318 319 self.json("success", user_dict) 320 else: 321 self.json("fail", "exists") 322 323 def _update_user_action(self): 324 user_id = self.get_body_argument("user_id", default="") 325 admin = self.get_body_argument("permission_id", default="") 326 status_id = self.get_body_argument("status_id", default="") 327 328 try: 329 self.db.execute('''update 330 users 331 set 332 admin = %s, 333 status = %s 334 where 335 id = %s''', 336 admin, 337 status_id, 338 user_id) 339 self.json("success", "success") 340 except Exception as e: 341 self.json("error", str(e)) 342 343 def _delete_user_action(self): 344 user_id = self.get_body_argument("user_id", default="") 345 try: 346 record = self.db.query('''select id from blogs 347 where user_id = %s limit 0,1''', user_id) 348 if len(record) == 0: 349 self.db.execute('''delete from users where id = %s''', user_id) 350 self.json("success", "success") 351 else: 352 self.json("disable", "disable") 353 except Exception as e: 354 self.json("error", str(e)) 355 356 def _checkusername_action(self, username, email): 357 ''' 358 检查是否有该用户 359 ''' 360 user = self.db.query( 361 "select id from users where (name=%s or email=%s)", username, email) 362 if len(user) == 0: 363 return False 364 else: 365 return True