Merge remote-tracking branch 'upstream/master' into external_login

This commit is contained in:
zhongyehong 2016-10-29 17:47:02 +08:00
commit c41771e0b7
12 changed files with 196 additions and 173 deletions

View File

@ -65,7 +65,7 @@ First copy docklet.conf.template to get docklet.conf.
Pay attention to the following settings: Pay attention to the following settings:
- NETWORK_DEVICE : the network interface to use. - NETWORK_DEVICE : the network interface to use.
- ETCD : the etcd server address. For distributed muli hosts - ETCD : the etcd server address. For distributed multi hosts
environment, it should be one of the ETCD public server address. environment, it should be one of the ETCD public server address.
For single host environment, the default value should be OK. For single host environment, the default value should be OK.
- STORAGE : using disk or file to storage persistent data, for - STORAGE : using disk or file to storage persistent data, for
@ -127,7 +127,7 @@ The master logs are in **FS_PREFIX/local/log/docklet-master.log** and
Worker needs a basefs image to create containers. Worker needs a basefs image to create containers.
You can create such an image with `lxc-create -n test -t download`, You can create such an image with `lxc-create -n test -t download`,
then copy the rootfs to **FS_PREFIX/local**, and renamed `rootfs` then copy the rootfs to **FS_PREFIX/local**, and rename `rootfs`
to `basefs`. to `basefs`.
Note the `jupyerhub` package must be installed for this image. And the Note the `jupyerhub` package must be installed for this image. And the
@ -138,9 +138,9 @@ You can check and run `tools/update-basefs.sh` to update basefs.
Run `bin/docklet-worker start`, will start worker in background. Run `bin/docklet-worker start`, will start worker in background.
You can check the daemon status by running `bin/docklet-worker status` You can check the daemon status by running `bin/docklet-worker status`.
The log is in **FS_PREFIX/local/log/docklet-worker.log** The log is in **FS_PREFIX/local/log/docklet-worker.log**.
Currently, the worker must be run after the master has been started. Currently, the worker must be run after the master has been started.

View File

@ -1,3 +1,4 @@
import threading,datetime,random,time
from model import db,User,ApplyMsg from model import db,User,ApplyMsg
from userManager import administration_required from userManager import administration_required
@ -54,3 +55,28 @@ class ApplicationMgr:
applymsg.status = "Rejected" applymsg.status = "Rejected"
db.session.commit() db.session.commit()
return {"success":"true"} return {"success":"true"}
class ApprovalRobot(threading.Thread):
def __init__(self,maxtime=3600):
threading.Thread.__init__(self)
self.stop = False
self.interval = 20
self.maxtime = maxtime
def stop(self):
self.stop = True
def run(self):
while not self.stop:
applymsgs = ApplyMsg.query.filter_by(status="Processing").all()
for msg in applymsgs:
secs = (datetime.datetime.now() - msg.time).seconds
ranint = random.randint(self.interval,self.maxtime)
if secs >= ranint:
msg.status = "Agreed"
user = User.query.filter_by(username=msg.username).first()
if user is not None:
user.beans += msg.number
db.session.commit()
time.sleep(self.interval)

View File

@ -42,13 +42,15 @@ def login_required(func):
@wraps(func) @wraps(func)
def wrapper(*args, **kwargs): def wrapper(*args, **kwargs):
global G_usermgr global G_usermgr
logger.info ("get request, path: %s" % request.path)
token = request.form.get("token", None) token = request.form.get("token", None)
if (token == None): if (token == None):
logger.info ("get request without token, path: %s" % request.path)
return json.dumps({'success':'false', 'message':'user or key is null'}) return json.dumps({'success':'false', 'message':'user or key is null'})
cur_user = G_usermgr.auth_token(token) cur_user = G_usermgr.auth_token(token)
if (cur_user == None): if (cur_user == None):
logger.info ("get request with an invalid token, path: %s" % request.path)
return json.dumps({'success':'false', 'message':'token failed or expired', 'Unauthorized': 'True'}) return json.dumps({'success':'false', 'message':'token failed or expired', 'Unauthorized': 'True'})
logger.info ("get request, user: %s, path: %s" % (cur_user.username, request.path))
return func(cur_user, cur_user.username, request.form, *args, **kwargs) return func(cur_user, cur_user.username, request.form, *args, **kwargs)
return wrapper return wrapper
@ -64,6 +66,47 @@ def beans_check(func):
return wrapper return wrapper
# def inside_ip_required(func):
# @wraps(func)
# def wrapper(*args, **kwargs):
# global G_usermgr
# global G_vclustermgr
# #cur_user = G_usermgr.find_by_ip(request.remote_addr)
# cur_user = G_usermgr.auth_token(G_usermgr.auth('username', 'password')['data']['token'])
# if (cur_user == None):
# logger.info ("get request with an invalid ip, path: %s" % request.path)
# return json.dumps({'success':'false', 'message':'invalid ip address', 'Unauthorized': 'True'})
# #cluster_info = G_vclustermgr.find_by_ip(cur_user.username, request.remote_addr)
# cluster_filename = '/opt/docklet/global/users/liupd/clusters/asdf'
# cluster_file = open(cluster_filename,'r')
# cluster_info = json.loads(cluster_file.read())
# cluster_file.close()
# cluster_info['name'] = 'asdf'
# logger.info ("get request with ip, user: %s, ip: %s ,path: %s" % (cur_user.username, request.remote_addr, request.path))
# return func(cur_user, cluster_info, request.form, *args, **kwargs)
#
# return wrapper
def worker_ip_required(func):
@wraps(func)
def wrapper(*args, **kwargs):
global G_nodemgr
workers = G_nodemgr.get_rpcs()
ip = request.remote_addr
flag = False
for worker in workers:
workerip = G_nodemgr.rpc_to_ip(worker)
#logger.info(str(ip) + " " + str(workerip))
if ip == '127.0.0.1' or ip == '0.0.0.0' or ip == workerip:
flag = True
break
if not flag:
return json.dumps({'success':'false','message':'Worker\'s ip is required!'})
else:
return func(*args, **kwargs)
return wrapper
@app.route("/login/", methods=['POST']) @app.route("/login/", methods=['POST'])
def login(): def login():
global G_usermgr global G_usermgr
@ -175,6 +218,7 @@ def scaleout_cluster(cur_user, user, form):
global G_usermgr global G_usermgr
global G_vclustermgr global G_vclustermgr
clustername = form.get('clustername', None) clustername = form.get('clustername', None)
logger.info ("scaleout: %s" % form)
if (clustername == None): if (clustername == None):
return json.dumps({'success':'false', 'message':'clustername is null'}) return json.dumps({'success':'false', 'message':'clustername is null'})
logger.info("handle request : scale out %s" % clustername) logger.info("handle request : scale out %s" % clustername)
@ -288,9 +332,12 @@ def list_cluster(cur_user, user, form):
return json.dumps({'success':'false', 'action':'list cluster', 'message':clusterlist}) return json.dumps({'success':'false', 'action':'list cluster', 'message':clusterlist})
@app.route("/cluster/stopall/",methods=['POST']) @app.route("/cluster/stopall/",methods=['POST'])
@login_required @worker_ip_required
def stopall_cluster(cur_user, user, form): def stopall_cluster():
global G_vclustermgr global G_vclustermgr
user = request.form.get('username',None)
if user is None:
return json.dumps({'success':'false', 'message':'User is required!'})
logger.info ("handle request : stop all clusters for %s" % user) logger.info ("handle request : stop all clusters for %s" % user)
[status, clusterlist] = G_vclustermgr.list_clusters(user) [status, clusterlist] = G_vclustermgr.list_clusters(user)
if status: if status:
@ -853,6 +900,35 @@ def resetall_system(cur_user, user, form):
return json.dumps({'success':'false', 'message': message}) return json.dumps({'success':'false', 'message': message})
return json.dumps(result) return json.dumps(result)
# @app.route("/inside/cluster/scaleout/", methods=['POST'])
# @inside_ip_required
# def inside_cluster_scalout(cur_user, cluster_info, form):
# global G_usermgr
# global G_vclustermgr
# clustername = cluster_info['name']
# logger.info("handle request : scale out %s" % clustername)
# image = {}
# image['name'] = form.get("imagename", None)
# image['type'] = form.get("imagetype", None)
# image['owner'] = form.get("imageowner", None)
# user_info = G_usermgr.selfQuery(cur_user = cur_user)
# user = user_info['data']['username']
# user_info = json.dumps(user_info)
# setting = {
# 'cpu': form.get('cpuSetting'),
# 'memory': form.get('memorySetting'),
# 'disk': form.get('diskSetting')
# }
# [status, result] = G_usermgr.usageInc(cur_user = cur_user, modification = setting)
# if not status:
# return json.dumps({'success':'false', 'action':'scale out', 'message': result})
# [status, result] = G_vclustermgr.scale_out_cluster(clustername, user, image, user_info, setting)
# if status:
# return json.dumps({'success':'true', 'action':'scale out', 'message':result})
# else:
# G_usermgr.usageRecover(cur_user = cur_user, modification = setting)
# return json.dumps({'success':'false', 'action':'scale out', 'message':result})
@app.errorhandler(500) @app.errorhandler(500)
def internal_server_error(error): def internal_server_error(error):
logger.debug("An internel server error occured") logger.debug("An internel server error occured")
@ -998,6 +1074,8 @@ if __name__ == '__main__':
master_collector.start() master_collector.start()
logger.info("master_collector started") logger.info("master_collector started")
G_applicationmgr = beansapplicationmgr.ApplicationMgr() G_applicationmgr = beansapplicationmgr.ApplicationMgr()
approvalrbt = beansapplicationmgr.ApprovalRobot()
approvalrbt.start()
# server = http.server.HTTPServer((masterip, masterport), DockletHttpHandler) # server = http.server.HTTPServer((masterip, masterport), DockletHttpHandler)
logger.info("starting master server") logger.info("starting master server")

View File

@ -95,7 +95,7 @@ class User(db.Model):
self.department = department self.department = department
self.truename = truename self.truename = truename
self.tel = tel self.tel = tel
self.beans = 100 self.beans = 1000
if (date != None): if (date != None):
self.register_date = date self.register_date = date
else: else:
@ -247,12 +247,14 @@ class ApplyMsg(db.Model):
number = db.Column(db.Integer) number = db.Column(db.Integer)
reason = db.Column(db.String(600)) reason = db.Column(db.String(600))
status = db.Column(db.String(10)) status = db.Column(db.String(10))
time = db.Column(db.DateTime(10))
def __init__(self,username, number, reason): def __init__(self,username, number, reason):
self.username = username self.username = username
self.number = number self.number = number
self.reason = reason self.reason = reason
self.status = "Processing" self.status = "Processing"
self.time = datetime.now()
def __repr__(self): def __repr__(self):
return "{\"id\":\"%d\", \"username\":\"%s\", \"number\": \"%d\", \"reason\":\"%s\", \"status\":\"%s\"}" % (self.id, self.username, self.number, self.reason, self.status) return "{\"id\":\"%d\", \"username\":\"%s\", \"number\": \"%d\", \"reason\":\"%s\", \"status\":\"%s\", \"time\":\"%s\"}" % (self.id, self.username, self.number, self.reason, self.status, self.time.strftime("%Y-%m-%d %H:%M:%S"))

View File

@ -59,7 +59,7 @@ class Container_Collector(threading.Thread):
return containers return containers
def get_proc_etime(self,pid): def get_proc_etime(self,pid):
fmt = subprocess.getoutput("ps -A -opid,etime | grep '^ *%d' | awk '{print $NF}'" % pid).strip() fmt = subprocess.getoutput("ps -A -opid,etime | grep '^ *%d ' | awk '{print $NF}'" % pid).strip()
if fmt == '': if fmt == '':
return -1 return -1
parts = fmt.split('-') parts = fmt.split('-')
@ -109,13 +109,18 @@ class Container_Collector(threading.Thread):
try: try:
vnode = VNode.query.get(vnode_name) vnode = VNode.query.get(vnode_name)
vnode.billing = nowbillingval vnode.billing = nowbillingval
db.session.commit()
except Exception as err: except Exception as err:
vnode = VNode(vnode_name) vnode = VNode(vnode_name)
vnode.billing = nowbillingval vnode.billing = nowbillingval
db.session.add(vnode) db.session.add(vnode)
db.session.commit()
logger.warning(err) logger.warning(err)
try:
db.session.commit()
except Exception as err:
db.session.rollback()
logger.warning(traceback.format_exc())
logger.warning(err)
raise
workercinfo[vnode_name]['basic_info']['billing'] = nowbillingval workercinfo[vnode_name]['basic_info']['billing'] = nowbillingval
owner_name = get_owner(vnode_name) owner_name = get_owner(vnode_name)
owner = User.query.filter_by(username=owner_name).first() owner = User.query.filter_by(username=owner_name).first()
@ -129,7 +134,7 @@ class Container_Collector(threading.Thread):
if owner.beans <= 0: if owner.beans <= 0:
logger.info("The beans of User(" + str(owner) + ") are less than or equal to zero, the container("+vnode_name+") will be stopped.") logger.info("The beans of User(" + str(owner) + ") are less than or equal to zero, the container("+vnode_name+") will be stopped.")
token = owner.generate_auth_token() token = owner.generate_auth_token()
form = {'token':token} form = {'username':owner.username}
header = {'Content-Type':'application/x-www-form-urlencoded'} header = {'Content-Type':'application/x-www-form-urlencoded'}
http = Http() http = Http()
[resp,content] = http.request("http://"+G_masterip+"/cluster/stopall/","POST",urlencode(form),headers = header) [resp,content] = http.request("http://"+G_masterip+"/cluster/stopall/","POST",urlencode(form),headers = header)

View File

@ -440,6 +440,7 @@ class userManager:
"group" : user.user_group, "group" : user.user_group,
"groupinfo": group, "groupinfo": group,
"beans" : user.beans, "beans" : user.beans,
"auth_method": user.auth_method,
}, },
} }
return result return result
@ -467,6 +468,12 @@ class userManager:
user.e_mail = value user.e_mail = value
elif (name == 'tel'): elif (name == 'tel'):
user.tel = value user.tel = value
elif (name == 'password'):
old_password = hashlib.sha512(form.get('old_value', '').encode('utf-8')).hexdigest()
if (user.password != old_password):
result = {'success': 'false'}
return result
user.password = hashlib.sha512(value.encode('utf-8')).hexdigest()
else: else:
result = {'success': 'false'} result = {'success': 'false'}
return result return result

View File

@ -10,6 +10,7 @@ if [ $# -eq 0 ] ; then
exit 1 exit 1
fi fi
etcd_1=$1
index=1 index=1
while [ $# -gt 0 ] ; do while [ $# -gt 0 ] ; do
h="etcd_$index" h="etcd_$index"
@ -31,7 +32,6 @@ done
# -initial-cluster-state : new means join a new cluster; existing means join an existing cluster # -initial-cluster-state : new means join a new cluster; existing means join an existing cluster
# : new not means clear # : new not means clear
etcd --name etcd_1 \ etcd --name etcd_1 \
--initial-advertise-peer-urls http://$etcd_1:2380 \ --initial-advertise-peer-urls http://$etcd_1:2380 \
--listen-peer-urls http://$etcd_1:2380 \ --listen-peer-urls http://$etcd_1:2380 \

View File

@ -3,8 +3,8 @@
echo "Backup UserTable..." echo "Backup UserTable..."
cp /opt/docklet/global/sys/UserTable.db /opt/docklet/global/sys/UserTable.db.backup cp /opt/docklet/global/sys/UserTable.db /opt/docklet/global/sys/UserTable.db.backup
sed -i "75s/^ /#/g" ../src/model.py sed -i "s/^ beans/# beans/g" ../src/model.py
sed -i "95s/^ /#/g" ../src/model.py sed -i "s/^ self.beans/# self.beans/g" ../src/model.py
echo "Alter UserTable..." echo "Alter UserTable..."
python3 alterUserTable.py python3 alterUserTable.py

View File

@ -35,7 +35,7 @@
</div> </div>
<div class="box-body"> <div class="box-body">
<p> <p>
<button type="button" class="btn btn-primary btn-sm" data-toggle="modal" data-target="#AddApplication"><i class="fa fa-plus"></i> Add Application</button> <button type="button" class="btn btn-primary btn-sm" data-toggle="modal" data-target="#AddApplication"><i class="fa fa-plus"></i> Apply For Beans</button>
</p> </p>
<div class="modal inmodal" id="AddApplication" tabindex="-1" role="dialog" aria-hidden="true"> <div class="modal inmodal" id="AddApplication" tabindex="-1" role="dialog" aria-hidden="true">
<div class="modal-dialog"> <div class="modal-dialog">
@ -74,6 +74,7 @@
<th>Application ID</th> <th>Application ID</th>
<th>Username</th> <th>Username</th>
<th>Number</th> <th>Number</th>
<th>Submission Time</th>
<th>Reason</th> <th>Reason</th>
<th>Status</th> <th>Status</th>
</tr> </tr>
@ -83,7 +84,8 @@
<tr> <tr>
<td>{{ application.id }}</td> <td>{{ application.id }}</td>
<td>{{ application.username }}</td> <td>{{ application.username }}</td>
<td>{{ application.number }} beans</td> <td>{{ application.number }} <img src='/static/img/bean.png'></td>
<td>{{ application.time }}</td>
<td>{{ application.reason }}</td> <td>{{ application.reason }}</td>
<td>{{ application.status }}</td> <td>{{ application.status }}</td>
</tr> </tr>

View File

@ -1,139 +0,0 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Docklet | Home</title>
<link rel="shortcut icon" href="/static/img/favicon.ico">
<link href="http://cdn.bootcss.com/bootstrap/3.3.5/css/bootstrap.min.css" rel="stylesheet">
<link href="http://cdn.bootcss.com/font-awesome/4.5.0/css/font-awesome.css" rel="stylesheet">
<style type="text/css">
a.linkbtn, a.linkbtn:visited, a.linkbtn:active{
color:white;
padding:8px;
}
a.linkbtn:hover{
color:white;
text-decoration:none;
border-bottom: 1px solid white;
}
.navbar-custom-top{
background:transparent;
position:absolute;
z-index:1030;
left:0px;
right:0px;
}
</style>
</head>
<body>
<div class="navbar navbar-custom-top" role="navigation">
<div class="container">
<div class="row" style="font-size:16px; color:white; padding:16px">
<div class="pull-right" >
<a class="linkbtn" href="http://docklet.unias.org/docklet-book/userguide/_book/">Document</a>
&centerdot;
<a class="linkbtn" href="/login/" >Sign In</a>
</div>
<div>
<a class="linkbtn" href="http://docklet.unias.org"><strong>Docklet Cloud OS</strong></a>
</div>
</div>
</div>
</div>
<!-- Carousel -->
<div id="myCarousel" class="carousel slide" data-ride="carousel" style="box-shadow:0px 2px 10px 0px black">
<!-- Indicators -->
<ol class="carousel-indicators">
<li data-target="#myCarousel" data-slide-to="0" class="active"></li>
<li data-target="#myCarousel" data-slide-to="1"></li>
</ol>
<div class="carousel-inner" role="listbox">
<div class="item active">
<img src="/static/img/home/cloud.png" alt="Cloud OS" style="min-height:600px">
<div class="container">
<div class="carousel-caption">
<h1>Cloud OS</h1>
<p class="lead">Cloud OS for your cloud Apps.</p>
<br>
</div>
</div>
</div>
<div class="item">
<img src="/static/img/home/workspace.png" alt="Cloud Workspace" style="min-height:600px">
<div class="container">
<div class="carousel-caption">
<h1>Cloud Workspace</h1>
<p class="lead">Workspace in cloud, all your work in cloud.</p>
<br>
</div>
</div>
</div>
</div>
<a class="left carousel-control" href="#myCarousel" role="button" data-slide="prev">
<span class="glyphicon glyphicon-chevron-left" aria-hidden="true"></span>
<span class="sr-only">Previous</span>
</a>
<a class="right carousel-control" href="#myCarousel" role="button" data-slide="next">
<span class="glyphicon glyphicon-chevron-right" aria-hidden="true"></span>
<span class="sr-only">Next</span>
</a>
</div><!-- /.carousel -->
<div class="container" style="margin-top:60px">
<div class="row">
<div class="col-lg-6 col-lg-offset-1 col-md-7 col-md-offset-0 col-sm-7 col-sm-offset-0 col-xs-12 col-xs-offset-0">
<h2>Workspace=Cluster+Service+Data</h2>
<br/>
<p class="lead">Package service and data based on virtual cluster as virtual compute environment for your work.
<br> This is your Workspace !</p>
</div>
<div class="col-lg-3 col-lg-offset-1 col-md-4 col-md-offset-1 col-sm-5 col-sm-offset-0 col-xs-10 col-xs-offset-1">
<img src="/static/img/home/app-workspace.png" alt="feature-workspace" width="100%">
</div>
</div>
<hr>
<div class="row">
<div class="col-lg-3 col-lg-offset-1 col-md-4 col-md-offset-1 col-sm-5 col-sm-offset-0 col-xs-10 col-xs-offset-1">
<img src="/static/img/home/app-dist.png" alt="feature-app" width="100%">
</div>
<div class="col-lg-6 col-lg-offset-1 col-md-7 col-md-offset-0 col-sm-7 col-sm-offset-0 col-xs-12 col-xs-offset-0">
<h2>Click and Go</h2>
<br/>
<p class="lead">Distributed or single node ? Never mind !
Click it just like start an app on your smart phone, and your workspace is ready for you.</p>
</div>
</div>
<hr>
<div class="row">
<div class="col-lg-6 col-lg-offset-1 col-md-7 col-md-offset-0 col-sm-7 col-sm-offset-0 col-xs-12 col-xs-offset-0">
<h2>All in Web</h2>
<br/>
<p class="lead">All you need is a web browser. Compute in web, code in web, plot in web, anything in web !
You can get to work anytime and anywhere by internet.</p>
</div>
<div class="col-lg-3 col-lg-offset-1 col-md-4 col-md-offset-1 col-sm-5 col-sm-offset-0 col-xs-10 col-xs-offset-1">
<img src="/static/img/home/app-web.png" alt="feature-web" width="100%">
</div>
</div>
<hr>
<footer>
<p class="pull-right">Powered by <a href="http://docklet.unias.org" style="color:blue">Docklet</a></p>
<p>&copy; SEI, PKU</p>
</footer>
</div>
<script src="http://cdn.bootcss.com/jquery/2.2.1/jquery.js"></script>
<script src="http://cdn.bootcss.com/bootstrap/3.3.5/js/bootstrap.min.js"></script>
</body>
</html>

View File

@ -4,6 +4,7 @@
{% block css_src %} {% block css_src %}
<link href="//cdn.bootcss.com/x-editable/1.5.1/bootstrap3-editable/css/bootstrap-editable.css" rel="stylesheet"> <link href="//cdn.bootcss.com/x-editable/1.5.1/bootstrap3-editable/css/bootstrap-editable.css" rel="stylesheet">
<link href="/static/dist/css/modalconfig.css" rel="stylesheet">
{% endblock %} {% endblock %}
{% block panel_title %}Detail for User Infomation{% endblock %} {% block panel_title %}Detail for User Infomation{% endblock %}
@ -71,12 +72,12 @@
<td>Telephone</td> <td>Telephone</td>
<td><a href="#" id="tel" data-type="text" data-pk="1" data-url="/user/info/" data-title="Enter telephone number">{{ info['tel'] }}</a></td> <td><a href="#" id="tel" data-type="text" data-pk="1" data-url="/user/info/" data-title="Enter telephone number">{{ info['tel'] }}</a></td>
</tr> </tr>
<!-- {% if info['auth_method'] == 'local' %}
<tr> <tr>
<td>password</td> <td>password</td>
<td> <td>
<div class="col-md-12" > <div class="col-md-12" >
<button type="button" class="btn btn-white btn-xs btn-block" data-toggle="modal" data-target="#ChpasswordModal"> Change Password</button> <button type="button" class="btn btn-primary btn-xs btn-block" data-toggle="modal" data-target="#ChpasswordModal"> Change Password</button>
</div> </div>
<div class="modal inmodal" id="ChpasswordModal" tabindex="-1" role="dialog" aria-hidden="true"> <div class="modal inmodal" id="ChpasswordModal" tabindex="-1" role="dialog" aria-hidden="true">
<div class="modal-dialog"> <div class="modal-dialog">
@ -89,25 +90,26 @@
</div> </div>
<div class="modal-body"> <div class="modal-body">
<form action="/group/add/" method="POST" id="ChpasswordForm"> <form action="/user/info/" method="POST" id="ChpasswordForm">
<div class="form-group"> <div class="form-group">
<label>Old password</label> <label>Old password</label>
<input type = "password" placeholder="Enter old password" class="form-control" name="o_password"> <input type = "password" placeholder="Enter old password" class="form-control" name="o_password" id="o_password">
</div> </div>
<div class="form-group"> <div class="form-group">
<label>New password</label> <label>New password</label>
<input type = "password" placeholder="Enter new password" class="form-control" name="n_password"> <input type = "password" placeholder="Enter new password" class="form-control" name="n_password" id = "n_password">
</div> </div>
<div class="form-group"> <div class="form-group">
<label>Verify</label> <label>Verify</label>
<input type = "password" placeholder="Enter new password again" class="form-control" name="v_password"> <input type = "password" placeholder="Enter new password again" class="form-control" name="v_password" id = "v_password">
</div> </div>
<p style="color:red" id="notCorrectFlag"></p>
</form> </form>
</div> </div>
<div class="modal-footer"> <div class="modal-footer">
<button type="button" class="btn btn-white" data-dismiss="modal">Close</button> <button type="button" class="btn btn-white" data-dismiss="modal">Close</button>
<button type="button" class="btn btn-primary" onClick="javascript:sendAddGroup();">Submit</button> <button type="button" class="btn btn-primary" onClick="javascript:sendChpassword();">Submit</button>
</div> </div>
</div> </div>
</div> </div>
@ -115,7 +117,8 @@
</td> </td>
</tr> </tr>
--> {% endif %}
</table> </table>
</div> </div>
@ -248,6 +251,33 @@ $(document).ready(function(){
*/ */
}); });
function sendChpassword(){
if ($("#n_password").val() == $("#v_password").val())
{
$.post("/user/info/",
{
name: 'password',
value: $("#n_password").val(),
old_value : $("#o_password").val()
},
function(data,status){
var result = eval("("+data+")");
if (result.success == 'true')
{
location.reload();
}
else
{
$("#notCorrectFlag").html("Cannot modify your password");
}
});
}
else
{
$("#notCorrectFlag").html("Two passwords are not identical");
}
}
</script> </script>

View File

@ -166,6 +166,7 @@
</div> </div>
<div class="modal-footer"> <div class="modal-footer">
<button type="button" class="btn btn-white" data-dismiss="modal">Close</button> <button type="button" class="btn btn-white" data-dismiss="modal">Close</button>
<a class="btn btn-danger" data-toggle="modal" data-target="#ChpasswordModal" onClick="" id="ChpasswordButton">Change Password</a>
<button type="button" class="btn btn-primary" onClick="javascript:sendModifyUser();">Submit</button> <button type="button" class="btn btn-primary" onClick="javascript:sendModifyUser();">Submit</button>
</div> </div>
</div> </div>
@ -191,6 +192,11 @@
<input type="password" placeholder="Enter Password" class="form-control" name="password" id="mpPassword"> <input type="password" placeholder="Enter Password" class="form-control" name="password" id="mpPassword">
</div> </div>
</form> </form>
<div class="form-group">
<label>Retype Password</label>
<input type="password" placeholder="Enter Password" class="form-control" id="mpPassword2">
</div>
<p style="color:red" id="notCorrectFlag"></p>
</div> </div>
<div class="modal-footer"> <div class="modal-footer">
@ -227,6 +233,7 @@
<th>Application ID</th> <th>Application ID</th>
<th>Username</th> <th>Username</th>
<th>Number</th> <th>Number</th>
<th>Submission Time</th>
<th>Reason</th> <th>Reason</th>
<th>Command</th> <th>Command</th>
</tr> </tr>
@ -237,6 +244,7 @@
<td>{{ application.id }}</td> <td>{{ application.id }}</td>
<td>{{ application.username }}</td> <td>{{ application.username }}</td>
<td>{{ application.number }} beans</td> <td>{{ application.number }} beans</td>
<td>{{ application.time }}</td>
<td>{{ application.reason }}</td> <td>{{ application.reason }}</td>
<td><a class="btn btn-xs btn-info" href="/beans/admin/{{ application.id }}/agree/">Agree</a>&nbsp;&nbsp;&nbsp;&nbsp; <td><a class="btn btn-xs btn-info" href="/beans/admin/{{ application.id }}/agree/">Agree</a>&nbsp;&nbsp;&nbsp;&nbsp;
<a class="btn btn-xs btn-danger" href="/beans/admin/{{ application.id }}/reject/">Reject</a></td> <a class="btn btn-xs btn-danger" href="/beans/admin/{{ application.id }}/reject/">Reject</a></td>
@ -272,10 +280,6 @@
{ {
str=str + '<a class="btn btn-danger btn-xs" onClick="javascript:setActivateUser(' + row[0] + ');">' + 'Activate' + '</a>'; str=str + '<a class="btn btn-danger btn-xs" onClick="javascript:setActivateUser(' + row[0] + ');">' + 'Activate' + '</a>';
} }
else
{
str=str + '<a class="btn btn-primary btn-xs" data-toggle="modal" data-target="#ChpasswordModal" onClick="javascript:setFormChpassword(\'' + row[1] + '\');">' + 'Chpassword' + '</a>';
}
return str; return str;
}, },
"targets": 9 "targets": 9
@ -310,8 +314,15 @@
document.getElementById("modifyUserForm").submit(); document.getElementById("modifyUserForm").submit();
} }
function sendChpassword(){ function sendChpassword(){
if ($("#mpPassword").val() == $("#mpPassword2").val())
{
document.getElementById("chpasswordForm").submit(); document.getElementById("chpasswordForm").submit();
} }
else
{
$("#notCorrectFlag").html("Two passwords are not identical");
}
}
function sendModifyGroup(){ function sendModifyGroup(){
document.getElementById("modifyGroupForm").submit(); document.getElementById("modifyGroupForm").submit();
} }
@ -332,6 +343,7 @@
$("#mUserGroup").val(result.group); $("#mUserGroup").val(result.group);
$("#mAuthMethod").val(result.auth_method); $("#mAuthMethod").val(result.auth_method);
$("#mDescription").val(result.description); $("#mDescription").val(result.description);
$("#ChpasswordButton").attr("onClick", "javascript:setFormChpassword(\"" + result.username + "\");");
}); });
} }
function setFormChpassword(arg){ function setFormChpassword(arg){