diff --git a/README.md b/README.md index 07f9298..03d7d92 100644 --- a/README.md +++ b/README.md @@ -70,11 +70,13 @@ By design, this system is very secure as far as controlling clients over SSH, bu ## Todo -* [ ] enable more than one user per machine * [ ] add PIN protection in web GUI * [ ] add "refresh" button per client in web GUI -* [ ] better error handling when SSH fails etc. -* [ ] support ssh keys +* [ ] support ssh keys +* [X] enable more than one user per machine +* [X] better error handling when SSH fails etc. +* [X] AJAX async loading +* [X] handle identically named users on diff servers ## Related projects diff --git a/docker-compose.yml b/docker-compose.yml index ae21f99..ffc6cba 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -10,3 +10,5 @@ services: restart: unless-stopped ports: - "${TIMEKPR_IP:-0.0.0.0}:${TIMEKPR_PORT:-8080}:8080" + environment: + TZ: ${TIMEKPR_TZ:-America/Los_Angeles} \ No newline at end of file diff --git a/main.py b/main.py index 62320de..dda2b89 100644 --- a/main.py +++ b/main.py @@ -4,6 +4,7 @@ import conf, re from fabric import Connection from paramiko.ssh_exception import AuthenticationException +from paramiko.ssh_exception import NoValidConnectionsError def get_config(): @@ -12,10 +13,24 @@ def get_config(): def get_usage(user, computer, ssh): # to do - maybe check if user is in timekpr first? (/usr/bin/timekpra --userlist) - timekpra_userinfo_output = str(ssh.run( - conf.ssh_timekpra_bin + ' --userinfo ' + user, - hide=True - )) + global timekpra_userinfo_output + fail_json = {'time_left': 0, 'time_spent': 0, 'result': 'fail'} + try: + timekpra_userinfo_output = str(ssh.run( + conf.ssh_timekpra_bin + ' --userinfo ' + user, + hide=True + )) + except NoValidConnectionsError as e: + print(f"Cannot connect to SSH server on host '{computer}'. " + f"Check address in conf.py or try again later.") + return fail_json + except AuthenticationException as e: + print(f"Wrong credentials for user '{conf.ssh_user}' on host '{computer}'. " + f"Check `ssh_user` and `ssh_password` credentials in conf.py.") + return fail_json + except Exception as e: + quit(f"Error logging in as user '{conf.ssh_user}' on host '{computer}', check conf.py. \n\n\t" + str(e)) + return fail_json search = r"(TIME_LEFT_DAY: )([0-9]+)" time_left = re.search(search, timekpra_userinfo_output) search = r"(TIME_SPENT_DAY: )([0-9]+)" @@ -23,14 +38,12 @@ def get_usage(user, computer, ssh): # todo - better handle "else" when we can't find time remaining if not time_left or not time_left.group(2): print(f"Error getting time left, setting to 0. ssh call result: " + str(timekpra_userinfo_output)) - time_left = '0' - time_spent = '0' + return fail_json else: time_left = str(time_left.group(2)) time_spent = str(time_spent.group(2)) - - print(f"Time left for {user} at {computer}: {time_spent}") - return {'time_left': time_left, 'time_spent': time_spent} + print(f"Time left for {user} at {computer}: {time_left}") + return {'time_left': time_left, 'time_spent': time_spent, 'result': 'success'} def get_connection(computer): @@ -49,9 +62,9 @@ def get_connection(computer): ) except AuthenticationException as e: quit(f"Wrong credentials for user '{conf.ssh_user}' on host '{computer}'. " - f"Check `ssh_user` and `ssh_password` credentials in config.py.") + f"Check `ssh_user` and `ssh_password` credentials in conf.py.") except Exception as e: - quit(f"Error logging in as user '{conf.ssh_user}' on host '{computer}', check config. \n\n\t" + str(e)) + quit(f"Error logging in as user '{conf.ssh_user}' on host '{computer}', check conf.py. \n\n\t" + str(e)) finally: return connection diff --git a/templates/index.html b/templates/index.html index 7953971..bc2fabf 100644 --- a/templates/index.html +++ b/templates/index.html @@ -16,6 +16,24 @@ color: blue; margin-left: 4px; } + .loading { + color: lightgray; + } + .error { + color: red; + margin-left: 4px; + } + .user { + padding-bottom: 15px; + display: block; + } + .disabled { + border: 1px solid #ddd !important; + color: #ccc !important; + } + .failed_load { + height: 62px; + } /* ========================================================================== Fork Me on Github Stuffs @@ -103,105 +121,143 @@
-
+
+ + diff --git a/timekpr-next-remote.png b/timekpr-next-remote.png index aa46f8f..fbde2da 100644 Binary files a/timekpr-next-remote.png and b/timekpr-next-remote.png differ diff --git a/timekpr-next-web.py b/timekpr-next-web.py index 8319639..9e48fab 100644 --- a/timekpr-next-web.py +++ b/timekpr-next-web.py @@ -32,7 +32,7 @@ def get_usage(computer, user): return validate_request(computer, user), 500 ssh = main.get_connection(computer) usage = main.get_usage(user, computer, ssh) - return {'result': "success", "time_left": usage['time_left'], "time_spent": usage['time_spent']}, 200 + return {'result': usage['result'], "time_left": usage['time_left'], "time_spent": usage['time_spent']}, 200 @app.route("/increase_time///")