Merge remote-tracking branch 'upstream/master' into external_login
This commit is contained in:
commit
c41771e0b7
|
@ -65,7 +65,7 @@ First copy docklet.conf.template to get docklet.conf.
|
|||
Pay attention to the following settings:
|
||||
|
||||
- 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.
|
||||
For single host environment, the default value should be OK.
|
||||
- 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.
|
||||
|
||||
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`.
|
||||
|
||||
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.
|
||||
|
||||
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.
|
||||
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
import threading,datetime,random,time
|
||||
from model import db,User,ApplyMsg
|
||||
from userManager import administration_required
|
||||
|
||||
|
@ -54,3 +55,28 @@ class ApplicationMgr:
|
|||
applymsg.status = "Rejected"
|
||||
db.session.commit()
|
||||
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)
|
||||
|
|
|
@ -42,13 +42,15 @@ def login_required(func):
|
|||
@wraps(func)
|
||||
def wrapper(*args, **kwargs):
|
||||
global G_usermgr
|
||||
logger.info ("get request, path: %s" % request.path)
|
||||
token = request.form.get("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'})
|
||||
cur_user = G_usermgr.auth_token(token)
|
||||
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'})
|
||||
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 wrapper
|
||||
|
@ -64,6 +66,47 @@ def beans_check(func):
|
|||
|
||||
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'])
|
||||
def login():
|
||||
global G_usermgr
|
||||
|
@ -175,6 +218,7 @@ def scaleout_cluster(cur_user, user, form):
|
|||
global G_usermgr
|
||||
global G_vclustermgr
|
||||
clustername = form.get('clustername', None)
|
||||
logger.info ("scaleout: %s" % form)
|
||||
if (clustername == None):
|
||||
return json.dumps({'success':'false', 'message':'clustername is null'})
|
||||
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})
|
||||
|
||||
@app.route("/cluster/stopall/",methods=['POST'])
|
||||
@login_required
|
||||
def stopall_cluster(cur_user, user, form):
|
||||
@worker_ip_required
|
||||
def stopall_cluster():
|
||||
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)
|
||||
[status, clusterlist] = G_vclustermgr.list_clusters(user)
|
||||
if status:
|
||||
|
@ -853,6 +900,35 @@ def resetall_system(cur_user, user, form):
|
|||
return json.dumps({'success':'false', 'message': message})
|
||||
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)
|
||||
def internal_server_error(error):
|
||||
logger.debug("An internel server error occured")
|
||||
|
@ -998,6 +1074,8 @@ if __name__ == '__main__':
|
|||
master_collector.start()
|
||||
logger.info("master_collector started")
|
||||
G_applicationmgr = beansapplicationmgr.ApplicationMgr()
|
||||
approvalrbt = beansapplicationmgr.ApprovalRobot()
|
||||
approvalrbt.start()
|
||||
|
||||
# server = http.server.HTTPServer((masterip, masterport), DockletHttpHandler)
|
||||
logger.info("starting master server")
|
||||
|
|
|
@ -95,7 +95,7 @@ class User(db.Model):
|
|||
self.department = department
|
||||
self.truename = truename
|
||||
self.tel = tel
|
||||
self.beans = 100
|
||||
self.beans = 1000
|
||||
if (date != None):
|
||||
self.register_date = date
|
||||
else:
|
||||
|
@ -247,12 +247,14 @@ class ApplyMsg(db.Model):
|
|||
number = db.Column(db.Integer)
|
||||
reason = db.Column(db.String(600))
|
||||
status = db.Column(db.String(10))
|
||||
time = db.Column(db.DateTime(10))
|
||||
|
||||
def __init__(self,username, number, reason):
|
||||
self.username = username
|
||||
self.number = number
|
||||
self.reason = reason
|
||||
self.status = "Processing"
|
||||
self.time = datetime.now()
|
||||
|
||||
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"))
|
||||
|
|
|
@ -59,7 +59,7 @@ class Container_Collector(threading.Thread):
|
|||
return containers
|
||||
|
||||
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 == '':
|
||||
return -1
|
||||
parts = fmt.split('-')
|
||||
|
@ -109,13 +109,18 @@ class Container_Collector(threading.Thread):
|
|||
try:
|
||||
vnode = VNode.query.get(vnode_name)
|
||||
vnode.billing = nowbillingval
|
||||
db.session.commit()
|
||||
except Exception as err:
|
||||
vnode = VNode(vnode_name)
|
||||
vnode.billing = nowbillingval
|
||||
db.session.add(vnode)
|
||||
db.session.commit()
|
||||
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
|
||||
owner_name = get_owner(vnode_name)
|
||||
owner = User.query.filter_by(username=owner_name).first()
|
||||
|
@ -129,7 +134,7 @@ class Container_Collector(threading.Thread):
|
|||
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.")
|
||||
token = owner.generate_auth_token()
|
||||
form = {'token':token}
|
||||
form = {'username':owner.username}
|
||||
header = {'Content-Type':'application/x-www-form-urlencoded'}
|
||||
http = Http()
|
||||
[resp,content] = http.request("http://"+G_masterip+"/cluster/stopall/","POST",urlencode(form),headers = header)
|
||||
|
|
|
@ -440,6 +440,7 @@ class userManager:
|
|||
"group" : user.user_group,
|
||||
"groupinfo": group,
|
||||
"beans" : user.beans,
|
||||
"auth_method": user.auth_method,
|
||||
},
|
||||
}
|
||||
return result
|
||||
|
@ -467,6 +468,12 @@ class userManager:
|
|||
user.e_mail = value
|
||||
elif (name == 'tel'):
|
||||
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:
|
||||
result = {'success': 'false'}
|
||||
return result
|
||||
|
|
|
@ -10,6 +10,7 @@ if [ $# -eq 0 ] ; then
|
|||
exit 1
|
||||
fi
|
||||
|
||||
etcd_1=$1
|
||||
index=1
|
||||
while [ $# -gt 0 ] ; do
|
||||
h="etcd_$index"
|
||||
|
@ -31,7 +32,6 @@ done
|
|||
# -initial-cluster-state : new means join a new cluster; existing means join an existing cluster
|
||||
# : new not means clear
|
||||
|
||||
|
||||
etcd --name etcd_1 \
|
||||
--initial-advertise-peer-urls http://$etcd_1:2380 \
|
||||
--listen-peer-urls http://$etcd_1:2380 \
|
||||
|
|
|
@ -3,8 +3,8 @@
|
|||
echo "Backup UserTable..."
|
||||
cp /opt/docklet/global/sys/UserTable.db /opt/docklet/global/sys/UserTable.db.backup
|
||||
|
||||
sed -i "75s/^ /#/g" ../src/model.py
|
||||
sed -i "95s/^ /#/g" ../src/model.py
|
||||
sed -i "s/^ beans/# beans/g" ../src/model.py
|
||||
sed -i "s/^ self.beans/# self.beans/g" ../src/model.py
|
||||
|
||||
echo "Alter UserTable..."
|
||||
python3 alterUserTable.py
|
||||
|
|
|
@ -35,7 +35,7 @@
|
|||
</div>
|
||||
<div class="box-body">
|
||||
<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>
|
||||
<div class="modal inmodal" id="AddApplication" tabindex="-1" role="dialog" aria-hidden="true">
|
||||
<div class="modal-dialog">
|
||||
|
@ -74,6 +74,7 @@
|
|||
<th>Application ID</th>
|
||||
<th>Username</th>
|
||||
<th>Number</th>
|
||||
<th>Submission Time</th>
|
||||
<th>Reason</th>
|
||||
<th>Status</th>
|
||||
</tr>
|
||||
|
@ -83,7 +84,8 @@
|
|||
<tr>
|
||||
<td>{{ application.id }}</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.status }}</td>
|
||||
</tr>
|
||||
|
|
|
@ -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>
|
||||
·
|
||||
<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>© 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>
|
|
@ -4,6 +4,7 @@
|
|||
|
||||
{% block css_src %}
|
||||
<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 %}
|
||||
|
||||
{% block panel_title %}Detail for User Infomation{% endblock %}
|
||||
|
@ -71,12 +72,12 @@
|
|||
<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>
|
||||
</tr>
|
||||
<!--
|
||||
{% if info['auth_method'] == 'local' %}
|
||||
<tr>
|
||||
<td>password</td>
|
||||
<td>
|
||||
<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 class="modal inmodal" id="ChpasswordModal" tabindex="-1" role="dialog" aria-hidden="true">
|
||||
<div class="modal-dialog">
|
||||
|
@ -89,25 +90,26 @@
|
|||
</div>
|
||||
<div class="modal-body">
|
||||
|
||||
<form action="/group/add/" method="POST" id="ChpasswordForm">
|
||||
<form action="/user/info/" method="POST" id="ChpasswordForm">
|
||||
<div class="form-group">
|
||||
<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 class="form-group">
|
||||
<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 class="form-group">
|
||||
<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>
|
||||
<p style="color:red" id="notCorrectFlag"></p>
|
||||
</form>
|
||||
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<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>
|
||||
|
@ -115,7 +117,8 @@
|
|||
</td>
|
||||
|
||||
</tr>
|
||||
-->
|
||||
{% endif %}
|
||||
|
||||
|
||||
</table>
|
||||
</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>
|
||||
|
|
|
@ -166,6 +166,7 @@
|
|||
</div>
|
||||
<div class="modal-footer">
|
||||
<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>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -191,6 +192,11 @@
|
|||
<input type="password" placeholder="Enter Password" class="form-control" name="password" id="mpPassword">
|
||||
</div>
|
||||
</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 class="modal-footer">
|
||||
|
@ -227,6 +233,7 @@
|
|||
<th>Application ID</th>
|
||||
<th>Username</th>
|
||||
<th>Number</th>
|
||||
<th>Submission Time</th>
|
||||
<th>Reason</th>
|
||||
<th>Command</th>
|
||||
</tr>
|
||||
|
@ -237,6 +244,7 @@
|
|||
<td>{{ application.id }}</td>
|
||||
<td>{{ application.username }}</td>
|
||||
<td>{{ application.number }} beans</td>
|
||||
<td>{{ application.time }}</td>
|
||||
<td>{{ application.reason }}</td>
|
||||
<td><a class="btn btn-xs btn-info" href="/beans/admin/{{ application.id }}/agree/">Agree</a>
|
||||
<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>';
|
||||
}
|
||||
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;
|
||||
},
|
||||
"targets": 9
|
||||
|
@ -310,7 +314,14 @@
|
|||
document.getElementById("modifyUserForm").submit();
|
||||
}
|
||||
function sendChpassword(){
|
||||
document.getElementById("chpasswordForm").submit();
|
||||
if ($("#mpPassword").val() == $("#mpPassword2").val())
|
||||
{
|
||||
document.getElementById("chpasswordForm").submit();
|
||||
}
|
||||
else
|
||||
{
|
||||
$("#notCorrectFlag").html("Two passwords are not identical");
|
||||
}
|
||||
}
|
||||
function sendModifyGroup(){
|
||||
document.getElementById("modifyGroupForm").submit();
|
||||
|
@ -332,6 +343,7 @@
|
|||
$("#mUserGroup").val(result.group);
|
||||
$("#mAuthMethod").val(result.auth_method);
|
||||
$("#mDescription").val(result.description);
|
||||
$("#ChpasswordButton").attr("onClick", "javascript:setFormChpassword(\"" + result.username + "\");");
|
||||
});
|
||||
}
|
||||
function setFormChpassword(arg){
|
||||
|
|
Loading…
Reference in New Issue