diff --git a/app/__init__.py b/app/__init__.py index 28010cd589a0f39467a585361dbec9e7a987243b..c99094c03cf308fdd2bfdf725c337f676991068a 100644 --- a/app/__init__.py +++ b/app/__init__.py @@ -3,17 +3,17 @@ # local imports from __future__ import print_function import vars - +import messages # third-party imports import uuid -from flask import Flask, redirect, url_for, request, render_template, flash, session +from flask import Flask, redirect, url_for, request, render_template, flash, session, send_from_directory from flask_bootstrap import Bootstrap import random import os import json def create_app(config_name): - app = Flask(__name__) # initialization of the flask app + app = Flask(__name__, static_folder='static') # initialization of the flask app Bootstrap(app) # allowing app to use bootstrap def get_authorized_user(): @@ -49,7 +49,14 @@ def create_app(config_name): return render_template('auth/SignUp.html', room_id=session['uid'], username=session['user'].get('username'), fullname=session['user'].get('fullname'), email=session['user'].get('email'), - referrer=session['return_url'], cancel_url=vars.default_referrer) + referrer=session['return_url'], cancel_url=vars.default_referrer, + welcome_msg=messages.welcome_message, + cancel_msg=messages.cancel_message, + error_msg=messages.error_message) + + @app.route('/error_account') + def error_account_create(): + return render_template('errors/error.html', title='account creation failed') # misc page error catching diff --git a/app/static/img/cheaha-logo-a605de0aecd3006b82a5ee30a6d0cb8cd9bf8b7e836296cc293eac746a4c2b11.png b/app/static/img/cheaha-logo-a605de0aecd3006b82a5ee30a6d0cb8cd9bf8b7e836296cc293eac746a4c2b11.png index 3472668aa4cf3857431874b1bc6f10f18ad1e107..884b448de16d2ad760f2d440ad86020d2a0df3eb 100644 Binary files a/app/static/img/cheaha-logo-a605de0aecd3006b82a5ee30a6d0cb8cd9bf8b7e836296cc293eac746a4c2b11.png and b/app/static/img/cheaha-logo-a605de0aecd3006b82a5ee30a6d0cb8cd9bf8b7e836296cc293eac746a4c2b11.png differ diff --git a/app/static/img/logo_svg.svg b/app/static/img/logo_svg.svg new file mode 100644 index 0000000000000000000000000000000000000000..88508a14b488c8f49df15e6a717b6714e60542f1 --- /dev/null +++ b/app/static/img/logo_svg.svg @@ -0,0 +1 @@ +<svg id="Layer_1" data-name="Layer 1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 300 157"><title>Supercomputer-logo</title><image width="300" height="157" xlink:href="data:image/png;base64,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"/></svg> \ No newline at end of file diff --git a/app/static/scripts/function.js b/app/static/scripts/function.js index d3ee135e7438bd7c523f04e2fdb838a3407fa65a..ae406d73e8eb8bcb12bab94c16088026b3ca4c0b 100644 --- a/app/static/scripts/function.js +++ b/app/static/scripts/function.js @@ -1,5 +1,10 @@ -function displayloading() { - $('#myModal').modal('show'); +function displayloading1() { + $('#overlayModal').modal('show'); +} + +function displayloading2() { + $('#overlayModal').modal('hide'); + $('#myModal2').modal('show'); } function request_account() { @@ -11,27 +16,31 @@ function request_account() { }) } -function refresh() { - document.location.reload(true); +function renderDom(title, message, error_msg) { + document.getElementById("form-wrapper").innerHTML = "<h3>" + title + "</h3><br>"; + document.getElementById("form-wrapper").innerHTML += "<p>" + message + "</p><br>"; + if (error_msg !== null ) { + var error_button = document.createElement("BUTTON"); + error_button.innerHTML = 'Read Error Message'; + document.getElementById("form-wrapper").appendChild(error_button); + error_button.onclick = function(){document.getElementById("form-wrapper").innerHTML += "<br>" +error_msg} + } } function autofill_form(username, fullname, email) { - let username_input = document.getElementById("username"); - let fullname_input = document.getElementById("fullname"); - let email_input = document.getElementById("email"); - - if ((username.localeCompare("None")) !== 0) { - username_input.value = username; - username_input.disabled = "true"; - } - - if ((fullname.localeCompare("None")) !== 0) { - fullname_input.value = fullname; - fullname_input.disabled = "true"; - } - - if ((email.localeCompare("None")) !== 0) { - email_input.value = email; - email_input.disabled = "true"; - } + let username_input = document.getElementById("username"); + let fullname_input = document.getElementById("fullname"); + let email_input = document.getElementById("email"); + if ((username.localeCompare("None")) !== 0) { + username_input.value = username; + username_input.disabled = "true"; + } + if ((fullname.localeCompare("None")) !== 0) { + fullname_input.value = fullname; + fullname_input.disabled = "true"; + } + if ((email.localeCompare("None")) !== 0) { + email_input.value = email; + email_input.disabled = "true"; + } } diff --git a/app/templates/auth/SignUp.html b/app/templates/auth/SignUp.html index 1ada7d2c0ba488ffb98a271c0ce35009d2dd5a9d..7c450cbe8e7c393505cba4ffd2e27e4dd421cd47 100644 --- a/app/templates/auth/SignUp.html +++ b/app/templates/auth/SignUp.html @@ -17,36 +17,34 @@ }); socket.on( 'creating account', function( msg ) { - document.getElementById("error").innerText = ""; - displayloading(); + displayloading2(); }); socket.on( 'account ready', function( msg ) { - $('#myModal').modal('hide'); + $('#myModal2').modal('hide'); window.location.replace('{{ referrer }}'); }); - socket.on( 'Account creation failed', function( msg ) { - document.getElementById("error").innerText = "Registration Failed. Please try again."; + socket.on( 'account error', function( msg ) { + console.log(msg); + $('#myModal2').modal('hide'); + renderDom("Account Create Error", "{{ error_msg }}", msg); }); }); </script> - <style type="text/css"> - .important { color: #336699; } - </style> - <link rel="shortcut icon" type="image/x-icon" href="/public/favicon.ico"> +<link rel="shortcut icon" type="image/x-icon" href="/public/favicon.ico"> <link rel="stylesheet" media="all" href="{{ url_for('static', filename='style/application.css') }}"> <link rel="stylesheet" media="all" href="{{ url_for('static', filename='style/app2.css') }}"> <meta name="viewport" content="width=device-width, initial-scale=1"> <style> -.navbar-inverse { - background-color: rgb(0,99,65); -} - + .navbar-inverse { background-color: rgb(0,99,65); } + button{ margin: 13px; + .important { color: #336699; }} </style> + </head> @@ -55,91 +53,99 @@ <nav class="navbar navbar-inverse navbar-static-top"> <div class="container-fluid"> <div class="navbar-header"> - <button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#bs-example-navbar-collapse-9" aria-expanded="false"> <span class="sr-only">Toggle navigation</span> <span class="icon-bar"></span> <span class="icon-bar"></span> <span class="icon-bar"></span> </button> - <a class="navbar-brand" href="/">Research Computing</a> + <button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#bs-example-navbar-collapse-9" aria-expanded="false"> <span class="sr-only">Toggle navigation</span> <span class="icon-bar"></span> <span class="icon-bar"></span> <span class="icon-bar"></span> </button> + <a class="navbar-brand" href="/"> UAB Research Computing</a> </div> <div class="collapse navbar-collapse" id="bs-example-navbar-collapse-9"> - <ul class="nav navbar-nav"> - - </ul> - <div class="navbar-right"> - <ul class="nav navbar-nav"> - <li> - <a target="_blank" href="https://docs.uabgrid.uab.edu/wiki/Cheaha_GettingStarted"> - <i class="fas fa-info-circle fa-fw"></i> Online Documentation - </a></li> - <li> - </li></ul> - </div> + <div class="navbar-right"> + <ul class="nav navbar-nav"> + <li> + <a target="_blank" href="https://docs.uabgrid.uab.edu/wiki/Cheaha_GettingStarted"> + <i class="fas fa-info-circle fa-fw"></i> Online Documentation + </a> + </li> + </ul> + </div> </div> </div> </nav> </header> -<div class="container content" role="main" style="width: 625px"> - - <div style="position:relative;"> - <img alt="logo" height="auto" width="100%" style="margin-bottom: 20px" src="{{ url_for('static', filename='img/cheaha-logo-a605de0aecd3006b82a5ee30a6d0cb8cd9bf8b7e836296cc293eac746a4c2b11.png') }}"> - <a href="https://tinyurl.com/cheahaAL" target="_blank"> - <div style="float:left;position:absolute;display:block;left:310px;top:-6px;padding:10px 20px;"> </div> - </a> -</div> - -<!-- <h2>Hello, <span id="username">{{ user }}</span>!</h2> --> - <h2>Hi, </h2> - <div id="user-input"> - - <form id="signup" data-toggle="validator" role="form" action="." method="post" onsubmit=""> - <div class="form-group"> - <label for="username" class="control-label">Blazer Id:</label>	<input id="username" class="form-control" - placeholder="Enter Username" required><br> - </div> - <div class="form-group"> - <label for="fullname" class="control-label">Full Name:</label>	<input id="fullname" class="form-control" - placeholder="Enter Full Name" required><br> - </div> - <div class="form-group"> - <label for="email" class="control-label">Email:</label>	<input id="email" class="form-control" - placeholder="Enter Email" required><br> - </div> - <div class="form-group"> - <label for="reason" class="control-label">Reason for Requesting Account:</label><br> +<div class="container content" role="main" style="width: 100%"> + <div class="col-md-2 col-sm-2 my-col"> + <img alt="logo" height="auto" width="80%" src="{{ url_for('static', filename='img/logo_svg.svg') }}"> + <a href="https://tinyurl.com/cheahaAL" target="_blank"></a> + </div> + + <div class="col-md-10 col-sm-10 my-col"> + <div id="form-wrapper"> + <h2> Self Registration Form </h2> + <p style="font-size:110%;"> {{ welcome_msg |safe }}</p> + <div id="user-input"> + <form id="signup" data-toggle="validator" role="form" action="." method="post" onsubmit=""> + <div class="col-md-7 col-sm-7 my-col"> + <label for="username" class="control-label">Blazer Id:</label>	<input id="username" class="form-control" placeholder="Enter Username" required><br> + </div> + <div class="col-md-7 col-sm-7 my-col"> + <label for="fullname" class="control-label">Full Name:</label>	<input id="fullname" class="form-control" placeholder="Enter Full Name" required><br> + </div> + <div class="col-md-7 col-sm-7 my-col"> + <label for="email" class="control-label">Email:</label>	<input id="email" class="form-control" placeholder="Enter Email" required><br> + </div> + <div class="col-md-7 col-sm-7 my-col"> + <label for="reason" class="control-label">Reason for Requesting Account:</label><br> <textarea class="form-control" id="reason" name="reason" placeholder="Enter Reason for Account Request" required></textarea> - </div> - - <input class="btn btn-primary btn-block" id="submit" name="submit" type="button" value="Submit" onclick="request_account()"> - - <div> - <strong id="error" style="color: #be051b; text-align: center;"></strong> - </div> - - </form> + </div> + <br> + <div class="col-md-7 col-sm-7 my-col"> + <button class="btn btn-danger btn-md" id="cancel" name="cancel" type="button" onClick="renderDom('Account Creation Cancelled','{{ cancel_msg |safe }}', null)">Cancel</button> + <button class="btn btn-primary btn-md" id="submit" name="submit" type="button" value="Submit" onclick="displayloading1();request_account()"> Create Account</button> + </div> + </form> + </div> </div> + </div> +</div> + +<div class="modal fade" id="overlayModal" tabindex="-1" role="dialog" aria-labelledby="myModalLabel" data-backdrop="static" data-keyboard="false"> + <div class="modal-dialog modal-sm" role="document"> + <div class="modal-content"> + <div class="modal-header"> + <h4 class="modal-title" id="myModalLabel">Account Request Received!</h4> + </div> + <div class="modal-body"> + <span>Communicating this information to the server</span> + <img src="{{ url_for('static', filename='img/loading.gif') }}" width="40px"> + </div> </div> + </div> +</div> - <div class="modal fade" id="myModal" tabindex="-1" role="dialog" aria-labelledby="myModalLabel" data-backdrop="static" data-keyboard="false"> - <div class="modal-dialog modal-sm" role="document"> - <div class="modal-content"> - <div class="modal-header"> - <h4 class="modal-title" id="myModalLabel">Account Request Received!</h4> - </div> - <div class="modal-body"> - <span>Please wait while we create your account. This may take up to 5-10 minutes.</span> - <img src="{{ url_for('static', filename='img/loading.gif') }}" width="40px"> - </div> - </div> - </div> +<div class="modal fade" id="myModal2" tabindex="-1" role="dialog" aria-labelledby="myModalLabel" data-backdrop="static" data-keyboard="false"> + <div class="modal-dialog modal-sm" role="document"> + <div class="modal-content"> + <div class="modal-header"> + <h4 class="modal-title" id="myModalLabel">Account Request Received!</h4> + </div> + <div class="modal-body"> + <span>Please wait while we create your account. This may take up to 5-10 minutes.</span> + <img src="{{ url_for('static', filename='img/loading.gif') }}" width="40px"> + </div> </div> + </div> +</div> + <footer> <div class="container-fluid"> <div class="row"> <div class="col-md-6 col-sm-6"> - <a href="https://osc.github.io/Open-OnDemand/"> - <img class="footer-logo" alt="Powered by Open OnDemand" height="40" style="margin-bottom: 20px" src="{{ url_for('static', filename='img/OpenOnDemand_powered_by_RGB-cb3aad5ff5350c7994f250fb334ddcc72e343233ce99eb71fda93beddd76a847.svg') }}"> + <a href="https://osc.github.io/Open-OnDemand/"> + <img class="footer-logo" alt="Powered by Open OnDemand" height="40" style="margin-bottom: 20px" src="{{ url_for('static', filename='img/OpenOnDemand_powered_by_RGB-cb3aad5ff5350c7994f250fb334ddcc72e343233ce99eb71fda93beddd76a847.svg') }}"> </a> </div> </div> - </div><!-- /.container --> + </div> </footer> + </body> </html> diff --git a/app/templates/errors/error.html b/app/templates/errors/error.html new file mode 100644 index 0000000000000000000000000000000000000000..32933b0fb1292bf5cc94c3c35866e61447bb749d --- /dev/null +++ b/app/templates/errors/error.html @@ -0,0 +1,55 @@ +<html class="gr__rc_uab_edu"> +<title>User Registration Error</title> +<head> +<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.12.4/jquery.min.js"></script> +<script src="https://cdnjs.cloudflare.com/ajax/libs/socket.io/1.7.3/socket.io.min.js"></script> +<script src="https://stackpath.bootstrapcdn.com/bootstrap/3.4.1/js/bootstrap.min.js" integrity="sha384-aJ21OjlMXNL5UyIl/XNwTMqvzeRMZH2w8c5cRVpzpU8Y5bApTppSuUkhZXN0VxHd" crossorigin="anonymous"></script> +<script src="{{ url_for('static', filename='scripts/function.js') }}"></script> + +<script> + + +</script> + + <style type="text/css"> + .important { color: #336699; } + </style> + <link rel="shortcut icon" type="image/x-icon" href="/public/favicon.ico"> +<link rel="stylesheet" media="all" href="{{ url_for('static', filename='style/application.css') }}"> +<link rel="stylesheet" media="all" href="{{ url_for('static', filename='style/app2.css') }}"> + +<meta name="viewport" content="width=device-width, initial-scale=1"> +<style> +.navbar-inverse { + background-color: rgb(0,99,65); +} + +</style> +</head> + + +<body data-gr-c-s-loaded="true"> + + +<div class="container content" role="main" style="width: 625px"> + + <div style="position:relative;"> + <img alt="logo" height="auto" width="100%" style="margin-bottom: 20px" src="{{ url_for('static', filename='img/cheaha-logo-a605de0aecd3006b82a5ee30a6d0cb8cd9bf8b7e836296cc293eac746a4c2b11.png') }}"> + <a href="https://tinyurl.com/cheahaAL" target="_blank"> + <div style="float:left;position:absolute;display:block;left:310px;top:-6px;padding:10px 20px;"> </div> + </a> +</div> + +<footer> + <div class="container-fluid"> + <div class="row"> + <div class="col-md-6 col-sm-6"> + <a href="https://osc.github.io/Open-OnDemand/"> + <img class="footer-logo" alt="Powered by Open OnDemand" height="40" style="margin-bottom: 20px" src="{{ url_for('static', filename='img/OpenOnDemand_powered_by_RGB-cb3aad5ff5350c7994f250fb334ddcc72e343233ce99eb71fda93beddd76a847.svg') }}"> + </a> + </div> + </div> + </div><!-- /.container --> +</footer> +</body> +</html> diff --git a/app/templates/errors/registration_failed.html b/app/templates/errors/registration_failed.html index 8386d4b87fc925632b9b5e616fd77e292ba5604c..8e506156a43804ee85162b9a9eb119a1910327dd 100644 --- a/app/templates/errors/registration_failed.html +++ b/app/templates/errors/registration_failed.html @@ -7,8 +7,5 @@ <body> <h2>Something went right...</h2> - <p> - Redirecting back to sign-in page in 5 seconds. - </p> </body> -</html> \ No newline at end of file +</html> diff --git a/logo_svg.svg b/logo_svg.svg new file mode 100644 index 0000000000000000000000000000000000000000..88508a14b488c8f49df15e6a717b6714e60542f1 --- /dev/null +++ b/logo_svg.svg @@ -0,0 +1 @@ +<svg id="Layer_1" data-name="Layer 1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 300 157"><title>Supercomputer-logo</title><image width="300" height="157" xlink:href="data:image/png;base64,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"/></svg> \ No newline at end of file diff --git a/messages.py b/messages.py new file mode 100644 index 0000000000000000000000000000000000000000..8895350ee09db1fab6a914699059b06088aeb9d9 --- /dev/null +++ b/messages.py @@ -0,0 +1,3 @@ +welcome_message = "Welcome to UAB's Reseach Computing cluster. The information below will be used to create your account. Please fill in all the details as this helps us understand our user base. Contact <a href='mailto:someone@yoursite.com'>Research Computing</a> for any assistance in creating your account." +cancel_message = "Close browser to end session. Contact <a href="'mailto:someone@yoursite.com'">Research Computing</a> for any assistance in creating your account." +error_message = "Error while creating your account. We've been notified about this. Contact <a href="'mailto:someone@yoursite.com'">Research Computing</a> for any assistance in creating your account." diff --git a/rabbit_config.py b/rabbit_config.py deleted file mode 100644 index 70081fc0f4bb46c6d90e10a300cf126fadb0877b..0000000000000000000000000000000000000000 --- a/rabbit_config.py +++ /dev/null @@ -1,6 +0,0 @@ -Exchange = 'RegUsr' -User = 'reggie' -Password = 'reggie' -VHost = '/' -Server = 'ohpc' -Port = 5672 diff --git a/rc_rmq.py b/rc_rmq.py deleted file mode 100644 index 37afa3f44f872454a3b96fccf2d5a6a538fe01cf..0000000000000000000000000000000000000000 --- a/rc_rmq.py +++ /dev/null @@ -1,116 +0,0 @@ -import json -import pika -import socket -import rabbit_config as rcfg - -class RCRMQ(object): - - USER = 'guest' - PASSWORD = 'guest' - HOST = 'localhost' - PORT = 5672 - VHOST = '/' - EXCHANGE = '' - EXCHANGE_TYPE = 'direct' - QUEUE = None - DURABLE = True - ROUTING_KEY = None - DEBUG = False - - def __init__(self, config=None, debug=False): - if config: - if 'exchange' in config: - self.EXCHANGE = config['exchange'] - if 'exchange_type' in config: - self.EXCHANGE_TYPE = config['exchange_type'] - - hostname = socket.gethostname().split(".", 1)[0] - - self.HOST = rcfg.Server if hostname != rcfg.Server else "localhost" - self.USER = rcfg.User - self.PASSWORD = rcfg.Password - self.VHOST = rcfg.VHost - self.PORT = rcfg.Port - self.DEBUG = debug - - if self.DEBUG: - print(""" - Created RabbitMQ instance with: - Exchange name: {}, - Exchange type: {}, - Host: {}, - User: {}, - VHost: {}, - Port: {} - """.format(self.EXCHANGE, self.EXCHANGE_TYPE, self.HOST, self.USER, self.VHOST, self.PORT)) - - self._consumer_tag = None - self._connection = None - self._consuming = False - self._channel = None - self._parameters = pika.ConnectionParameters( - self.HOST, - self.PORT, - self.VHOST, - pika.PlainCredentials(self.USER, self.PASSWORD)) - - def connect(self): - if self.DEBUG: - print("Connecting...\n" + "Exchange: " + self.EXCHANGE + " Exchange type: " + self.EXCHANGE_TYPE) - - self._connection = pika.BlockingConnection(self._parameters) - self._channel = self._connection.channel() - self._channel.exchange_declare( - exchange=self.EXCHANGE, - exchange_type=self.EXCHANGE_TYPE, - durable=True) - - def bind_queue(self): - self._channel.queue_declare(queue=self.QUEUE, durable=self.DURABLE) - self._channel.queue_bind(exchange=self.EXCHANGE, - queue=self.QUEUE, - routing_key=self.ROUTING_KEY) - - def disconnect(self): - self._channel.close() - self._connection.close() - self._connection = None - - def delete_queue(self): - self._channel.queue_delete(self.QUEUE) - - def publish_msg(self, obj): - if 'routing_key' in obj: - self.ROUTING_KEY = obj['routing_key'] - - if self._connection is None: - self.connect() - - self._channel.basic_publish(exchange=self.EXCHANGE, - routing_key=self.ROUTING_KEY, - body=json.dumps(obj['msg'])) - - def start_consume(self, obj): - if 'queue' in obj: - self.QUEUE = obj['queue'] - self.ROUTING_KEY = obj['routing_key'] if 'routing_key' in obj else self.QUEUE - if 'durable' in obj: - self.DURABLE = obj['durable'] - - if self.DEBUG: - print("Queue: " + self.QUEUE + "\nRouting_key: " + self.ROUTING_KEY) - - if self._connection is None: - self.connect() - - self.bind_queue() - - self._consumer_tag = self._channel.basic_consume(self.QUEUE,obj['cb']) - self._consuming = True - try: - self._channel.start_consuming() - except KeyboardInterrupt: - self._channel.stop_consuming() - - def stop_consume(self): - self._channel.basic_cancel(self._consumer_tag) diff --git a/rc_util.py b/rc_util.py deleted file mode 100644 index 0e7c4c1e6ec7d0cba4cc7370cf35370efa7f7354..0000000000000000000000000000000000000000 --- a/rc_util.py +++ /dev/null @@ -1,72 +0,0 @@ -import logging -import argparse -from rc_rmq import RCRMQ -import json - -rc_rmq = RCRMQ({'exchange': 'RegUsr', 'exchange_type': 'topic'}) -tasks = {'ohpc_account': None, 'ood_account': None, 'slurm_account': None} -logger_fmt = '%(asctime)s [%(module)s] - %(message)s' - -def add_account(username, email, full='', reason=''): - rc_rmq.publish_msg({ - 'routing_key': 'request.' + username, - 'msg': { - "username": username, - "email": email, - "fullname": full, - "reason": reason - } - }) - rc_rmq.disconnect() - -def worker(ch, method, properties, body): - msg = json.loads(body) - task = msg['task'] - tasks[task] = msg['success'] - print("Got msg: {}({})".format(msg['task'], msg['success'])) - - # Check if all tasks are done - done = True - for key, status in tasks.items(): - if not status: - print("{} is not done yet.".format(key)) - done = False - if done: - rc_rmq.stop_consume() - rc_rmq.delete_queue() - -def consume(username, callback=worker, debug=False): - if debug: - sleep(5) - else: - rc_rmq.start_consume({ - 'queue': username, - 'routing_key': 'confirm.' + username, - 'cb': callback - }) - rc_rmq.disconnect() - - return { 'success' : True } - -def get_args(): - # Parse arguments - parser = argparse.ArgumentParser() - parser.add_argument('-v', '--verbose', action='store_true', help='verbose output') - parser.add_argument('-n', '--dry-run', action='store_true', help='enable dry run mode') - return parser.parse_args() - -def get_logger(args=None): - if args is None: - args = get_args() - - logger_lvl = logging.WARNING - - if args.verbose: - logger_lvl = logging.DEBUG - - if args.dry_run: - logger_lvl = logging.INFO - - logging.basicConfig(format=logger_fmt, level=logger_lvl) - return logging.getLogger(__name__) - diff --git a/run.py b/run.py index 1232ae6e5f0e6e41f340e6951e754a5b886294a4..226a79f1b715c91b6b87c044e298b5f4e3f42687 100644 --- a/run.py +++ b/run.py @@ -7,9 +7,7 @@ import vars from flask import session from flask_socketio import SocketIO, join_room - from app import create_app - from gevent import monkey monkey.patch_all(subprocess=True) @@ -18,18 +16,14 @@ app = create_app(config_name) app.config['SECRET_KEY'] = vars.key socketio = SocketIO(app, message_queue= vars.message_queue) - - @socketio.on('join_room') def on_room(json): - room = str(session['uid']) referrer = json['referrer'] join_room(room) print('\t\t\t|-----Room ID: ' + room) print('\t\t\t|-----Referrer: ' + referrer) - @socketio.on('request account') def request_account(json, methods=['GET', 'POST']): print (time.strftime("%m-%d-%Y_%H:%M:%S") + '\tQueue request received: ' + str(json)) @@ -41,6 +35,5 @@ def request_account(json, methods=['GET', 'POST']): print(time.strftime("%m-%d-%Y_%H:%M:%S") + "\tError in account creation: ", e) socketio.emit("Account creation failed", room) - if __name__ == '__main__': socketio.run(app, host='0.0.0.0') diff --git a/tasks.py b/tasks.py index fe371fbd81bd360986b07afd99987e535a542ce7..6888829bdf9c71b83f9ca653bb43d80cfbb0c3a6 100644 --- a/tasks.py +++ b/tasks.py @@ -1,23 +1,48 @@ -from celery import Celery +import vars +import sys +import json import time +import signal + +from celery import Celery from flask_socketio import SocketIO -import subprocess -import vars -import rc_util -from gevent import monkey -monkey.patch_all(subprocess=True) +sys.path.append('/cm/shared/rabbitmq_agents/') +import rc_util broker_url = vars.broker_url celery = Celery('flask_user_reg', broker=broker_url) socketio = SocketIO(message_queue=vars.message_queue) - +timeout = 30 + +def gen_f(room): + def callback(channel, method, properties, body): + msg = json.loads(body) + username = msg['username'] + + if msg['success']: + print(f'Account for {username} has been created.') + send_msg('account ready', room) + else: + print(f"There's some issue while creating account for {username}") + errmsg = msg.get('errmsg', []) + for err in errmsg: + print(err) + socketio.emit('account error', errmsg, room= room) + + rc_util.rc_rmq.stop_consume() + rc_util.rc_rmq.delete_queue() + return callback def send_msg(event, room): - print("Post '{}' to room '{}'".format(event,room)) - socketio.emit(event, room=room) + socketio.emit(event, room=room) +def timeout_handler(signum, frame): + print("Process timeout, there's might some issue with agents") + socketio.emit('account error', errmsg, room= room) + rc_util.rc_rmq.stop_consume() + rc_util.rc_rmq.delete_queue() @celery.task def celery_create_account(json, session): @@ -26,11 +51,12 @@ def celery_create_account(json, session): email= json['email'] fullname= json['fullname'] reason= json['reason'] + queuename= rc_util.encode_name(username) print(time.strftime("%m-%d-%Y_%H:%M:%S") + '\tUser ' + username + ' added to queue') send_msg('creating account', room) print(username) - rc_util.add_account(username, email, fullname, reason) - rc_util.consume(username) - print(time.strftime("%m-%d-%Y_%H:%M:%S") + '\tAccount successfully created for ' + username) - send_msg('account ready', room) + rc_util.add_account(username, queuename, email, fullname, reason) + print('sent account info') + print('Waiting for completion...') + rc_util.consume(queuename, routing_key=f'complete.{queuename}', callback=gen_f(room)) diff --git a/vars.py b/vars.py deleted file mode 100644 index 41249880a3d18ee7e7b813060e1c511fea23dadd..0000000000000000000000000000000000000000 --- a/vars.py +++ /dev/null @@ -1,9 +0,0 @@ -id = '' -password = '' -key = '' -broker_url = 'amqp://' + id + ':' + password + '@ohpc:5672/' -message_queue = broker_url + 'socketio' -default_referrer = "/pun/sys/dashboard" -username_key = ["REMOTE_USER"] -fullname_key = ["HTTP_DISPLAYNAME"] -email_key = ["HTTP_MAIL"]