From b26bb6b274e32c9694590f7f91cd345646cc2750 Mon Sep 17 00:00:00 2001 From: zhongyehong Date: Thu, 28 Jul 2016 12:01:11 +0800 Subject: [PATCH 1/7] update CHANGES and VERSION --- CHANGES | 14 ++++++++++++++ VERSION | 2 +- 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/CHANGES b/CHANGES index dae64b0..4b1a1e1 100644 --- a/CHANGES +++ b/CHANGES @@ -1,3 +1,17 @@ +v0.2.8, Jul 17, 2016 +-------------------- + +**Bug Fix** + * [#119] version display error + +**Improvement** + * [#52] give user a total quota, let themselves decide how to use quota + * [#72] recording the user's historical resource usage + * [#85] Making workers's state consistent with master + * [#88] setting config file in admin panel + * [#96] Web notifications + * [#113] Recovery : after poweroff, just recover container, not recover service + v0.2.7, May 17, 2016 -------------------- diff --git a/VERSION b/VERSION index b003284..a45be46 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -0.2.7 +0.2.8 From 2da24f9176a084ae0365783f5ef1d4b278584cfd Mon Sep 17 00:00:00 2001 From: zhongyehong Date: Thu, 28 Jul 2016 12:01:53 +0800 Subject: [PATCH 2/7] update date --- CHANGES | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGES b/CHANGES index 4b1a1e1..7e3a640 100644 --- a/CHANGES +++ b/CHANGES @@ -1,4 +1,4 @@ -v0.2.8, Jul 17, 2016 +v0.2.8, Jul 28, 2016 -------------------- **Bug Fix** From f2e209cb42546f42085a41ba242ca624560cef78 Mon Sep 17 00:00:00 2001 From: zhongyehong Date: Mon, 1 Aug 2016 17:24:43 +0800 Subject: [PATCH 3/7] fix bug that docklet don't create generated_password file --- src/httprest.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/httprest.py b/src/httprest.py index 4047081..2d030ff 100755 --- a/src/httprest.py +++ b/src/httprest.py @@ -880,7 +880,7 @@ if __name__ == '__main__': if etcdclient.isdir("_lock")[0]: etcdclient.deldir("_lock") - G_usermgr = userManager.userManager('root','unias1616') + G_usermgr = userManager.userManager('root') if mode == "new": G_usermgr.initUsage() G_notificationmgr = notificationmgr.NotificationMgr() From fc4139b8521a83d08b40d524a6d0663d99bbdb1e Mon Sep 17 00:00:00 2001 From: root Date: Tue, 2 Aug 2016 16:30:17 +0800 Subject: [PATCH 4/7] Fix notification --- src/model.py | 14 +++++++++ src/notificationmgr.py | 50 ++++++++++++++++++++++++++++++-- web/templates/base_AdminLTE.html | 12 ++++++-- 3 files changed, 70 insertions(+), 6 deletions(-) diff --git a/src/model.py b/src/model.py index edf7d4f..eadbdfb 100755 --- a/src/model.py +++ b/src/model.py @@ -186,6 +186,20 @@ class NotificationGroups(db.Model): def __repr__(self): return '' % (self.notification_id, self.group_name) +class UserNotificationPair(db.Model): + id = db.Column(db.Integer, primary_key=True) + userName = db.Column(db.String(10)) + notifyId = db.Column(db.Integer) + isRead = db.Column(db.Integer) + + def __init__(self, username, notifyid): + self.userName = username + self.notifyId = notifyid + self.isRead = 0 + + def __repr__(self): + return '' % (self.userName, self.notifyId) + class VNode(db.Model): __bind_key__ = 'history' name = db.Column(db.String(100), primary_key=True) diff --git a/src/notificationmgr.py b/src/notificationmgr.py index 6713dea..c94826f 100644 --- a/src/notificationmgr.py +++ b/src/notificationmgr.py @@ -1,7 +1,7 @@ import json from log import logger -from model import db, Notification, NotificationGroups, User +from model import db, Notification, NotificationGroups, User, UserNotificationPair from userManager import administration_required, token_required import smtplib from email.mime.text import MIMEText @@ -21,6 +21,10 @@ class NotificationMgr: NotificationGroups.query.all() except: db.create_all() + try: + UserNotificationPair.query.all() + except: + db.create_all() logger.info("Notification Manager init done!") def query_user_notifications(self, user): @@ -102,6 +106,16 @@ class NotificationMgr: db.session.commit() if 'sendMail' in form: self.mail_notification(notify.id) + users = User.query.all() + for user in users: + user_group = user.user_group + for group_name in group_names: + if user_group == group_name: + tempPair = UserNotificationPair(user.username, notify.id) + db.session.add(tempPair) + break; + db.session.commit() + return {"success": 'true'} @administration_required @@ -158,36 +172,62 @@ class NotificationMgr: db.session.delete(notify_groups) db.session.delete(notify) db.session.commit() + temppairs = UserNotificationPair.query.filter_by(notifyId=notify_id).all() + for temppair in temppairs: + db.session.delete(temppair) + db.session.commit() return {"success": 'true'} @token_required def query_self_notification_simple_infos(self, *args, **kwargs): user = kwargs['cur_user'] + username = user.username notifies = self.query_user_notifications(user) notify_simple_infos = [] for notify in notifies: if notify is None or notify.status != 'open': continue + notifyid = notify.id + temppair = UserNotificationPair.query.filter_by(userName=username, notifyId=notifyid).first() + if temppair == None: + isRead = 0 + temppair = UserNotificationPair(username, notifyid) + db.session.add(temppair) + db.session.commit() + else: + isRead = temppair.isRead notify_simple_infos.append({ 'id': notify.id, 'title': notify.title, - 'create_date': notify.create_date + 'create_date': notify.create_date, + 'isRead': isRead }) return {'success': 'true', 'data': notify_simple_infos} @token_required def query_self_notifications_infos(self, *args, **kwargs): user = kwargs['cur_user'] + username = user.username notifies = self.query_user_notifications(user) notify_infos = [] for notify in notifies: if notify is None or notify.status != 'open': continue + notifyid = notify.id + temppair = UserNotificationPair.query.filter_by(userName=username, notifyId=notifyid).first() + if temppair == None: + temppair = UserNotificationPair(username, notifyid) + db.session.add(temppair) + isRead = 1 + temppair.isRead = 1 + db.session.add(temppair) + db.session.commit() notify_infos.append({ 'id': notify.id, 'title': notify.title, 'content': notify.content, - 'create_date': notify.create_date + 'create_date': notify.create_date, + 'isRead': isRead }) return {'success': 'true', 'data': notify_infos} @@ -208,6 +248,10 @@ class NotificationMgr: 'content': notify.content, 'create_date': notify.create_date } + usernotifypair = UserNotificationPair.query.filter_by(userName=user.username, notifyId=notify.id).first() + usernotifypair.isRead = 1 + db.session.add(usernotifypair) + db.session.commit() if notify.status != 'open': notify_info['title'] = 'This notification is not available' notify_info['content'] = 'Sorry, it seems that the administrator has closed this notification.' diff --git a/web/templates/base_AdminLTE.html b/web/templates/base_AdminLTE.html index d1666be..c9db229 100644 --- a/web/templates/base_AdminLTE.html +++ b/web/templates/base_AdminLTE.html @@ -265,29 +265,35 @@ var notifies = data.data; var len = notifies.length; var cnt = 0; + var unread = 0; var now = new Date().getTime(); for(var t = 0; t < len; t++) { var notify = notifies[t]; var createDate = notify.create_date.substring(0, 19); + var isRead = notify.isRead; createDate = createDate.replace(/-/g,'/'); var from = new Date(createDate).getTime(); var delta = now - from; if(delta <= 604800000) { cnt ++; } + if(isRead == 0){ + unread ++; + } } $('#notificationIcon').find('span').remove(); $('#notificationList').empty(); - if(cnt != 0) { - $(""+cnt+"").appendTo($('#notificationIcon')); - } + if(unread != 0) + $(""+unread+"").appendTo($('#notificationIcon')); + $("#notificationHeader").html("You have " + len + " notifications, "+cnt+" in 1 week"); for(var i = 0; i < len; i++) { notify = notifies[i]; console.log(notify); + var isRead = notify.isRead; var a = $(" "+ notify.title +"") var item = $("
  • "); item.append(a); From 2054182cbf6bae9b7e75f74f7295a3a6dacd0b89 Mon Sep 17 00:00:00 2001 From: Peidong Liu Date: Thu, 4 Aug 2016 21:58:08 +0800 Subject: [PATCH 5/7] Add a new button to activate user quickly Remove password changing to avoid errors caused by auto-filling Change the time record to current time other than UTC time --- src/model.py | 2 +- src/userManager.py | 26 +++++++++++++++++--------- web/templates/user_list.html | 21 ++++++++++++++++++--- web/web.py | 7 ++++++- 4 files changed, 42 insertions(+), 14 deletions(-) diff --git a/src/model.py b/src/model.py index 409bd85..a6fc008 100755 --- a/src/model.py +++ b/src/model.py @@ -94,7 +94,7 @@ class User(db.Model): if (date != None): self.register_date = date else: - self.register_date = datetime.utcnow() + self.register_date = datetime.now() self.user_group = usergroup self.auth_method = auth_method diff --git a/src/userManager.py b/src/userManager.py index 22e0a1d..924805e 100755 --- a/src/userManager.py +++ b/src/userManager.py @@ -82,7 +82,7 @@ def send_activated_email(to_address, username):

    Docklet Team, SEI, PKU

    ''' % (env.getenv("PORTAL_URL"), env.getenv("PORTAL_URL")) - text += '

    '+ str(datetime.utcnow()) + '

    ' + text += '

    '+ str(datetime.now()) + '

    ' text += '' subject = 'Docklet account activated' msg = MIMEMultipart() @@ -107,7 +107,7 @@ def send_remind_activating_email(username):

    Docklet Team, SEI, PKU

    ''' % (username, env.getenv("PORTAL_URL"), env.getenv("PORTAL_URL")) - text += '

    '+ str(datetime.utcnow()) + '

    ' + text += '

    '+ str(datetime.now()) + '

    ' text += '' subject = 'An activating request in Docklet has been sent' msg = MIMEMultipart() @@ -312,14 +312,14 @@ class userManager: def set_nfs_quota_bygroup(self,groupname, quota): if not data_quota == "True": - return - users = User.query.filter_by(user_group = groupname).all() + return + users = User.query.filter_by(user_group = groupname).all() for user in users: self.set_nfs_quota(user.username, quota) def set_nfs_quota(self, username, quota): if not data_quota == "True": - return + return nfspath = "/users/%s/data" % username try: cmd = data_quota_cmd % (nfspath,quota+"GB") @@ -590,6 +590,13 @@ class userManager: will send an e-mail when status is changed from 'applying' to 'normal' Usage: modify(newValue = dict_from_form, cur_user = token_from_auth) ''' + if ( kwargs['newValue'].get('Instruction', '') == 'Activate'): + user_modify = User.query.filter_by(id = kwargs['newValue'].get('ID', None)).first() + user_modify.status = 'normal' + send_activated_email(user_modify.e_mail, user_modify.username) + db.session.commit() + return {"success": "true"} + user_modify = User.query.filter_by(username = kwargs['newValue'].get('username', None)).first() if (user_modify == None): @@ -607,11 +614,12 @@ class userManager: if (user_modify.status == 'applying' and form.get('status', '') == 'normal'): send_activated_email(user_modify.e_mail, user_modify.username) user_modify.status = form.get('status', '') - if (form.get('password', '') != ''): - new_password = form.get('password','') - new_password = hashlib.sha512(new_password.encode('utf-8')).hexdigest() - user_modify.password = new_password + #if (form.get('password', '') != ''): + #new_password = form.get('password','') + #new_password = hashlib.sha512(new_password.encode('utf-8')).hexdigest() + #user_modify.password = new_password #self.chpassword(cur_user = user_modify, password = form.get('password','no_password')) + #modify password in another function now db.session.commit() res = self.groupQuery(name=user_modify.user_group) diff --git a/web/templates/user_list.html b/web/templates/user_list.html index abb5c10..cff6da3 100644 --- a/web/templates/user_list.html +++ b/web/templates/user_list.html @@ -133,10 +133,10 @@ -
    +
    @@ -194,7 +194,12 @@ "columnDefs": [ { "render": function ( data, type, row ) { - return '' + 'Edit' + ''; + str='' + 'Edit' + ''; + if (row[6]=='applying') + { + str=str + '' + 'Activate' + ''; + } + return str; }, "targets": 8 }, @@ -249,5 +254,15 @@ $("#mDescription").val(result.description); }); } + function setActivateUser(arg){ + $.post("/user/change/", + { + ID: arg, + Instruction: "Activate", + }, + function(data,status){ + location.reload(); + }); + } {% endblock %} diff --git a/web/web.py b/web/web.py index c74928c..05eb9ba 100755 --- a/web/web.py +++ b/web/web.py @@ -317,6 +317,11 @@ def useradd(): def usermodify(): return usermodifyView.as_view() +@app.route("/user/change/", methods=['POST']) +@administration_required +def userchange(): + return usermodifyView.as_view() + @app.route("/quota/add/", methods=['POST']) @administration_required def quotaadd(): @@ -493,4 +498,4 @@ if __name__ == '__main__': elif opt in ("-p", "--port"): webport = int(arg) - app.run(host = webip, port = webport, threaded=True) + app.run(host = webip, port = webport, threaded=True,) From 2b81f1963e6f940bc8ba4cc09ceec22886f5d7e2 Mon Sep 17 00:00:00 2001 From: Peidong Liu Date: Thu, 4 Aug 2016 21:58:08 +0800 Subject: [PATCH 6/7] Add a new button to activate user quickly Remove password changing to avoid errors caused by auto-filling Change the time record to current time other than UTC time --- src/model.py | 2 +- src/userManager.py | 26 +++++++++++++++++--------- web/templates/user_list.html | 21 ++++++++++++++++++--- web/web.py | 7 ++++++- 4 files changed, 42 insertions(+), 14 deletions(-) diff --git a/src/model.py b/src/model.py index edf7d4f..6ebd924 100755 --- a/src/model.py +++ b/src/model.py @@ -95,7 +95,7 @@ class User(db.Model): if (date != None): self.register_date = date else: - self.register_date = datetime.utcnow() + self.register_date = datetime.now() self.user_group = usergroup self.auth_method = auth_method diff --git a/src/userManager.py b/src/userManager.py index d58a68b..d7d03dd 100755 --- a/src/userManager.py +++ b/src/userManager.py @@ -82,7 +82,7 @@ def send_activated_email(to_address, username):

    Docklet Team, SEI, PKU

    ''' % (env.getenv("PORTAL_URL"), env.getenv("PORTAL_URL")) - text += '

    '+ str(datetime.utcnow()) + '

    ' + text += '

    '+ str(datetime.now()) + '

    ' text += '' subject = 'Docklet account activated' msg = MIMEMultipart() @@ -107,7 +107,7 @@ def send_remind_activating_email(username):

    Docklet Team, SEI, PKU

    ''' % (username, env.getenv("PORTAL_URL"), env.getenv("PORTAL_URL")) - text += '

    '+ str(datetime.utcnow()) + '

    ' + text += '

    '+ str(datetime.now()) + '

    ' text += '' subject = 'An activating request in Docklet has been sent' msg = MIMEMultipart() @@ -324,14 +324,14 @@ class userManager: def set_nfs_quota_bygroup(self,groupname, quota): if not data_quota == "True": - return - users = User.query.filter_by(user_group = groupname).all() + return + users = User.query.filter_by(user_group = groupname).all() for user in users: self.set_nfs_quota(user.username, quota) def set_nfs_quota(self, username, quota): if not data_quota == "True": - return + return nfspath = "/users/%s/data" % username try: cmd = data_quota_cmd % (nfspath,quota+"GB") @@ -769,6 +769,13 @@ class userManager: will send an e-mail when status is changed from 'applying' to 'normal' Usage: modify(newValue = dict_from_form, cur_user = token_from_auth) ''' + if ( kwargs['newValue'].get('Instruction', '') == 'Activate'): + user_modify = User.query.filter_by(id = kwargs['newValue'].get('ID', None)).first() + user_modify.status = 'normal' + send_activated_email(user_modify.e_mail, user_modify.username) + db.session.commit() + return {"success": "true"} + user_modify = User.query.filter_by(username = kwargs['newValue'].get('username', None)).first() if (user_modify == None): @@ -786,11 +793,12 @@ class userManager: if (user_modify.status == 'applying' and form.get('status', '') == 'normal'): send_activated_email(user_modify.e_mail, user_modify.username) user_modify.status = form.get('status', '') - if (form.get('password', '') != ''): - new_password = form.get('password','') - new_password = hashlib.sha512(new_password.encode('utf-8')).hexdigest() - user_modify.password = new_password + #if (form.get('password', '') != ''): + #new_password = form.get('password','') + #new_password = hashlib.sha512(new_password.encode('utf-8')).hexdigest() + #user_modify.password = new_password #self.chpassword(cur_user = user_modify, password = form.get('password','no_password')) + #modify password in another function now db.session.commit() res = self.groupQuery(name=user_modify.user_group) diff --git a/web/templates/user_list.html b/web/templates/user_list.html index abb5c10..cff6da3 100644 --- a/web/templates/user_list.html +++ b/web/templates/user_list.html @@ -133,10 +133,10 @@
    -
    +
    @@ -194,7 +194,12 @@ "columnDefs": [ { "render": function ( data, type, row ) { - return '' + 'Edit' + ''; + str='' + 'Edit' + ''; + if (row[6]=='applying') + { + str=str + '' + 'Activate' + ''; + } + return str; }, "targets": 8 }, @@ -249,5 +254,15 @@ $("#mDescription").val(result.description); }); } + function setActivateUser(arg){ + $.post("/user/change/", + { + ID: arg, + Instruction: "Activate", + }, + function(data,status){ + location.reload(); + }); + } {% endblock %} diff --git a/web/web.py b/web/web.py index 952b103..d5d3d19 100755 --- a/web/web.py +++ b/web/web.py @@ -327,6 +327,11 @@ def useradd(): def usermodify(): return usermodifyView.as_view() +@app.route("/user/change/", methods=['POST']) +@administration_required +def userchange(): + return usermodifyView.as_view() + @app.route("/quota/add/", methods=['POST']) @administration_required def quotaadd(): @@ -545,4 +550,4 @@ if __name__ == '__main__': elif opt in ("-p", "--port"): webport = int(arg) - app.run(host = webip, port = webport, threaded=True) + app.run(host = webip, port = webport, threaded=True,) From 50a24d4f950e99f0d110bf7617d2765f4aede274 Mon Sep 17 00:00:00 2001 From: zhuyj17 Date: Sun, 7 Aug 2016 17:10:18 +0800 Subject: [PATCH 7/7] Add history page and user can query all history of created vnodes. --- src/httprest.py | 20 ++++-- src/monitor.py | 7 +++ web/templates/base_AdminLTE.html | 5 ++ web/templates/monitor/history.html | 62 ++++++++++--------- web/templates/monitor/historyVNode.html | 82 +++++++++++++++++++++++++ web/templates/monitor/status.html | 2 - web/web.py | 14 +++-- web/webViews/monitor.py | 12 ++++ 8 files changed, 163 insertions(+), 41 deletions(-) create mode 100644 web/templates/monitor/historyVNode.html diff --git a/src/httprest.py b/src/httprest.py index 2d030ff..43de1b6 100755 --- a/src/httprest.py +++ b/src/httprest.py @@ -451,14 +451,22 @@ def vnodes_monitor(cur_user, user, form, con_id, issue): return json.dumps({'success':'true', 'monitor':res}) -@app.route("/monitor/user/quotainfo/", methods=['POST']) +@app.route("/monitor/user//", methods=['POST']) @login_required -def user_quotainfo_monitor(cur_user, user, form): +def user_quotainfo_monitor(cur_user, user, form,issue): global G_usermgr - logger.info("handle request: monitor/user/quotainfo/") - user_info = G_usermgr.selfQuery(cur_user = cur_user) - quotainfo = user_info['data']['groupinfo'] - return json.dumps({'success':'true', 'quotainfo':quotainfo}) + global G_historymgr + if issue == 'quotainfo': + logger.info("handle request: monitor/user/quotainfo/") + user_info = G_usermgr.selfQuery(cur_user = cur_user) + quotainfo = user_info['data']['groupinfo'] + return json.dumps({'success':'true', 'quotainfo':quotainfo}) + elif issue == 'createdvnodes': + logger.info("handle request: monitor/user/createdvnodes/") + res = G_historymgr.getCreatedVNodes(user) + return json.dumps({'success':'true', 'createdvnodes':res}) + else: + return json.dumps({'success':'false', 'message':"Unspported Method!"}) @app.route("/monitor/listphynodes/", methods=['POST']) @login_required diff --git a/src/monitor.py b/src/monitor.py index f5b1b09..7fb2e53 100755 --- a/src/monitor.py +++ b/src/monitor.py @@ -637,3 +637,10 @@ class History_Manager: else: res = History.query.filter_by(vnode=vnode_name).all() return list(eval(str(res))) + + def getCreatedVNodes(self,owner): + vnodes = VNode.query.filter(VNode.name.startswith(owner)).all() + res = [] + for vnode in vnodes: + res.append(vnode.name) + return res diff --git a/web/templates/base_AdminLTE.html b/web/templates/base_AdminLTE.html index d1666be..f8ef6cf 100644 --- a/web/templates/base_AdminLTE.html +++ b/web/templates/base_AdminLTE.html @@ -149,6 +149,9 @@ + {% if mysession['usergroup'] == 'root' or mysession['usergroup'] == 'admin'%} @@ -242,6 +245,8 @@ $("#nav_Hosts").addClass("active"); else if(pathname[1] == 'config') $("#nav_Config").addClass("active"); + else if(pathname[1] == 'history') + $("#nav_History").addClass("active"); else if(pathname[1] == 'user') { if (pathname[2] == 'list') diff --git a/web/templates/monitor/history.html b/web/templates/monitor/history.html index 4f03ffe..7be1b25 100644 --- a/web/templates/monitor/history.html +++ b/web/templates/monitor/history.html @@ -2,16 +2,13 @@ {% block title %}Docklet | History{% endblock %} -{% block panel_title %}History for
    {{ vnode_name }}
    {% endblock %} +{% block panel_title %}History of All Created VNodes{% endblock %} {% block panel_list %}