Browse Source

user page done

laiwei 8 years ago
parent
commit
0560a8f338

+ 6 - 0
rrd/model/user.py

@@ -23,3 +23,9 @@ class User(object):
         return "<UserProfile id=%s, name=%s, cnname=%s>" \
                 % (self.id, self.name, self.cnname)
     __str__ = __repr__
+
+    def is_root(self):
+        return str(self.role) == "2"
+
+    def is_admin(self):
+        return str(self.role) == "1"

+ 93 - 0
rrd/static/css/g.css

@@ -0,0 +1,93 @@
+body, input, div, span, h1, h2, h3, h4, h5, table, th, td, ul, li, dl, dt, dd, a {
+	font-family: 'verdana', 'Microsoft YaHei', 'Consolas', 'Deja Vu Sans Mono', 'Bitstream Vera Sans Mono';
+}
+.text-center {
+  text-align: center;
+}
+
+ul.catlist { list-style: none; margin: 0; padding: 0; }
+ul.catlist li { display: inline; }
+ul.catlist li:after { content: "・"; }
+ul.catlist li:last-child:after { content: ""; }
+
+.cut-line {
+    margin: 0 5px;
+    color: #D6D6D6;
+}
+
+.font-bold {
+	font-weight: bold;
+}
+
+.red {
+    color: red;
+}
+
+.orange {
+    color: orange;
+}
+
+.green {
+    color: green;
+}
+
+.blue {
+    color: blue;
+}
+
+.gray {
+    color: #999 !important;
+}
+
+.mt0 {
+    margin-top: 0px;
+}
+
+.mt10 {
+    margin-top: 10px !important;
+}
+
+.mt20 {
+    margin-top: 20px !important;
+}
+
+.mt30 {
+    margin-top: 30px !important;
+}
+
+.mb20 {
+    margin-bottom: 20px !important;
+}
+
+.thin-border {
+    padding: 10px;
+    line-height: 1;
+    border: 1px solid #ddd;
+    -webkit-border-radius: 4px;
+    -moz-border-radius: 4px;
+    border-radius: 4px;
+    -webkit-box-shadow: 0 1px 1px rgba(0, 0, 0, 0.075);
+    -moz-box-shadow: 0 1px 1px rgba(0, 0, 0, 0.075);
+    box-shadow: 0 1px 1px rgba(0, 0, 0, 0.075);
+    background-color: #fff;
+}
+
+.links {
+	margin:0 auto;
+	width: 360px;
+	line-height: 30px; 
+}
+
+.links .link-head {
+	margin-top: 10px;
+}
+
+.us {
+    line-height: 28px;
+}
+
+code.users {
+    font-family:'verdana','Consolas';
+    color: green;
+    line-height: 26px;
+}

+ 152 - 0
rrd/static/js/g.js

@@ -98,6 +98,8 @@ function change_password() {
 function register() {
 	$.post('/auth/register', {
 		'name' : $('#name').val(),
+		'cnname' : $('#cnname').val(),
+		'email' : $('#email').val(),
 		'password' : $("#password").val(),
 		'repeat_password' : $("#repeat_password").val()
 	}, function(json) {
@@ -110,3 +112,153 @@ function register() {
 		}
 	}, "json");
 }
+
+function query_user() {
+	var query = $("#query").val();
+	location.href = "/user/list?query=" + query;
+}
+
+function query_team() {
+	var query = $("#query").val();
+	location.href = "/team/list?query=" + query;
+}
+
+function create_user() {
+	$.post('/admin/user/create', {
+		'name' : $("#name").val(),
+		'cnname' : $("#cnname").val(),
+		'email' : $("#email").val(),
+		'phone' : $("#phone").val(),
+		'im' : $("#im").val(),
+		'qq' : $("#qq").val(),
+		'password' : $("#password").val()
+	}, function(json) {
+		if (json.msg.length > 0) {
+			err_message_quietly(json.msg);
+		} else {
+			ok_message_quietly("create user successfully");
+		}
+	}, "json");
+}
+
+function edit_user(id) {
+	$.post('/admin/user/'+id+'/edit', {
+        'id': id,
+		'cnname' : $("#cnname").val(),
+		'email' : $("#email").val(),
+		'phone' : $("#phone").val(),
+		'im' : $("#im").val(),
+		'qq' : $("#qq").val()
+	}, function(json) {
+		if (json.msg.length > 0) {
+			err_message_quietly(json.msg);
+		} else {
+			ok_message_quietly("更新成功:)");
+		}
+	}, "json");
+}
+
+function reset_password(id) {
+	$.post('/admin/user/'+id+'/chpwd', {
+		'password' : $("#password").val()
+	}, function(json) {
+		if (json.msg.length > 0) {
+			err_message_quietly(json.msg);
+		} else {
+			ok_message_quietly("密码重置成功:)");
+		}
+	}, "json");
+}
+
+function create_team() {
+	$.post('/admin/team/create', {
+		'name' : $("#name").val(),
+		'resume' : $("#resume").val(),
+		'users' : $("#users").val()
+	}, function(json) {
+		if (json.msg.length > 0) {
+			err_message_quietly(json.msg);
+		} else {
+			ok_message_quietly('create team successfully');
+		}
+	}, "json");
+}
+
+function edit_team(tid) {
+	$.post('/admin/team/'+tid+'/edit', {
+		'resume' : $("#resume").val(),
+		'users' : $("#users").val(),
+		'id': tid
+	}, function(json) {
+		if (json.msg.length > 0) {
+			err_message_quietly(json.msg);
+		} else {
+			ok_message_quietly('edit team successfully');
+		}
+	}, "json");
+}
+
+function delete_user(uid) {
+	my_confirm("真的要删除么?通常只有离职的时候才需要删除", [ '确定', '取消' ], function() {
+		$.post('/admin/user/'+uid+'/delete', {
+		}, function(json) {
+			if (json.msg.length > 0) {
+				err_message_quietly(json.msg);
+			} else {
+				ok_message_quietly('delete user successfully', function() {
+					location.reload();
+				});
+			}
+		}, "json");
+	}, function() {
+	});
+}
+
+function delete_team(id) {
+	my_confirm("真的真的要删除么?", [ '确定', '取消' ], function() {
+		$.get('/admin/team/'+id+'/delete', {}, function(json) {
+			if (json.msg.length > 0) {
+				err_message_quietly(json.msg);
+			} else {
+				ok_message_quietly('delete team successfully', function() {
+					location.reload();
+				});
+			}
+		});
+	}, function() {
+	}, "json");
+}
+
+function set_role(uid, obj) {
+	var role = obj.checked ? '1' : '0';
+	$.post('/admin/user/'+uid+'/role', {
+		'role' : role
+	}, function(json) {
+		if (json.msg.length > 0) {
+			err_message_quietly(json.msg);
+			location.reload();
+		} else {
+			if (role == '1') {
+				ok_message_quietly('成功设置为管理员:)');
+			} else if (role == '0') {
+				ok_message_quietly('成功取消管理员权限:)');
+			}
+		}
+	}, "json");
+}
+
+function user_detail(uid) {
+	$("#user_detail_div").load("/user/detail?id=" + uid);
+	$.layer({
+		type : 1,
+		shade : [ 0.5, '#000' ],
+		shadeClose : true,
+		closeBtn : [ 0, true ],
+		area : [ '450px', '240px' ],
+		title : false,
+		border : [ 0 ],
+		page : {
+			dom : '#user_detail_div'
+		}
+	}, "json");
+}

+ 10 - 0
rrd/templates/auth/base.html

@@ -0,0 +1,10 @@
+{% extends "base.html" %}
+
+{%block head_js%}
+    {{super()}}
+    <script src="{{url_for('static', filename='js/g.js')}}"></script>
+{%endblock%}
+
+{%block navbar%}
+  {%include "navbar.html"%}
+{%endblock%}

+ 1 - 6
rrd/templates/auth/login.html

@@ -1,4 +1,4 @@
-{% extends "base.html" %}
+{% extends "auth/base.html" %}
 
 {%block head_js%}
     {{super()}}
@@ -13,11 +13,6 @@
     });
     </script>
 
-    <script src="{{url_for('static', filename='js/g.js')}}"></script>
-{%endblock%}
-
-{%block navbar%}
-  {%include "navbar.html"%}
 {%endblock%}
 
 {% block container_outer %}

+ 52 - 0
rrd/templates/auth/register.html

@@ -0,0 +1,52 @@
+{% extends "auth/base.html" %}
+
+{% block container_outer %}
+<div id="container" class="container-fluid">
+	<div class="row">
+		<div class="col-md-12">
+
+			<div style="margin: 0 auto; max-width: 400px;">
+				<div class="panel panel-default">
+					<div class="panel-heading">
+						<h3 class="panel-title">Sign up</h3>
+					</div>
+					<div class="panel-body">
+
+						<form class="form-sign" role="form">
+							<div class="form-group">
+								<label for="name">Login Name(a-zA-Z0-9_.):</label> <input
+									type="text" id="name" class="form-control" required autofocus />
+							</div>
+							<div class="form-group">
+								<label for="cnname">中文名:</label> <input
+									type="text" id="cnname" class="form-control" required autofocus />
+							</div>
+							<div class="form-group">
+								<label for="email">Email:</label> <input
+									type="text" id="email" class="form-control" required autofocus />
+							</div>
+							<div class="form-group">
+								<label for="password">Password:</label> <input type="password"
+									id="password" class="form-control" required />
+							</div>
+							<div class="form-group">
+								<label for="repeat_password">Repeat Password:</label> <input
+									type="password" id="repeat_password" class="form-control"
+									required />
+							</div>
+							<button class="btn btn-default btn-block" type="button"
+								onclick="register();">Sign up</button>
+
+							<div style="margin-top: 10px">
+								has account already? <a href="/auth/login">sign in</a>
+							</div>
+						</form>
+
+					</div>
+				</div>
+			</div>
+
+		</div>
+	</div>
+</div>
+{%endblock%}

+ 2 - 1
rrd/templates/base.html

@@ -8,7 +8,7 @@
     {% endblock %}
 
     <title>
-        {%block title%}Falcon-Dashboard{%endblock%}
+        {%block title%}Falcon+{%endblock%}
     </title>
 
     {% block css %}
@@ -19,6 +19,7 @@
         <link href="{{url_for('static', filename='bootstrap-datetimepicker/css/bootstrap-datetimepicker.min.css')}}" rel="stylesheet"> </link>
         <link rel="stylesheet" href="{{url_for('static', filename='bootstrap-tokenfield/css/bootstrap-tokenfield.min.css')}}">
         <link href="/static/css/base.css?v=0.1.0" rel="stylesheet">
+        <link href="{{url_for('static', filename='css/g.css')}}" rel="stylesheet">
         <style>
             body {
                 font-size:12px;

+ 1 - 1
rrd/templates/base_ng.html

@@ -8,7 +8,7 @@
     {% endblock %}
 
     <title>
-        {%block title%}Falcon-Dashboard{%endblock%}
+        {%block title%}Falcon+{%endblock%}
     </title>
 
     {% block css %}

+ 1 - 1
rrd/templates/navbar.html

@@ -3,7 +3,7 @@
     <div class="navbar-header">
         <button type="button" class="navbar-toggle" data-toggle="collapse" data-target=".navbar-ex1-collapse">
         </button>
-        <a class="navbar-brand" href="/">Falcon-Dashboard</a>
+        <a class="navbar-brand" href="/">Falcon+</a>
     </div>
     <div class="collapse navbar-collapse navbar-ex1-collapse">
         <ul class="nav navbar-nav navbar-right">

+ 65 - 0
rrd/templates/user/create.html

@@ -0,0 +1,65 @@
+{% extends "user/base.html" %}
+
+{% block container_outer %}
+<div id="container" class="container-fluid">
+
+	<div class="row">
+		<div class="col-md-12">
+			<div style="margin: 0 auto; max-width: 400px;">
+
+				<ol class="breadcrumb">
+					<li><a href="/">首页</a></li>
+					<li><a href="/user/list">通讯录</a></li>
+					<li class="active">创建用户</li>
+				</ol>
+
+				<div class="panel panel-default">
+					<div class="panel-heading">
+						<h3 class="panel-title">Create User</h3>
+					</div>
+					<div class="panel-body">
+						<div class="form-group">
+							<label for="name">* 账号(a-zA-Z0-9_-.):</label> <input type="text"
+							id="name" class="form-control" />
+						</div>
+						<div class="form-group">
+							<label for="password">* 密码:</label> <input
+							type="password" name="password" id="password" class="form-control" />
+						</div>
+						<div class="form-group">
+							<label for="name">中文名(可以附带上部门、工位号之类的做详细区分):</label> <input
+							type="text" name="cnname" id="cnname" class="form-control" />
+						</div>
+						<div class="form-group">
+							<label for="email">邮箱:</label> <input type="email" name="email"
+							id="email" class="form-control" />
+						</div>
+						<div class="form-group">
+							<label for="phone">手机:</label> <input type="text" name="phone"
+							id="phone" class="form-control" />
+						</div>
+						<div class="form-group">
+							<label for="name">IM(内部通讯工具账号,比如百度hi、米聊):</label> <input
+							type="text" name="im" id="im" class="form-control" />
+						</div>
+						<div class="form-group">
+							<label for="name">QQ:</label> <input type="text" name="qq" id="qq"
+							class="form-control" />
+						</div>
+						<button type="button" class="btn btn-default" onclick="create_user();">
+							<span class="glyphicon glyphicon-floppy-disk"></span>
+							创建
+						</button>
+						<a href="/me/users" class="btn btn-default">
+							<span class="glyphicon glyphicon-arrow-left"></span>
+							返回
+						</a>
+					</div>
+				</div>
+
+			</div>
+		</div>
+	</div>
+
+</div>
+{%endblock%}

+ 73 - 0
rrd/templates/user/edit.html

@@ -0,0 +1,73 @@
+{% extends "user/base.html" %}
+
+{% block container_outer %}
+<div id="container" class="container-fluid">
+
+	<div class="row">
+		<div class="col-md-12">
+			<div style="margin: 0 auto; max-width: 400px;">
+
+				<div class="panel panel-default">
+					<div class="panel-heading">
+						<h3 class="panel-title">Profile of {{user.name}}</h3>
+					</div>
+					<div class="panel-body">
+						<div class="form-group">
+							<label for="name">中文名(可以附带上部门、工位号之类的做详细区分):</label> <input
+							type="text" name="cnname" id="cnname" class="form-control"
+							value="{{user.cnname}}" />
+						</div>
+						<div class="form-group">
+							<label for="email">邮箱:</label> <input type="email" name="email"
+							id="email" class="form-control" value="{{user.email}}" />
+						</div>
+						<div class="form-group">
+							<label for="phone">手机:</label> <input type="text" name="phone"
+							id="phone" class="form-control" value="{{user.phone}}" />
+						</div>
+						<div class="form-group">
+							<label for="name">IM(内部通讯工具账号,比如百度hi、米聊):</label> <input
+							type="text" name="im" id="im" class="form-control"
+							value="{{user.im}}" />
+						</div>
+						<div class="form-group">
+							<label for="name">QQ:</label> <input type="text" name="qq" id="qq"
+							class="form-control" value="{{user.qq}}" />
+						</div>
+                        <button type="button" class="btn btn-default" id="update_profile" onclick="edit_user('{{user.id}}');">
+							<span class="glyphicon glyphicon-floppy-disk"></span>
+							更新
+						</button>
+						<a href="/me/users" class="btn btn-default">
+							<span class="glyphicon glyphicon-arrow-left"></span>
+							返回
+						</a>
+					</div>
+				</div>
+
+				<div class="panel panel-default">
+					<div class="panel-heading">
+						<h3 class="panel-title">Reset Password</h3>
+					</div>
+					<div class="panel-body">
+						<div class="form-group">
+							<label for="password">输入密码:</label> <input type="password"
+							name="password" id="password" class="form-control" />
+						</div>
+						<button type="submit" class="btn btn-default" onclick="reset_password('{{user.id}}');">
+							<span class="glyphicon glyphicon-floppy-disk"></span>
+							更新
+						</button>
+						<a href="/user/list" class="btn btn-default">
+							<span class="glyphicon glyphicon-arrow-left"></span>
+							返回
+						</a>
+					</div>
+				</div>
+
+			</div>
+		</div>
+	</div>
+
+</div>
+{%endblock%}

+ 98 - 0
rrd/templates/user/list.html

@@ -0,0 +1,98 @@
+{% extends "user/base.html" %}
+
+{%block head_js%}
+    {{super()}}
+
+    <script>
+    $(function() {
+        $("#query").keypress(function(e) {
+            var key = e.which;
+            if (key == 13) {
+                query_user();
+            }
+        });
+    });
+    </script>
+
+{%endblock%}
+
+{% block container_outer %}
+<div id="container" class="container-fluid">
+	<div class="row">
+		<div class="col-md-12">
+
+			<div style="margin: 0 auto; max-width: 400px;">
+
+				<ol class="breadcrumb">
+					<li><a href="/">首页</a></li>
+					<li class="active">通讯录</li>
+				</ol>
+
+				<div class="form-inline mb20" role="form">
+					<div class="form-group">
+						<input type="text" value="{{query_term}}" class="form-control" id="query"
+						placeholder="name or email">
+					</div>
+					<button type="button" onclick="query_user();" class="btn btn-default">
+						<span class="glyphicon glyphicon-search"></span>
+						Search
+					</button>
+
+                    {%if g.user.is_admin() or g.user.is_root()%}
+                    <a href="/admin/user/create" class="btn btn-default pull-right">
+                            <span class="glyphicon glyphicon-plus"></span>
+                            Add
+                    </a>
+                    {%endif%}
+
+				</div>
+
+				<div class="us">
+                    {%for user in users%}
+					<div class="u">
+                        {%if g.user.is_root() %}
+						<div class="pull-right">
+                            {%if user.is_root()%}
+                            root
+                            {%elif user.is_admin()%}
+							<input type="checkbox" checked="checked" onclick="set_role('{{user.id}}', this);">
+							管理员
+							{%else%}
+							<input type="checkbox" onclick="set_role('{{user.id}}', this);">
+							管理员
+							{%endif%}
+						</div>
+						{%endif%}
+
+                        登录账号:{{user.name}}, 中文名:{{user.cnname}}
+						<a href="/user/about/{{user.id}}" target="_blank" style="text-decoration:none;">
+							<span class="glyphicon glyphicon-qrcode"></span>
+						</a>
+						<br>
+						邮箱: {{user.email}}<br>
+						手机: {{user.phone}}<br>
+						IM:{{user.im}}, QQ:{{user.qq}}
+
+                        {%if g.user.is_root() or g.user.is_admin() %}
+						<div class="pull-right">
+                            <a href="/admin/user/{{user.id}}/edit" class="orange" style="text-decoration:none;">
+								<span class="glyphicon glyphicon-edit"></span>
+							</a>
+							<span class="cut-line">¦</span>
+							<a href="javascript:delete_user('{{user.id}}');" class="orange" style="text-decoration:none;">
+								<span class="glyphicon glyphicon-trash"></span>
+							</a>
+						</div>
+						{%endif%}
+
+						<hr>
+					</div>
+					{%endfor%}
+				</div>
+
+			</div>
+
+		</div>
+	</div>
+</div>
+{%endblock%}

+ 43 - 5
rrd/view/auth.py

@@ -1,7 +1,9 @@
 #-*- coding:utf-8 -*-
-from flask import request, g, abort, render_template
+from flask import request, g, abort, render_template, redirect
 from rrd import app
+from rrd import config
 from rrd.view import utils as view_utils
+from rrd.view.utils import require_login
 
 import requests
 import json
@@ -9,6 +11,9 @@ import json
 @app.route("/auth/login", methods=["GET", "POST"])
 def auth_login():
     if request.method == "GET":
+        if g.user:
+            return redirect("/")
+
         return render_template("auth/login.html", **locals())
 
     if request.method == "POST":
@@ -35,15 +40,48 @@ def auth_login():
             ret["msg"] = str(e)
             return json.dumps(ret)
 
-@app.route("/auth/logout", methods=["POST",])
+@app.route("/auth/logout", methods=["GET",])
+@require_login()
 def auth_logout():
-    if request.method == "POST":
-        pass
+    if request.method == "GET":
+        view_utils.logout_user(g.user_token)
+        return redirect("/auth/login")
 
 @app.route("/auth/register", methods=["GET", "POST"])
 def auth_register():
     if request.method == "GET":
+        if g.user:
+            return redirect("/auth/login")
         return render_template("auth/register.html", **locals())
 
     if request.method == "POST":
-        pass
+        ret = {"msg":""}
+
+        name = request.form.get("name", "")
+        cnname = request.form.get("cnname", "")
+        email = request.form.get("email", "")
+        password = request.form.get("password", "")
+        repeat_password = request.form.get("repeat_password", "")
+
+        if not name or not password or not email or not cnname:
+            ret["msg"] = "not all form item entered"
+            return json.dumps(ret)
+
+        if password != repeat_password:
+            ret["msg"] = "repeat password not equal"
+            return json.dumps(ret)
+
+        h = {"Content-type":"application/json"}
+        d = {
+            "name": name,
+            "cnname": cnname,
+            "email": email,
+            "password": password,
+        }
+
+        r = requests.post("%s/user/create" %(config.API_ADDR,), \
+                data=json.dumps(d), headers=h)
+        if r.status_code != 200:
+            ret['msg'] = r.text
+
+        return json.dumps(ret)

+ 175 - 6
rrd/view/user.py

@@ -5,6 +5,7 @@ from rrd import app
 from rrd import corelib
 from rrd import config
 from rrd.view.utils import require_login
+from rrd.model.user import User
 
 @app.route("/user/about/<username>", methods=["GET",])
 @require_login()
@@ -18,7 +19,7 @@ def user_info(username):
         return render_template("user/about.html", **locals())
 
 @app.route("/user/profile", methods=["GET", "POST"])
-@require_login()
+@require_login(json_msg = "please login first")
 def user_profile():
     if request.method == "GET":
         current_user = g.user
@@ -52,7 +53,7 @@ def user_profile():
         return json.dumps(ret)
 
 @app.route("/user/chpwd", methods=["POST", ])
-@require_login()
+@require_login(json_msg = "please login first")
 def user_change_passwd():
     if request.method == "POST":
         ret = {"msg": ""}
@@ -81,16 +82,184 @@ def user_change_passwd():
 
         return json.dumps(ret)
         
-
+##admin
 @app.route("/user/list", methods=["GET",])
+@require_login()
 def user_list():
     if request.method == "GET":
+        query_term = request.args.get("query", "")
+        users = []
+        if query_term:
+            d = {
+                    "q": query_term,
+                    "limit": g.limit or 50,
+                    "page": g.page or 1,
+            }
+            r = corelib.auth_requests(g.user_token, "GET", "%s/user/users" \
+                    %(config.API_ADDR,), params=d)
+            if r.status_code != 200:
+                abort(400, "request to api fail: %s" %(r.text,))
+            j = r.json() or []
+            for x in j:
+                u = User(x["id"], x["name"], x["cnname"], x["email"], x["phone"], x["im"], x["qq"], x["role"])
+                users.append(u)
+
         return render_template("user/list.html", **locals())
 
-@app.route("/user/create", methods=["GET", "POST"])
-def user_create():
+@app.route("/admin/user/create", methods=["GET", "POST"])
+@require_login()
+def admin_user_create():
     if request.method == "GET":
+        if not (g.user.is_admin() or g.user.is_root()):
+            abort(403, "no such privilege")
         return render_template("user/create.html", **locals())
     
     if request.method == "POST":
-        pass
+        ret = {"msg":""}
+
+        if not (g.user.is_admin() or g.user.is_root()):
+            ret["msg"] = "no such privilege"
+            return json.dumps(ret)
+
+        name = request.form.get("name", "")
+        cnname = request.form.get("cnname", "")
+        password = request.form.get("password", "")
+        email = request.form.get("email", "")
+        phone = request.form.get("phone", "")
+        im = request.form.get("im", "")
+        qq = request.form.get("qq", "")
+
+        if not name or not cnname or not password or not email:
+            ret["msg"] = "not all form item entered"
+            return json.dumps(ret)
+        
+        h = {"Content-type": "application/json"}
+        d = {
+                "name": name, "cnname": cnname, "password": password, "email": email, "phone": phone, "im": im, "qq": qq,
+        }
+        r = corelib.auth_requests(g.user_token ,"POST", "%s/user/create" %(config.API_ADDR,), \
+                data=json.dumps(d), headers=h)
+        if r.status_code != 200:
+            ret["msg"] = r.text
+
+        return json.dumps(ret)
+
+
+
+@app.route("/admin/user/<int:user_id>/edit", methods=["GET", "POST"])
+@require_login()
+def admin_user_edit(user_id):
+    if request.method == "GET":
+        if not (g.user.is_admin() or g.user.is_root()):
+            abort(403, "no such privilege")
+
+        h = {"Content-type":"application/json"}
+        r = corelib.auth_requests(g.user_token ,"GET", "%s/user/u/%s" %(config.API_ADDR, user_id), headers=h)
+        if r.status_code != 200:
+            abort(r.status_code, r.text)
+        j = r.json()
+        user = j and User(j["id"], j["name"], j["cnname"], j["email"], j["phone"], j["im"], j["qq"], j["role"])
+
+        if not user:
+            abort(404, "no such user where id=%s" % user_id)
+
+        return render_template("user/edit.html", **locals())
+    
+    if request.method == "POST":
+        ret = {"msg":""}
+
+        if not (g.user.is_admin() or g.user.is_root()):
+            ret["msg"] = "no such privilege"
+            return json.dumps(ret)
+
+        user_id = request.form.get("id", "")
+        cnname = request.form.get("cnname", "")
+        email = request.form.get("email", "")
+        phone = request.form.get("phone", "")
+        im = request.form.get("im", "")
+        qq = request.form.get("qq", "")
+
+        h = {"Content-type": "application/json"}
+        d = {
+                "user_id": user_id, "cnname": cnname, "email": email, "phone": phone, "im": im, "qq": qq,
+        }
+        r = corelib.auth_requests(g.user_token ,"PUT", "%s/admin/change_user_profile" %(config.API_ADDR,), \
+                data=json.dumps(d), headers=h)
+        if r.status_code != 200:
+            ret["msg"] = r.text
+
+        return json.dumps(ret)
+
+@app.route("/admin/user/<int:user_id>/chpwd", methods=["POST", ])
+@require_login(json_msg="login first")
+def admin_user_change_password(user_id):
+    if request.method == "POST":
+        ret = {"msg": ""}
+
+        if not (g.user.is_admin or g.user.is_root()):
+            ret["msg"] = "you do not have permissions"
+            return json.dumps(ret)
+
+        password = request.form.get("password")
+        if not password:
+            ret["msg"] = "no password entered"
+            return json.dumps(ret)
+
+        h = {"Content-type": "application/json"}
+        d = {
+                "user_id": user_id, "password": password,
+        }
+        r = corelib.auth_requests(g.user_token ,"PUT", "%s/admin/change_user_passwd" %(config.API_ADDR,), \
+                data=json.dumps(d), headers=h)
+        if r.status_code != 200:
+            ret["msg"] = r.text
+
+        return json.dumps(ret)
+
+
+@app.route("/admin/user/<int:user_id>/role", methods=["POST", ])
+@require_login(json_msg="login first")
+def admin_user_change_role(user_id):
+    if request.method == "POST":
+        ret = {"msg": ""}
+
+        if not (g.user.is_admin or g.user.is_root()):
+            ret["msg"] = "you do not have permissions"
+            return json.dumps(ret)
+
+        role = str(request.form.get("role", ""))
+        if not role or role not in ['1', '0']:
+            ret["msg"] = "invalid role"
+            return json.dumps(ret)
+
+        admin = "yes" if role == '1' else "no"
+
+        h = {"Content-type":"application/json"}
+        d = {"admin": admin, "user_id": int(user_id)}
+
+        r = corelib.auth_requests(g.user_token, "PUT", "%s/admin/change_user_role" \
+                %(config.API_ADDR,), data=json.dumps(d), headers=h)
+        if r.status_code != 200:
+            ret["msg"] = r.text
+
+        return json.dumps(ret)
+
+@app.route("/admin/user/<int:user_id>/delete", methods=["POST", ])
+@require_login(json_msg="login first")
+def admin_user_delete(user_id):
+    if request.method == "POST":
+        ret = {"msg": ""}
+
+        if not (g.user.is_admin or g.user.is_root()):
+            ret["msg"] = "you do not have permissions"
+            return json.dumps(ret)
+
+        h = {"Content-type":"application/json"}
+        d = {"user_id": int(user_id)}
+
+        r = corelib.auth_requests(g.user_token, "DELETE", "%s/admin/delete_user" \
+                %(config.API_ADDR,), data=json.dumps(d), headers=h)
+        if r.status_code != 200:
+            ret["msg"] = r.text
+
+        return json.dumps(ret)

+ 9 - 5
rrd/view/utils.py

@@ -10,15 +10,19 @@ from rrd import corelib
 from rrd.utils import randbytes
 from rrd.model.user import User, UserToken
 
-def require_login(msg="please login first", redir=""):
+def require_login(redir="/auth/login", json_msg="", html_msg=""):
     def _(f):
         @wraps(f)
         def __(*a, **kw):
             if not g.user:
                 if redir:
-                    return redirect(redir or "/")
+                    return redirect(redir)
+                elif json_msg:
+                    return json.dumps({"msg": json_msg})
+                elif html_msg:
+                    return abort(403, html_msg)
                 else:
-                    return json.dumps({"msg": msg})
+                    return abort(403, "please login first")
             return f(*a, **kw)
         return __
     return _
@@ -56,9 +60,9 @@ def logout_user(user_token):
     if not user_token:
         return 
 
-    r = auth_requests(user_token, "POST", "%s/user/logout" %config.API_ADDR)
+    r = corelib.auth_requests(user_token, "GET", "%s/user/logout" %config.API_ADDR)
     if r.status_code != 200:
-        raise Exception("%s:%s", r.status_code, r.text)
+        raise Exception("%s:%s" %(r.status_code, r.text))
     clear_user_cookie(session)
 
 def login_user(name, password):