diff --git a/portal/__init__.py b/portal/__init__.py index adf7e9e..72bad37 100644 --- a/portal/__init__.py +++ b/portal/__init__.py @@ -1,16 +1,13 @@ from flask import Flask from flask_wtf.csrf import CSRFProtect from datetime import timedelta -import json # from flask import Markup -from flask_misaka import markdown from flask_misaka import Misaka import logging.handlers -import logging import sys -__author__ = 'Jeremy Van ' +__author__ = "MANIAC Lab " app = Flask(__name__) # Enable CSRF protection globally for Flask app @@ -26,13 +23,24 @@ print("Could not read config location from {}".format(sys.argv[1])) else: print("Reading config file from local directory") - app.config.from_pyfile('portal.conf') + app.config.from_pyfile("portal.conf") app.url_map.strict_slashes = False app.permanent_session_lifetime = timedelta(minutes=1440) -app.config.update(SESSION_COOKIE_SECURE=True, SESSION_COOKIE_HTTPONLY=True, SESSION_COOKIE_SAMESITE='Lax') +app.config.update( + SESSION_COOKIE_SECURE=True, + SESSION_COOKIE_HTTPONLY=True, + SESSION_COOKIE_SAMESITE="Lax", +) # set up Markdown Rendering md = Misaka() -md.__init__(app, tables=True, autolink=True, fenced_code=True, smartypants=True, quote=True, math=True, math_explicit=True) - -import portal.views +md.__init__( + app, + tables=True, + autolink=True, + fenced_code=True, + smartypants=True, + quote=True, + math=True, + math_explicit=True, +) diff --git a/portal/connect_api.py b/portal/connect_api.py index 7351cba..65b02cc 100644 --- a/portal/connect_api.py +++ b/portal/connect_api.py @@ -4,14 +4,15 @@ import json # Read configurable tokens and endpoints from config file, values must be set -ciconnect_api_token = app.config['CONNECT_API_TOKEN'] -ciconnect_api_endpoint = app.config['CONNECT_API_ENDPOINT'] +ciconnect_api_token = app.config["CONNECT_API_TOKEN"] +ciconnect_api_endpoint = app.config["CONNECT_API_ENDPOINT"] -try: - user_access_token = get_user_access_token(session) - query = {'token': user_access_token} -except: - query = {'token': ciconnect_api_token} +# get_user_access_token seems to be undefined here +# try: +# user_access_token = get_user_access_token(session) +# query = {"token": user_access_token} +# except: +query = {"token": ciconnect_api_token} def connect_name(group_name): @@ -20,13 +21,13 @@ def connect_name(group_name): :param group_name: unix string name of group :return: string of connect name """ - connect_name = '.'.join(group_name.split('.')[:2]) + connect_name = ".".join(group_name.split(".")[:2]) return connect_name def query_status_code(query_response): if query_response.status_code == requests.codes.ok: - query_return = query_response.json()['items'] + query_return = query_response.json()["items"] else: query_return = [] return query_return @@ -39,25 +40,26 @@ def get_multiplex(json): :return: [{state, name, state_set_by}] """ multiplex = requests.post( - ciconnect_api_endpoint + '/v1alpha1/multiplex', params=query, json=json) + ciconnect_api_endpoint + "/v1alpha1/multiplex", params=query, json=json + ) multiplex = multiplex.json() return multiplex + ############################# ##### USER ###### ############################# + def get_user_info(session): """ Returns object of user information :param session: user session to pull primary_identity :return: object {kind: User, apiVersion: v1alpha1, metadata: {access_token, unix_name}} """ - query = {'token': ciconnect_api_token, - 'globus_id': session['primary_identity']} + query = {"token": ciconnect_api_token, "globus_id": session["primary_identity"]} - user = requests.get(ciconnect_api_endpoint + - '/v1alpha1/find_user', params=query) + user = requests.get(ciconnect_api_endpoint + "/v1alpha1/find_user", params=query) user = user.json() return user @@ -68,12 +70,13 @@ def get_user_group_memberships(session, unix_name): :param session: user session to pull primary_identity :return: {query: {status: response, body: { apiVersion, kind, metadata: {} } }} """ - query = {'token': ciconnect_api_token, - 'globus_id': session['primary_identity']} + query = {"token": ciconnect_api_token, "globus_id": session["primary_identity"]} users_group_memberships = requests.get( - ciconnect_api_endpoint + '/v1alpha1/users/' + unix_name + '/groups', params=query) - users_group_memberships = users_group_memberships.json()['group_memberships'] + ciconnect_api_endpoint + "/v1alpha1/users/" + unix_name + "/groups", + params=query, + ) + users_group_memberships = users_group_memberships.json()["group_memberships"] return users_group_memberships @@ -85,13 +88,17 @@ def get_user_group_status(unix_name, group_name, session): :param session: user session to pull primary_identity :return: string """ - query = {'token': ciconnect_api_token, - 'globus_id': session['primary_identity']} + query = {"token": ciconnect_api_token, "globus_id": session["primary_identity"]} user_status = requests.get( - ciconnect_api_endpoint + '/v1alpha1/groups/' + - group_name + '/members/' + unix_name, params=query) - user_status = user_status.json()['membership']['state'] + ciconnect_api_endpoint + + "/v1alpha1/groups/" + + group_name + + "/members/" + + unix_name, + params=query, + ) + user_status = user_status.json()["membership"]["state"] return user_status @@ -103,12 +110,12 @@ def get_user_pending_project_requests(unix_name): :param connect_group: string name of connect group :return: string (active, admin, nonmember) """ - query = {'token': ciconnect_api_token} - pending_project_requests = requests.get(ciconnect_api_endpoint - + '/v1alpha1/users/' - + unix_name - + '/group_requests', params=query) - pending_project_requests = pending_project_requests.json()['groups'] + query = {"token": ciconnect_api_token} + pending_project_requests = requests.get( + ciconnect_api_endpoint + "/v1alpha1/users/" + unix_name + "/group_requests", + params=query, + ) + pending_project_requests = pending_project_requests.json()["groups"] return pending_project_requests @@ -119,15 +126,20 @@ def get_user_connect_status(unix_name, connect_group): :param connect_group: string name of connect group :return: string (active, admin, nonmember) """ - connect_status = requests.get(ciconnect_api_endpoint + '/v1alpha1/users/' - + unix_name + '/groups/' - + connect_group, params=query) - connect_status = connect_status.json()['membership']['state'] + connect_status = requests.get( + ciconnect_api_endpoint + + "/v1alpha1/users/" + + unix_name + + "/groups/" + + connect_group, + params=query, + ) + connect_status = connect_status.json()["membership"]["state"] return connect_status def get_enclosing_group_status(group_name, unix_name): - enclosing_group_name = '.'.join(group_name.split('.')[:-1]) + enclosing_group_name = ".".join(group_name.split(".")[:-1]) if enclosing_group_name: enclosing_status = get_user_connect_status(unix_name, enclosing_group_name) else: @@ -136,22 +148,24 @@ def get_enclosing_group_status(group_name, unix_name): def enclosing_admin_status(session, group_name): - group_split = group_name.split('.') + group_split = group_name.split(".") admin = False enclosing_group = group_split[0] - + while group_split and not admin: - enclosing_group += '.{}'.format(group_split.pop(0)) - if get_user_connect_status(session['unix_name'], enclosing_group) == 'admin': + enclosing_group += ".{}".format(group_split.pop(0)) + if get_user_connect_status(session["unix_name"], enclosing_group) == "admin": admin = True else: enclosing_group return admin + ############################# ##### GROUP ###### ############################# + def get_group_info(group_name, session): """ Returns group details @@ -159,35 +173,37 @@ def get_group_info(group_name, session): :return: dict object """ access_token = get_user_access_token(session) - query = {'token': access_token} - group_info = requests.get(ciconnect_api_endpoint + '/v1alpha1/groups/' - + group_name, params=query) - group_info = group_info.json()['metadata'] + query = {"token": access_token} + group_info = requests.get( + ciconnect_api_endpoint + "/v1alpha1/groups/" + group_name, params=query + ) + group_info = group_info.json()["metadata"] return group_info def get_group_members(group_name, session): access_token = get_user_access_token(session) - query = {'token': access_token} + query = {"token": access_token} group_members = requests.get( - ciconnect_api_endpoint + '/v1alpha1/groups/' + group_name + '/members', params=query) - group_members = group_members.json()['memberships'] + ciconnect_api_endpoint + "/v1alpha1/groups/" + group_name + "/members", + params=query, + ) + group_members = group_members.json()["memberships"] return group_members def get_group_members_emails(group_name): - query = {'token': ciconnect_api_token} + query = {"token": ciconnect_api_token} group_members = get_group_members(group_name, session) multiplexJson = {} users_statuses = {} # Get detailed user information from list of users for user in group_members: - unix_name = user['user_name'] - user_state = user['state'] - if (user_state != 'nonmember' and unix_name != 'root'): - user_query = "/v1alpha1/users/" + \ - unix_name + "?token=" + query['token'] + unix_name = user["user_name"] + user_state = user["state"] + if user_state != "nonmember" and unix_name != "root": + user_query = "/v1alpha1/users/" + unix_name + "?token=" + query["token"] multiplexJson[user_query] = {"method": "GET"} users_statuses[unix_name] = user_state @@ -197,12 +213,12 @@ def get_group_members_emails(group_name): group_user_dict = {} for user in multiplex: - user_name = user.split('/')[3].split('?')[0] - user_dict[user_name] = json.loads(multiplex[user]['body']) + user_name = user.split("/")[3].split("?")[0] + user_dict[user_name] = json.loads(multiplex[user]["body"]) for user, info in user_dict.items(): - for group_membership in info['metadata']['group_memberships']: - if group_membership['name'] == group_name: + for group_membership in info["metadata"]["group_memberships"]: + if group_membership["name"] == group_name: group_user_dict[user] = info return user_dict, users_statuses @@ -215,10 +231,11 @@ def delete_group_entry(group_name, session): :return: """ access_token = get_user_access_token(session) - query = {'token': access_token} + query = {"token": access_token} r = requests.delete( - ciconnect_api_endpoint + '/v1alpha1/groups/' + group_name, params=query) + ciconnect_api_endpoint + "/v1alpha1/groups/" + group_name, params=query + ) return r @@ -230,12 +247,13 @@ def get_subgroups(group_name, session): :return: list of dict objects """ access_token = get_user_access_token(session) - query = {'token': access_token} + query = {"token": access_token} subgroups = requests.get( - ciconnect_api_endpoint + '/v1alpha1/groups/' - + group_name + '/subgroups', params=query) - subgroups = subgroups.json()['groups'] + ciconnect_api_endpoint + "/v1alpha1/groups/" + group_name + "/subgroups", + params=query, + ) + subgroups = subgroups.json()["groups"] return subgroups @@ -249,14 +267,18 @@ def update_user_group_status(group_name, unix_name, status, session): :return: """ access_token = get_user_access_token(session) - query = {'token': access_token, - 'globus_id': session['primary_identity']} + query = {"token": access_token, "globus_id": session["primary_identity"]} - put_query = {"apiVersion": 'v1alpha1', - 'group_membership': {'state': status}} + put_query = {"apiVersion": "v1alpha1", "group_membership": {"state": status}} user_status = requests.put( - ciconnect_api_endpoint + '/v1alpha1/groups/' + - group_name + '/members/' + unix_name, params=query, json=put_query) + ciconnect_api_endpoint + + "/v1alpha1/groups/" + + group_name + + "/members/" + + unix_name, + params=query, + json=put_query, + ) return user_status @@ -265,31 +287,35 @@ def list_connect_admins(group_name): Return list of admins of connect group Return list of nested dictionaries with state, user_name, and state_set_by """ - query = {'token': ciconnect_api_token} + query = {"token": ciconnect_api_token} group_members = requests.get( - ciconnect_api_endpoint + '/v1alpha1/groups/' - + connect_name(group_name) + '/members', params=query) - memberships = group_members.json()['memberships'] - memberships = [member for member in memberships if member['state'] == 'admin'] + ciconnect_api_endpoint + + "/v1alpha1/groups/" + + connect_name(group_name) + + "/members", + params=query, + ) + memberships = group_members.json()["memberships"] + memberships = [member for member in memberships if member["state"] == "admin"] return memberships def get_user_profile(unix_name): - identity_id = session.get('primary_identity') + identity_id = session.get("primary_identity") - query = {'token': ciconnect_api_token, - 'globus_id': identity_id} + query = {"token": ciconnect_api_token, "globus_id": identity_id} profile = requests.get( - ciconnect_api_endpoint + '/v1alpha1/users/' + unix_name, params=query) + ciconnect_api_endpoint + "/v1alpha1/users/" + unix_name, params=query + ) if profile.status_code == requests.codes.ok: profile = profile.json() return profile else: - err_message = profile.json()['message'] + err_message = profile.json()["message"] print(err_message) return None @@ -297,7 +323,7 @@ def get_user_profile(unix_name): def get_user_access_token(session): user = get_user_info(session) if user: - access_token = user['metadata']['access_token'] + access_token = user["metadata"]["access_token"] else: access_token = None return access_token @@ -305,15 +331,15 @@ def get_user_access_token(session): def domain_name_edgecase(): """""" - domain_name = request.headers['Host'] - - if 'usatlas' in domain_name: - domain_name = 'atlas.ci-connect.net' - elif 'uscms' in domain_name: - domain_name = 'cms.ci-connect.net' - elif 'uchicago' in domain_name: - domain_name = 'psdconnect.uchicago.edu' - elif 'snowmass21' in domain_name: - domain_name = 'snowmass21.ci-connect.net' - - return domain_name \ No newline at end of file + domain_name = request.headers["Host"] + + if "usatlas" in domain_name: + domain_name = "atlas.ci-connect.net" + elif "uscms" in domain_name: + domain_name = "cms.ci-connect.net" + elif "uchicago" in domain_name: + domain_name = "psdconnect.uchicago.edu" + elif "snowmass21" in domain_name: + domain_name = "snowmass21.ci-connect.net" + + return domain_name diff --git a/portal/decorators.py b/portal/decorators.py index 022e7a9..9258117 100644 --- a/portal/decorators.py +++ b/portal/decorators.py @@ -4,21 +4,25 @@ def authenticated(fn): """Mark a route as requiring authentication.""" + @wraps(fn) def decorated_function(*args, **kwargs): - if not session.get('is_authenticated'): - return redirect(url_for('login', next=request.url)) + if not session.get("is_authenticated"): + return redirect(url_for("login", next=request.url)) - if request.path == '/logout': + if request.path == "/logout": return fn(*args, **kwargs) - if (not session.get('name') or - not session.get('email') or - not session.get('institution')) and request.path != '/profile': - return redirect(url_for('create_profile', next=request.url)) + if ( + not session.get("name") + or not session.get("email") + or not session.get("institution") + ) and request.path != "/profile": + return redirect(url_for("create_profile", next=request.url)) - if (not session.get('unix_name') and request.path != '/profile/new'): - return redirect(url_for('create_profile', next=request.url)) + if not session.get("unix_name") and request.path != "/profile/new": + return redirect(url_for("create_profile", next=request.url)) return fn(*args, **kwargs) + return decorated_function diff --git a/portal/slate_api.py b/portal/slate_api.py index 6d4f40c..15de7f2 100644 --- a/portal/slate_api.py +++ b/portal/slate_api.py @@ -1,16 +1,15 @@ -from flask import session import requests import os from base64 import b64encode from portal import app -from portal.connect_api import get_user_profile -slate_api_token = app.config['SLATE_API_TOKEN'] -slate_api_endpoint = app.config['SLATE_API_ENDPOINT'] -query = {'token': slate_api_token} +slate_api_token = app.config["SLATE_API_TOKEN"] +slate_api_endpoint = app.config["SLATE_API_ENDPOINT"] +query = {"token": slate_api_token} # Install Jupyter + def generateToken(): token_bytes = os.urandom(32) b64_encoded = b64encode(token_bytes).decode() @@ -18,35 +17,46 @@ def generateToken(): def get_app_config(app_name): - query = {'token': slate_api_token, 'dev': 'true'} + query = {"token": slate_api_token, "dev": "true"} app_config = requests.get( - slate_api_endpoint + '/v1alpha3/apps/' + app_name, params=query) + slate_api_endpoint + "/v1alpha3/apps/" + app_name, params=query + ) return app_config def get_app_readme(app_name): - query = {'token': slate_api_token, 'dev': 'true'} + query = {"token": slate_api_token, "dev": "true"} app_readme = requests.get( - slate_api_endpoint + '/v1alpha3/apps/' + app_name + '/info', params=query) + slate_api_endpoint + "/v1alpha3/apps/" + app_name + "/info", params=query + ) return app_readme + def create_application(): """ Query SLATE API to create application based on config, group, and cluster :return: """ - app_name = 'jupyter-notebook' - group = 'group_2Q9yPCOLxMg' - cluster = 'uchicago-river-v2' + app_name = "jupyter-notebook" + group = "group_2Q9yPCOLxMg" + cluster = "uchicago-river-v2" configuration = get_app_config(app_name) - configuration = configuration.json()['spec']['body'] + configuration = configuration.json()["spec"]["body"] - install_app = {"apiVersion": 'v1alpha3', "group": group, "cluster": cluster, "configuration": configuration} + install_app = { + "apiVersion": "v1alpha3", + "group": group, + "cluster": cluster, + "configuration": configuration, + } # Post query to install application config app_install = requests.post( - slate_api_endpoint + '/v1alpha3/apps/' + app_name, params=query, json=install_app) + slate_api_endpoint + "/v1alpha3/apps/" + app_name, + params=query, + json=install_app, + ) print("APP INSTALL STATUS: {}".format(app_install)) print("APP NAME: {}".format(app_name)) @@ -54,49 +64,44 @@ def create_application(): create_application = query_status_code(app_install) return create_application + # Users def get_user_info(session): - query = {'token': slate_api_token, - 'globus_id': session['primary_identity']} + query = {"token": slate_api_token, "globus_id": session["primary_identity"]} - profile = requests.get( - slate_api_endpoint + '/v1alpha3/find_user', params=query) + profile = requests.get(slate_api_endpoint + "/v1alpha3/find_user", params=query) profile = profile.json() - user_id = profile['metadata']['id'] - access_token = profile['metadata']['access_token'] + user_id = profile["metadata"]["id"] + access_token = profile["metadata"]["access_token"] return access_token, user_id def get_user_id(session): - query = {'token': slate_api_token, - 'globus_id': session['primary_identity']} + query = {"token": slate_api_token, "globus_id": session["primary_identity"]} - profile = requests.get( - slate_api_endpoint + '/v1alpha3/find_user', params=query) + profile = requests.get(slate_api_endpoint + "/v1alpha3/find_user", params=query) profile = profile.json() - user_id = profile['metadata']['id'] + user_id = profile["metadata"]["id"] return user_id def get_user_access_token(session): - query = {'token': slate_api_token, - 'globus_id': session['primary_identity']} + query = {"token": slate_api_token, "globus_id": session["primary_identity"]} - profile = requests.get( - slate_api_endpoint + '/v1alpha3/find_user', params=query) + profile = requests.get(slate_api_endpoint + "/v1alpha3/find_user", params=query) profile = profile.json() - access_token = profile['metadata']['access_token'] + access_token = profile["metadata"]["access_token"] return access_token def delete_user(userID, query): - res = requests.delete(slate_api_endpoint + '/v1alpha3/' + userID, params=query) + res = requests.delete(slate_api_endpoint + "/v1alpha3/" + userID, params=query) print(res) res = res.json() print(res) @@ -109,13 +114,13 @@ def connect_name(group_name): :param group_name: unix string name of group :return: string of connect name """ - connect_name = '.'.join(group_name.split('.')[:2]) + connect_name = ".".join(group_name.split(".")[:2]) return connect_name def query_status_code(query_response): if query_response.status_code == requests.codes.ok: - query_return = query_response.json()['items'] + query_return = query_response.json()["items"] else: query_return = [] return query_return @@ -126,8 +131,7 @@ def list_applications_request(): Returns list of all applications on slate :return: list of slate applications """ - applications = requests.get( - slate_api_endpoint + '/v1alpha3/apps') + applications = requests.get(slate_api_endpoint + "/v1alpha3/apps") applications = query_status_code(applications) return applications @@ -136,8 +140,7 @@ def list_incubator_applications_request(): """ Request query to list incubator applications information """ - incubator_apps = requests.get( - slate_api_endpoint + '/v1alpha3/apps?dev=true') + incubator_apps = requests.get(slate_api_endpoint + "/v1alpha3/apps?dev=true") # incubator_apps = incubator_apps.json()['items'] incubator_apps = query_status_code(incubator_apps) return incubator_apps @@ -148,9 +151,8 @@ def list_public_groups_request(): Returns list of all public groups on slate :return: list of public groups """ - public_groups = requests.get( - slate_api_endpoint + '/v1alpha3/groups', params=query) - public_groups = public_groups.json()['items'] + public_groups = requests.get(slate_api_endpoint + "/v1alpha3/groups", params=query) + public_groups = public_groups.json()["items"] return public_groups @@ -159,9 +161,8 @@ def list_clusters_request(): Returns list of all clusters on slate :return: list of slate clusters """ - clusters = requests.get( - slate_api_endpoint + '/v1alpha3/clusters', params=query) - clusters = clusters.json()['items'] + clusters = requests.get(slate_api_endpoint + "/v1alpha3/clusters", params=query) + clusters = clusters.json()["items"] return clusters @@ -170,21 +171,22 @@ def list_instances_request(): Returns list of all instances on slate :return: list of slate instances """ - instances = requests.get( - slate_api_endpoint + '/v1alpha3/instances', params=query) + instances = requests.get(slate_api_endpoint + "/v1alpha3/instances", params=query) # print("TRYING GET INSTANCES LIST WITH URL: {}".format(instances.url)) # print("RESPONSE: {}".format(instances.json())) - instances = instances.json()['items'] + instances = instances.json()["items"] return instances + def get_instance_details(instance_id): """ Returns json detail of specific instance on slate :return: json object of slate instance details """ - query = {'token': slate_api_token, 'detailed': 'true'} + query = {"token": slate_api_token, "detailed": "true"} instance_detail = requests.get( - slate_api_endpoint + '/v1alpha3/instances/' + instance_id, params=query) + slate_api_endpoint + "/v1alpha3/instances/" + instance_id, params=query + ) instance_detail = instance_detail.json() return instance_detail @@ -195,7 +197,9 @@ def get_instance_logs(instance_id): :return: json object of slate instance details """ instance_logs = requests.get( - slate_api_endpoint + '/v1alpha3/instances/' + instance_id + '/logs', params=query) + slate_api_endpoint + "/v1alpha3/instances/" + instance_id + "/logs", + params=query, + ) instance_logs = instance_logs.json() return instance_logs @@ -206,7 +210,8 @@ def delete_instance(instance_id): :return: request response """ response = requests.delete( - slate_api_endpoint + '/v1alpha3/instances/' + instance_id, params=query) + slate_api_endpoint + "/v1alpha3/instances/" + instance_id, params=query + ) return response @@ -218,9 +223,10 @@ def list_user_groups(session): """ # Get groups to which the user belongs based on CI-Connect user user_groups = requests.get( - slate_api_endpoint + '/v1alpha3/users/' - + 'user_YXRvNlN998A' + '/groups', params=query) - user_groups = user_groups.json()['items'] + slate_api_endpoint + "/v1alpha3/users/" + "user_YXRvNlN998A" + "/groups", + params=query, + ) + user_groups = user_groups.json()["items"] return user_groups @@ -239,17 +245,18 @@ def list_users_instances_request(session): user_groups = [] # Set up nice list of user group's name for groups in user_groups_list: - user_groups.append(groups['metadata']['name']) + user_groups.append(groups["metadata"]["name"]) # print("user_groups: {}".format(user_groups)) # Logic to isolate instances belonging to specific user user_instances = [] for instance in instances: - if (instance['metadata']['group'] in user_groups) and ("-{}-".format(session['unix_name']) in instance['metadata']['name']): + if (instance["metadata"]["group"] in user_groups) and ( + "-{}-".format(session["unix_name"]) in instance["metadata"]["name"] + ): user_instances.append(instance) # print("User instances: {}".format(user_instances)) # Return list of instances in sorted order - sorted_instances = sorted( - user_instances, key=lambda i: i['metadata']['name']) + sorted_instances = sorted(user_instances, key=lambda i: i["metadata"]["name"]) return sorted_instances @@ -258,11 +265,15 @@ def list_connect_admins(group_name): Return list of admins of connect group Return list of nested dictionaries with state, user_name, and state_set_by """ - query = {'token': slate_api_token} + query = {"token": slate_api_token} group_members = requests.get( - slate_api_endpoint + '/v1alpha1/groups/' - + connect_name(group_name) + '/members', params=query) - memberships = group_members.json()['memberships'] - memberships = [member for member in memberships if member['state'] == 'admin'] - - return memberships \ No newline at end of file + slate_api_endpoint + + "/v1alpha1/groups/" + + connect_name(group_name) + + "/members", + params=query, + ) + memberships = group_members.json()["memberships"] + memberships = [member for member in memberships if member["state"] == "admin"] + + return memberships diff --git a/portal/templates/base.html b/portal/templates/base.html index ab25e5a..b7cd261 100644 --- a/portal/templates/base.html +++ b/portal/templates/base.html @@ -8,7 +8,7 @@ - + {# Favicons for Connect #} diff --git a/portal/utils.py b/portal/utils.py index 3ac186f..fc8ba5d 100644 --- a/portal/utils.py +++ b/portal/utils.py @@ -2,6 +2,7 @@ from threading import Lock import globus_sdk + try: import ConfigParser as configparser except: @@ -15,11 +16,11 @@ from portal import app from portal.connect_api import domain_name_edgecase -brand_dir = app.config['MARKDOWN_DIR'] +brand_dir = app.config["MARKDOWN_DIR"] def flash_message_parser(route_name): - + # domain_name = request.headers['Host'] # if 'usatlas' in domain_name: # domain_name = 'atlas.ci-connect.net' @@ -33,16 +34,16 @@ def flash_message_parser(route_name): domain_name = domain_name_edgecase() # print(domain_name) config = configparser.RawConfigParser(allow_no_value=True) - config.read(brand_dir + '/' + domain_name + - '/flash_messages/flash_messages.cfg') - flash_message = config.get('flash_messages', route_name) + config.read(brand_dir + "/" + domain_name + "/flash_messages/flash_messages.cfg") + flash_message = config.get("flash_messages", route_name) return flash_message def load_portal_client(): """Create an AuthClient for the portal""" return globus_sdk.ConfidentialAppAuthClient( - app.config['PORTAL_CLIENT_ID'], app.config['PORTAL_CLIENT_SECRET']) + app.config["PORTAL_CLIENT_ID"], app.config["PORTAL_CLIENT_SECRET"] + ) def is_safe_redirect_url(target): @@ -50,13 +51,15 @@ def is_safe_redirect_url(target): host_url = urlparse(request.host_url) redirect_url = urlparse(urljoin(request.host_url, target)) - return redirect_url.scheme in ('http', 'https') and \ - host_url.netloc == redirect_url.netloc + return ( + redirect_url.scheme in ("http", "https") + and host_url.netloc == redirect_url.netloc + ) def get_safe_redirect(): """https://security.openstack.org/guidelines/dg_avoid-unvalidated-redirects.html""" # noqa - url = request.args.get('next') + url = request.args.get("next") if url and is_safe_redirect_url(url): return url @@ -64,11 +67,12 @@ def get_safe_redirect(): if url and is_safe_redirect_url(url): return url - return '/' + return "/" def get_portal_tokens( - scopes=['openid', 'urn:globus:auth:scope:demo-resource-server:all']): + scopes=["openid", "urn:globus:auth:scope:demo-resource-server:all"] +): """ Uses the client_credentials grant to get access tokens on the Portal's "client identity." @@ -77,23 +81,24 @@ def get_portal_tokens( if not get_portal_tokens.access_tokens: get_portal_tokens.access_tokens = {} - scope_string = ' '.join(scopes) + scope_string = " ".join(scopes) client = load_portal_client() - tokens = client.oauth2_client_credentials_tokens( - requested_scopes=scope_string) + tokens = client.oauth2_client_credentials_tokens(requested_scopes=scope_string) # walk all resource servers in the token response (includes the # top-level server, as found in tokens.resource_server), and store the # relevant Access Tokens for resource_server, token_info in tokens.by_resource_server.items(): - get_portal_tokens.access_tokens.update({ - resource_server: { - 'token': token_info['access_token'], - 'scope': token_info['scope'], - 'expires_at': token_info['expires_at_seconds'] + get_portal_tokens.access_tokens.update( + { + resource_server: { + "token": token_info["access_token"], + "scope": token_info["scope"], + "expires_at": token_info["expires_at_seconds"], + } } - }) + ) return get_portal_tokens.access_tokens diff --git a/portal/views.py b/portal/views.py index f8f3179..c7caa79 100644 --- a/portal/views.py +++ b/portal/views.py @@ -1,25 +1,29 @@ -from flask import (flash, redirect, render_template, request, - session, url_for, jsonify) +from flask import flash, redirect, render_template, request, session, url_for import requests -import json try: # Python 2 - from urllib.parse import urlparse, urlencode, parse_qs + from urllib.parse import urlparse, parse_qs except ImportError: # Python 3 from urlparse import urlparse, parse_qs - from urllib import urlencode from portal import app, csrf from portal.decorators import authenticated -from portal.utils import (load_portal_client, get_safe_redirect, flash_message_parser) -from portal.connect_api import (get_user_info, get_user_group_memberships, - get_multiplex, get_user_connect_status, - get_user_pending_project_requests, - get_group_info, get_group_members, - delete_group_entry, update_user_group_status, - get_user_access_token, domain_name_edgecase, get_user_profile, get_user_group_status) +from portal.utils import load_portal_client, get_safe_redirect, flash_message_parser +from portal.connect_api import ( + get_user_info, + get_user_connect_status, + get_group_info, + get_group_members, + delete_group_entry, + update_user_group_status, + get_user_access_token, + domain_name_edgecase, + get_user_profile, + get_user_group_status, +) + # Use these four lines on container import sys import subprocess @@ -27,21 +31,17 @@ import signal # Read configurable tokens and endpoints from config file, values must be set -ciconnect_api_token = app.config['CONNECT_API_TOKEN'] -ciconnect_api_endpoint = app.config['CONNECT_API_ENDPOINT'] -mailgun_api_token = app.config['MAILGUN_API_TOKEN'] +ciconnect_api_token = app.config["CONNECT_API_TOKEN"] +ciconnect_api_endpoint = app.config["CONNECT_API_ENDPOINT"] +mailgun_api_token = app.config["MAILGUN_API_TOKEN"] # Read Brand Dir from config and insert path to read -brand_dir = app.config['MARKDOWN_DIR'] +brand_dir = app.config["MARKDOWN_DIR"] sys.path.insert(0, brand_dir) # Set sys path and import view routes -sys.path.insert(1, 'portal/views') -import group_views -import error_handling -import users_groups -import slate_views +sys.path.insert(1, "portal/views") -@app.route('/webhooks/github', methods=['GET', 'POST']) +@app.route("/webhooks/github", methods=["GET", "POST"]) @csrf.exempt def webhooks(): """Endpoint that acepts post requests from Github Webhooks""" @@ -49,10 +49,17 @@ def webhooks(): cmd = """ cd {} git pull origin master - """.format(brand_dir) - - p = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE, - stderr=subprocess.PIPE, stdin=subprocess.PIPE) + """.format( + brand_dir + ) + + p = subprocess.Popen( + cmd, + shell=True, + stdout=subprocess.PIPE, + stderr=subprocess.PIPE, + stdin=subprocess.PIPE, + ) out, err = p.communicate() print("Return code: {}".format(p.returncode)) print("Error message: {}".format(err)) @@ -64,461 +71,605 @@ def webhooks(): return out -@app.route('/', methods=['GET']) +@app.route("/", methods=["GET"]) def home(): """Home page - play with it if you must!""" domain_name = domain_name_edgecase() - - with open(brand_dir + '/' + domain_name + '/home_content/home_text_headline.md', "r") as file: + + with open( + brand_dir + "/" + domain_name + "/home_content/home_text_headline.md", "r" + ) as file: home_text_headline = file.read() - with open(brand_dir + '/' + domain_name + '/home_content/home_text_rotating.md', "r") as file: + with open( + brand_dir + "/" + domain_name + "/home_content/home_text_rotating.md", "r" + ) as file: home_text_rotating = file.read() - collaborations = [{'name': 'Atlas', - 'href': 'https://connect.usatlas.org', - 'img': 'img/atlas-connect-logo.png', - 'description': get_about_markdown("atlas.ci-connect.net")}, - {'name': 'CMS', - 'href': 'https://connect.uscms.org', - 'img': 'img/cms-connect-logo.png', - 'description': get_about_markdown("cms.ci-connect.net")}, - {'name': 'Duke', - 'href': 'https://duke.ci-connect.net', - 'img': 'img/duke-connect-logo.png', - 'description': get_about_markdown("duke.ci-connect.net")}, - {'name': 'OSG', - 'href': 'https://www.osgconnect.net', - 'img': 'img/osg-connect-logo.png', - 'description': get_about_markdown("osgconnect.net")}, - {'name': 'SPT', - 'href': 'https://spt.ci-connect.net', - 'img': 'img/spt-connect-logo.png', - 'description': get_about_markdown("spt.ci-connect.net")}, - {'name': 'PSD', - 'href': 'https://psdconnect.uchicago.edu', - 'img': 'img/psd-connect-logo.png', - 'description': get_about_markdown("psdconnect.uchicago.edu")}, - {'name': 'Snowmass21', - 'href': 'https://connect.snowmass21.io', - 'img': 'img/snowmass-connect-logo.png', - 'description': get_about_markdown("snowmass21.ci-connect.net")}] - - return render_template('home.html', home_text_headline=home_text_headline, - home_text_rotating=home_text_rotating, - collaborations=collaborations) + collaborations = [ + { + "name": "Atlas", + "href": "https://connect.usatlas.org", + "img": "img/atlas-connect-logo.png", + "description": get_about_markdown("atlas.ci-connect.net"), + }, + { + "name": "CMS", + "href": "https://connect.uscms.org", + "img": "img/cms-connect-logo.png", + "description": get_about_markdown("cms.ci-connect.net"), + }, + { + "name": "Duke", + "href": "https://duke.ci-connect.net", + "img": "img/duke-connect-logo.png", + "description": get_about_markdown("duke.ci-connect.net"), + }, + { + "name": "OSG", + "href": "https://www.osgconnect.net", + "img": "img/osg-connect-logo.png", + "description": get_about_markdown("osgconnect.net"), + }, + { + "name": "SPT", + "href": "https://spt.ci-connect.net", + "img": "img/spt-connect-logo.png", + "description": get_about_markdown("spt.ci-connect.net"), + }, + { + "name": "PSD", + "href": "https://psdconnect.uchicago.edu", + "img": "img/psd-connect-logo.png", + "description": get_about_markdown("psdconnect.uchicago.edu"), + }, + { + "name": "Snowmass21", + "href": "https://connect.snowmass21.io", + "img": "img/snowmass-connect-logo.png", + "description": get_about_markdown("snowmass21.ci-connect.net"), + }, + ] + + return render_template( + "home.html", + home_text_headline=home_text_headline, + home_text_rotating=home_text_rotating, + collaborations=collaborations, + ) def get_about_markdown(domain_name): - with open(brand_dir + '/' + domain_name + '/about/about.md', "r") as file: + with open(brand_dir + "/" + domain_name + "/about/about.md", "r") as file: about = file.read() return about -@app.route('/groups/new', methods=['GET', 'POST']) + +@app.route("/groups/new", methods=["GET", "POST"]) @authenticated def create_group(): """Create groups""" access_token = get_user_access_token(session) - query = {'token': access_token} + query = {"token": access_token} print(query) - if request.method == 'GET': - sciences = requests.get( - ciconnect_api_endpoint + '/v1alpha1/fields_of_science') - sciences = sciences.json()['fields_of_science'] - return render_template('groups_create.html', sciences=sciences) - elif request.method == 'POST': - name = request.form['name'] - email = request.form['email'] - phone = request.form['phone'] - description = request.form['description'] + if request.method == "GET": + sciences = requests.get(ciconnect_api_endpoint + "/v1alpha1/fields_of_science") + sciences = sciences.json()["fields_of_science"] + return render_template("groups_create.html", sciences=sciences) + elif request.method == "POST": + name = request.form["name"] + email = request.form["email"] + phone = request.form["phone"] + description = request.form["description"] try: # Purpose/Field of Science for CMS will always be High Energy Physics - field_of_science = request.form['field_of_science'] + field_of_science = request.form["field_of_science"] except: field_of_science = "High Energy Physics" - put_group = {"apiVersion": 'v1alpha1', "kind": "Group", - 'metadata': {'name': name, - 'field_of_science': field_of_science, - 'email': email, 'phone': phone, - 'description': description}} + put_group = { + "apiVersion": "v1alpha1", + "kind": "Group", + "metadata": { + "name": name, + "field_of_science": field_of_science, + "email": email, + "phone": phone, + "description": description, + }, + } create_group = requests.put( - ciconnect_api_endpoint + '/v1alpha1/groups/root/subgroups/' + name, params=query, json=put_group) + ciconnect_api_endpoint + "/v1alpha1/groups/root/subgroups/" + name, + params=query, + json=put_group, + ) if create_group.status_code == requests.codes.ok: - flash_message = flash_message_parser('create_group') - flash(flash_message, 'success') - return redirect(url_for('groups')) + flash_message = flash_message_parser("create_group") + flash(flash_message, "success") + return redirect(url_for("groups")) else: - err_message = create_group.json()['message'] - flash('Failed to create group: {}'.format(err_message), 'warning') - return redirect(url_for('groups')) + err_message = create_group.json()["message"] + flash("Failed to create group: {}".format(err_message), "warning") + return redirect(url_for("groups")) -@app.route('/groups//delete', methods=['POST']) +@app.route("/groups//delete", methods=["POST"]) @authenticated def delete_group(group_name): - if request.method == 'POST': + if request.method == "POST": r = delete_group_entry(group_name, session) if r.status_code == requests.codes.ok: - flash_message = flash_message_parser('delete_group') - flash(flash_message, 'success') - return redirect(url_for('groups')) + flash_message = flash_message_parser("delete_group") + flash(flash_message, "success") + return redirect(url_for("groups")) else: - err_message = r.json()['message'] - flash('Failed to delete group: {}'.format(err_message), 'warning') - return redirect(url_for('view_group', group_name=group_name)) + err_message = r.json()["message"] + flash("Failed to delete group: {}".format(err_message), "warning") + return redirect(url_for("view_group", group_name=group_name)) -@app.route('/groups//add_group_member/', methods=['POST']) +@app.route("/groups//add_group_member/", methods=["POST"]) @authenticated def add_group_member(group_name, unix_name): - if request.method == 'POST': + if request.method == "POST": # Add user to group by setting user status to active - status = 'active' + status = "active" user_status = update_user_group_status(group_name, unix_name, status, session) if user_status.status_code == requests.codes.ok: - flash_message = flash_message_parser('add_group_member') - flash(flash_message, 'success') - return redirect(url_for('view_group_members', group_name=group_name)) + flash_message = flash_message_parser("add_group_member") + flash(flash_message, "success") + return redirect(url_for("view_group_members", group_name=group_name)) else: - err_message = user_status.json()['message'] - flash('Failed to add member to group: {}'.format( - err_message), 'warning') - return redirect(url_for('view_group_members', group_name=group_name)) + err_message = user_status.json()["message"] + flash("Failed to add member to group: {}".format(err_message), "warning") + return redirect(url_for("view_group_members", group_name=group_name)) -@app.route('/groups//delete_group_member/', methods=['POST']) +@app.route("/groups//delete_group_member/", methods=["POST"]) @authenticated def remove_group_member(group_name, unix_name): - if request.method == 'POST': + if request.method == "POST": access_token = get_user_access_token(session) - query = {'token': access_token} + query = {"token": access_token} try: - message = request.form['denial-message'] - denial_message = {'message': message} + message = request.form["denial-message"] + denial_message = {"message": message} remove_user = requests.delete( - ciconnect_api_endpoint + '/v1alpha1/groups/' + - group_name + '/members/' + unix_name, params=query, json=denial_message) + ciconnect_api_endpoint + + "/v1alpha1/groups/" + + group_name + + "/members/" + + unix_name, + params=query, + json=denial_message, + ) except: remove_user = requests.delete( - ciconnect_api_endpoint + '/v1alpha1/groups/' + - group_name + '/members/' + unix_name, params=query) + ciconnect_api_endpoint + + "/v1alpha1/groups/" + + group_name + + "/members/" + + unix_name, + params=query, + ) if remove_user.status_code == requests.codes.ok: - flash_message = flash_message_parser('remove_group_member') - flash(flash_message, 'success') - return redirect(url_for('view_group_members', group_name=group_name)) + flash_message = flash_message_parser("remove_group_member") + flash(flash_message, "success") + return redirect(url_for("view_group_members", group_name=group_name)) else: - err_message = remove_user.json()['message'] - flash('Failed to remove member from group: {}'.format( - err_message), 'warning') - return redirect(url_for('view_group_members', group_name=group_name)) + err_message = remove_user.json()["message"] + flash( + "Failed to remove member from group: {}".format(err_message), "warning" + ) + return redirect(url_for("view_group_members", group_name=group_name)) -@app.route('/groups//admin_group_member/', methods=['POST']) +@app.route("/groups//admin_group_member/", methods=["POST"]) @authenticated def admin_group_member(group_name, unix_name): - if request.method == 'POST': - status = 'admin' + if request.method == "POST": + status = "admin" user_status = update_user_group_status(group_name, unix_name, status, session) if user_status.status_code == requests.codes.ok: - flash_message = flash_message_parser('admin_group_member') - flash(flash_message, 'success') - return redirect(url_for('view_group_members', group_name=group_name)) + flash_message = flash_message_parser("admin_group_member") + flash(flash_message, "success") + return redirect(url_for("view_group_members", group_name=group_name)) else: - err_message = user_status.json()['message'] - flash('Failed make member an admin: {}'.format( - err_message), 'warning') - return redirect(url_for('view_group_members', group_name=group_name)) + err_message = user_status.json()["message"] + flash("Failed make member an admin: {}".format(err_message), "warning") + return redirect(url_for("view_group_members", group_name=group_name)) -@app.route('/groups//subgroups/new', methods=['GET', 'POST']) +@app.route("/groups//subgroups/new", methods=["GET", "POST"]) @authenticated def create_subgroup(group_name): access_token = get_user_access_token(session) - query = {'token': access_token} - if request.method == 'GET': - sciences = requests.get( - ciconnect_api_endpoint + '/v1alpha1/fields_of_science') - sciences = sciences.json()['fields_of_science'] + query = {"token": access_token} + if request.method == "GET": + sciences = requests.get(ciconnect_api_endpoint + "/v1alpha1/fields_of_science") + sciences = sciences.json()["fields_of_science"] # Get group members group_members = get_group_members(group_name, session) # Return list of admins of group try: group_admins = [ - member for member in group_members if member['state'] == 'admin'] + member for member in group_members if member["state"] == "admin" + ] except: group_admins = [] # Check if user status of root connect group specifically - connect_group = session['url_host']['unix_name'] - unix_name = session['unix_name'] + connect_group = session["url_host"]["unix_name"] + unix_name = session["unix_name"] user_status = get_user_connect_status(unix_name, connect_group) # Get group information group = get_group_info(group_name, session) - return render_template('groups_create.html', sciences=sciences, - group_name=group_name, group_admins=group_admins, - user_status=user_status, group=group) - - elif request.method == 'POST': - name = request.form['name'] - display_name = request.form['display-name'] - email = request.form['email'] - phone = request.form['phone'] - description = request.form['description'] + return render_template( + "groups_create.html", + sciences=sciences, + group_name=group_name, + group_admins=group_admins, + user_status=user_status, + group=group, + ) + + elif request.method == "POST": + name = request.form["name"] + display_name = request.form["display-name"] + email = request.form["email"] + phone = request.form["phone"] + description = request.form["description"] try: # Purpose/Field of Science for CMS will always be High Energy Physics - field_of_science = request.form['field_of_science'] + field_of_science = request.form["field_of_science"] except: field_of_science = "High Energy Physics" - put_query = {"apiVersion": 'v1alpha1', - 'metadata': {'name': name, 'display_name': display_name, - 'purpose': field_of_science, - 'email': email, 'phone': phone, - 'description': description}} + put_query = { + "apiVersion": "v1alpha1", + "metadata": { + "name": name, + "display_name": display_name, + "purpose": field_of_science, + "email": email, + "phone": phone, + "description": description, + }, + } r = requests.put( - ciconnect_api_endpoint + '/v1alpha1/groups/' + group_name + - '/subgroup_requests/' + name, params=query, json=put_query) - full_created_group_name = group_name + '.' + name + ciconnect_api_endpoint + + "/v1alpha1/groups/" + + group_name + + "/subgroup_requests/" + + name, + params=query, + json=put_query, + ) + full_created_group_name = group_name + "." + name # Check if user status of root connect group specifically - connect_group = session['url_host']['unix_name'] - unix_name = session['unix_name'] + connect_group = session["url_host"]["unix_name"] + unix_name = session["unix_name"] user_status = get_user_connect_status(unix_name, connect_group) if r.status_code == requests.codes.ok: - if user_status == 'admin': - flash_message = flash_message_parser('create_subgroup') - flash(flash_message, 'success') - return redirect(url_for('view_group', group_name=full_created_group_name)) + if user_status == "admin": + flash_message = flash_message_parser("create_subgroup") + flash(flash_message, "success") + return redirect( + url_for("view_group", group_name=full_created_group_name) + ) else: flash( - "The support team has been notified of your requested subgroup.", 'success') - return redirect(url_for('users_groups_pending')) + "The support team has been notified of your requested subgroup.", + "success", + ) + return redirect(url_for("users_groups_pending")) else: - err_message = r.json()['message'] - flash('Failed to request project creation: {}'.format( - err_message), 'warning') - return redirect(url_for('view_group_subgroups_requests', group_name=group_name)) + err_message = r.json()["message"] + flash( + "Failed to request project creation: {}".format(err_message), "warning" + ) + return redirect( + url_for("view_group_subgroups_requests", group_name=group_name) + ) -@app.route('/groups//requests/edit', methods=['GET', 'POST']) +@app.route("/groups//requests/edit", methods=["GET", "POST"]) @authenticated def edit_subgroup_requests(group_name): access_token = get_user_access_token(session) - query = {'token': access_token} - enclosing_group_name = '.'.join(group_name.split('.')[:-1]) - if request.method == 'GET': - sciences = requests.get( - ciconnect_api_endpoint + '/v1alpha1/fields_of_science') - sciences = sciences.json()['fields_of_science'] + query = {"token": access_token} + enclosing_group_name = ".".join(group_name.split(".")[:-1]) + if request.method == "GET": + sciences = requests.get(ciconnect_api_endpoint + "/v1alpha1/fields_of_science") + sciences = sciences.json()["fields_of_science"] group = get_group_info(group_name, session) - return render_template('groups_requests_edit.html', sciences=sciences, - group_name=group_name, group=group) + return render_template( + "groups_requests_edit.html", + sciences=sciences, + group_name=group_name, + group=group, + ) - elif request.method == 'POST': - name = request.form['name'] - display_name = request.form['display-name'] - email = request.form['email'] - phone = request.form['phone'] - description = request.form['description'] + elif request.method == "POST": + name = request.form["name"] + display_name = request.form["display-name"] + email = request.form["email"] + phone = request.form["phone"] + description = request.form["description"] - new_unix_name = enclosing_group_name + '.' + name + new_unix_name = enclosing_group_name + "." + name if new_unix_name == group_name: - put_query = {"apiVersion": 'v1alpha1', - 'metadata': {'display_name': display_name, - 'email': email, 'phone': phone, - 'description': description}} + put_query = { + "apiVersion": "v1alpha1", + "metadata": { + "display_name": display_name, + "email": email, + "phone": phone, + "description": description, + }, + } else: - put_query = {"apiVersion": 'v1alpha1', - 'metadata': {'name': name, - 'display_name': display_name, - 'email': email, 'phone': phone, - 'description': description}} + put_query = { + "apiVersion": "v1alpha1", + "metadata": { + "name": name, + "display_name": display_name, + "email": email, + "phone": phone, + "description": description, + }, + } r = requests.put( - ciconnect_api_endpoint + '/v1alpha1/groups/' + group_name, params=query, json=put_query) + ciconnect_api_endpoint + "/v1alpha1/groups/" + group_name, + params=query, + json=put_query, + ) - enclosing_group_name = '.'.join(group_name.split('.')[:-1]) + enclosing_group_name = ".".join(group_name.split(".")[:-1]) if r.status_code == requests.codes.ok: - flash_message = flash_message_parser('edit_subgroup_requests') - flash(flash_message, 'success') - return redirect(url_for('users_groups_pending')) + flash_message = flash_message_parser("edit_subgroup_requests") + flash(flash_message, "success") + return redirect(url_for("users_groups_pending")) else: - err_message = r.json()['message'] - flash('Failed to edit subgroup request: {}'.format( - err_message), 'warning') - return redirect(url_for('edit_subgroup_requests', group_name=group_name, - name=name, display_name=display_name, - email=email, phone=phone, - description=description)) - - -@app.route('/groups//edit', methods=['GET', 'POST']) + err_message = r.json()["message"] + flash("Failed to edit subgroup request: {}".format(err_message), "warning") + return redirect( + url_for( + "edit_subgroup_requests", + group_name=group_name, + name=name, + display_name=display_name, + email=email, + phone=phone, + description=description, + ) + ) + + +@app.route("/groups//edit", methods=["GET", "POST"]) @authenticated def edit_subgroup(group_name): access_token = get_user_access_token(session) - query = {'token': access_token} - if request.method == 'GET': - sciences = requests.get( - ciconnect_api_endpoint + '/v1alpha1/fields_of_science') - sciences = sciences.json()['fields_of_science'] + query = {"token": access_token} + if request.method == "GET": + sciences = requests.get(ciconnect_api_endpoint + "/v1alpha1/fields_of_science") + sciences = sciences.json()["fields_of_science"] group = get_group_info(group_name, session) - return render_template('groups_edit.html', sciences=sciences, - group_name=group_name, group=group) - - elif request.method == 'POST': - display_name = request.form['display-name'] - email = request.form['email'] - phone = request.form['phone'] - description = request.form['description'] + return render_template( + "groups_edit.html", sciences=sciences, group_name=group_name, group=group + ) - put_query = {"apiVersion": 'v1alpha1', - 'metadata': {'display_name': display_name, - 'email': email, 'phone': phone, - 'description': description}} + elif request.method == "POST": + display_name = request.form["display-name"] + email = request.form["email"] + phone = request.form["phone"] + description = request.form["description"] + + put_query = { + "apiVersion": "v1alpha1", + "metadata": { + "display_name": display_name, + "email": email, + "phone": phone, + "description": description, + }, + } r = requests.put( - ciconnect_api_endpoint + '/v1alpha1/groups/' + group_name, params=query, json=put_query) + ciconnect_api_endpoint + "/v1alpha1/groups/" + group_name, + params=query, + json=put_query, + ) if r.status_code == requests.codes.ok: - flash_message = flash_message_parser('edit_subgroup') - flash(flash_message, 'success') - return redirect(url_for('view_group', group_name=group_name)) + flash_message = flash_message_parser("edit_subgroup") + flash(flash_message, "success") + return redirect(url_for("view_group", group_name=group_name)) else: - err_message = r.json()['message'] - flash('Failed to update subgroup information: {}'.format( - err_message), 'warning') - return redirect(url_for('edit_subgroup', group_name=group_name)) + err_message = r.json()["message"] + flash( + "Failed to update subgroup information: {}".format(err_message), + "warning", + ) + return redirect(url_for("edit_subgroup", group_name=group_name)) -@app.route('/groups//subgroups//approve', methods=['GET']) +@app.route("/groups//subgroups//approve", methods=["GET"]) @authenticated def approve_subgroup(group_name, subgroup_name): access_token = get_user_access_token(session) - query = {'token': access_token} - if request.method == 'GET': + query = {"token": access_token} + if request.method == "GET": r = requests.put( - ciconnect_api_endpoint + '/v1alpha1/groups/' + group_name + - '/subgroup_requests/' + subgroup_name + '/approve', params=query) + ciconnect_api_endpoint + + "/v1alpha1/groups/" + + group_name + + "/subgroup_requests/" + + subgroup_name + + "/approve", + params=query, + ) if r.status_code == requests.codes.ok: - flash_message = flash_message_parser('approve_subgroup') - flash(flash_message, 'success') - return redirect(url_for('view_group_subgroups_requests', group_name=group_name)) + flash_message = flash_message_parser("approve_subgroup") + flash(flash_message, "success") + return redirect( + url_for("view_group_subgroups_requests", group_name=group_name) + ) else: - err_message = r.json()['message'] - flash('Failed to approve subgroup creation: {}'.format( - err_message), 'warning') - return redirect(url_for('view_group_subgroups_requests', group_name=group_name)) + err_message = r.json()["message"] + flash( + "Failed to approve subgroup creation: {}".format(err_message), "warning" + ) + return redirect( + url_for("view_group_subgroups_requests", group_name=group_name) + ) -@app.route('/groups//subgroups//deny', methods=['POST']) +@app.route("/groups//subgroups//deny", methods=["POST"]) @authenticated def deny_subgroup(group_name, subgroup_name): access_token = get_user_access_token(session) - query = {'token': access_token} - if request.method == 'POST': - message = request.form['denial-message'] - denial_message = {'message': message} + query = {"token": access_token} + if request.method == "POST": + message = request.form["denial-message"] + denial_message = {"message": message} r = requests.delete( - ciconnect_api_endpoint + '/v1alpha1/groups/' + group_name + - '/subgroup_requests/' + subgroup_name, params=query, json=denial_message) + ciconnect_api_endpoint + + "/v1alpha1/groups/" + + group_name + + "/subgroup_requests/" + + subgroup_name, + params=query, + json=denial_message, + ) if r.status_code == requests.codes.ok: - flash_message = flash_message_parser('deny_subgroup') - flash(flash_message, 'success') - return redirect(url_for('view_group_subgroups_requests', group_name=group_name)) + flash_message = flash_message_parser("deny_subgroup") + flash(flash_message, "success") + return redirect( + url_for("view_group_subgroups_requests", group_name=group_name) + ) else: - err_message = r.json()['message'] - flash('Failed to deny subgroup request: {}'.format( - err_message), 'warning') - return redirect(url_for('view_group_subgroups_requests', group_name=group_name)) + err_message = r.json()["message"] + flash("Failed to deny subgroup request: {}".format(err_message), "warning") + return redirect( + url_for("view_group_subgroups_requests", group_name=group_name) + ) -@app.route('/signup', methods=['GET']) +@app.route("/signup", methods=["GET"]) def signup(): """Send the user to Globus Auth with signup=1.""" domain_name = domain_name_edgecase() - with open(brand_dir + '/' + domain_name + '/signup_content/signup_modal.md', "r") as file: + with open( + brand_dir + "/" + domain_name + "/signup_content/signup_modal.md", "r" + ) as file: signup_modal_md = file.read() - with open(brand_dir + '/' + domain_name + '/signup_content/signup_instructions.md', "r") as file: + with open( + brand_dir + "/" + domain_name + "/signup_content/signup_instructions.md", "r" + ) as file: signup_instructions_md = file.read() - with open(brand_dir + '/' + domain_name + '/signup_content/signup.md', "r") as file: + with open(brand_dir + "/" + domain_name + "/signup_content/signup.md", "r") as file: signup_md = file.read() - return render_template('signup.html', signup_modal_md=signup_modal_md, signup_instructions_md=signup_instructions_md, signup_md=signup_md) + return render_template( + "signup.html", + signup_modal_md=signup_modal_md, + signup_instructions_md=signup_instructions_md, + signup_md=signup_md, + ) -@app.route('/aup', methods=['GET']) +@app.route("/aup", methods=["GET"]) def aup(): """Send the user to Acceptable Use Policy page""" # Read AUP from markdown dir domain_name = domain_name_edgecase() - with open(brand_dir + '/' + domain_name + '/signup_content/signup_modal.md', "r") as file: + with open( + brand_dir + "/" + domain_name + "/signup_content/signup_modal.md", "r" + ) as file: aup_md = file.read() - return render_template('AUP.html', aup_md=aup_md) + return render_template("AUP.html", aup_md=aup_md) -@app.route('/about', methods=['GET']) +@app.route("/about", methods=["GET"]) def about(): """Send the user to the About page""" # Read About from markdown dir domain_name = domain_name_edgecase() - with open(brand_dir + '/' + domain_name + '/about/about.md', "r") as file: + with open(brand_dir + "/" + domain_name + "/about/about.md", "r") as file: about = file.read() - - organizations = [{'name': 'OSG', - 'href': 'https://www.osgconnect.net', - 'img': 'img/osg-org.png', - 'description': "The OSG is providing a job submission service to the member institutions of the the Open Science Grid which are providing opportunistic CPU resources"}, - {'name': 'SLATE', - 'href': 'https://slateci.io/', - 'img': 'img/slate-org.png', - 'description': "The SLATE platform is utilized for job submission services"}, - {'name': 'IRIS-HEP', - 'href': 'https://iris-hep.org/', - 'img': 'img/iris-hep-org.png', - 'description': "The IRIS-HEP Scalable Systems Laboratory provides support for Snowmass21 Connect analysis services"}, - {'name': 'PSD', - 'href': 'https://psdconnect.uchicago.edu', - 'img': 'img/psd-org.png', - 'description': "The Physical Sciences Division of the University of Chicago is providing IT infrastructure supporting the login service and storage"}, - {'name': 'MANIAC lab', - 'href': 'https://maniaclab.uchicago.edu/', - 'img': 'img/maniac-org.png', - 'description': "The team at MANIAC Lab provides the CI-Connect service"}, - {'name': 'Brookhaven National Lab', - 'href': 'https://www.bnl.gov/world/', - 'img': 'img/brookhaven_national_lab.jpg', - 'description': "Brookhaven National Laboratory has pledged to store data from Snowmass21 Monte Carlo simulation activities"}, - {'name': 'Fermilab', - 'href': 'https://www.fnal.gov/', - 'img': 'img/fermilab_plain_logo.jpeg', - 'description': "Fermilab is pledging storage resources for Snowmass21"} - ] - return render_template('about.html', about=about, organizations=organizations) - - -@app.route('/login', methods=['GET']) + + organizations = [ + { + "name": "OSG", + "href": "https://www.osgconnect.net", + "img": "img/osg-org.png", + "description": "The OSG is providing a job submission service to the member institutions of the the Open Science Grid which are providing opportunistic CPU resources", + }, + { + "name": "SLATE", + "href": "https://slateci.io/", + "img": "img/slate-org.png", + "description": "The SLATE platform is utilized for job submission services", + }, + { + "name": "IRIS-HEP", + "href": "https://iris-hep.org/", + "img": "img/iris-hep-org.png", + "description": "The IRIS-HEP Scalable Systems Laboratory provides support for Snowmass21 Connect analysis services", + }, + { + "name": "PSD", + "href": "https://psdconnect.uchicago.edu", + "img": "img/psd-org.png", + "description": "The Physical Sciences Division of the University of Chicago is providing IT infrastructure supporting the login service and storage", + }, + { + "name": "MANIAC lab", + "href": "https://maniaclab.uchicago.edu/", + "img": "img/maniac-org.png", + "description": "The team at MANIAC Lab provides the CI-Connect service", + }, + { + "name": "Brookhaven National Lab", + "href": "https://www.bnl.gov/world/", + "img": "img/brookhaven_national_lab.jpg", + "description": "Brookhaven National Laboratory has pledged to store data from Snowmass21 Monte Carlo simulation activities", + }, + { + "name": "Fermilab", + "href": "https://www.fnal.gov/", + "img": "img/fermilab_plain_logo.jpeg", + "description": "Fermilab is pledging storage resources for Snowmass21", + }, + ] + return render_template("about.html", about=about, organizations=organizations) + + +@app.route("/login", methods=["GET"]) def login(): """Send the user to Globus Auth.""" next_url = get_safe_redirect() - return redirect(url_for('authcallback', next=next_url)) + return redirect(url_for("authcallback", next=next_url)) -@app.route('/logout', methods=['GET']) +@app.route("/logout", methods=["GET"]) @authenticated def logout(): """ @@ -530,81 +681,105 @@ def logout(): # Revoke the tokens with Globus Auth for token, token_type in ( - (token_info[ty], ty) - # get all of the token info dicts - for token_info in session['tokens'].values() - # cross product with the set of token types - for ty in ('access_token', 'refresh_token') - # only where the relevant token is actually present - if token_info[ty] is not None): + (token_info[ty], ty) + # get all of the token info dicts + for token_info in session["tokens"].values() + # cross product with the set of token types + for ty in ("access_token", "refresh_token") + # only where the relevant token is actually present + if token_info[ty] is not None + ): client.oauth2_revoke_token( - token, additional_params={'token_type_hint': token_type}) + token, additional_params={"token_type_hint": token_type} + ) # Destroy the session state session.clear() - redirect_uri = url_for('home', _external=True) + redirect_uri = url_for("home", _external=True) ga_logout_url = [] - ga_logout_url.append(app.config['GLOBUS_AUTH_LOGOUT_URI']) - ga_logout_url.append('?client={}'.format(app.config['PORTAL_CLIENT_ID'])) - ga_logout_url.append('&redirect_uri={}'.format(redirect_uri)) - ga_logout_url.append('&redirect_name=Connect Portal') + ga_logout_url.append(app.config["GLOBUS_AUTH_LOGOUT_URI"]) + ga_logout_url.append("?client={}".format(app.config["PORTAL_CLIENT_ID"])) + ga_logout_url.append("&redirect_uri={}".format(redirect_uri)) + ga_logout_url.append("&redirect_name=Connect Portal") # Redirect the user to the Globus Auth logout page - return redirect(''.join(ga_logout_url)) + return redirect("".join(ga_logout_url)) -@app.route('/profile/new', methods=['GET', 'POST']) +@app.route("/profile/new", methods=["GET", "POST"]) @authenticated def create_profile(): - identity_id = session.get('primary_identity') - institution = session.get('institution') + identity_id = session.get("primary_identity") + institution = session.get("institution") globus_id = identity_id - query = {'token': ciconnect_api_token} - - if request.method == 'GET': - unix_name = '' - phone = '' - public_key = '' - return render_template('profile_create.html', unix_name=unix_name, phone=phone, public_key=public_key) - - elif request.method == 'POST': - name = request.form['name'] - unix_name = request.form['unix_name'] - email = request.form['email'] - phone = request.form['phone-number'] - institution = request.form['institution'] - public_key = request.form['sshpubstring'] - globus_id = session['primary_identity'] + query = {"token": ciconnect_api_token} + + if request.method == "GET": + unix_name = "" + phone = "" + public_key = "" + return render_template( + "profile_create.html", + unix_name=unix_name, + phone=phone, + public_key=public_key, + ) + + elif request.method == "POST": + name = request.form["name"] + unix_name = request.form["unix_name"] + email = request.form["email"] + phone = request.form["phone-number"] + institution = request.form["institution"] + public_key = request.form["sshpubstring"] + globus_id = session["primary_identity"] superuser = False service_account = False # Schema and query for adding users to CI Connect DB if public_key: - post_user = {"apiVersion": 'v1alpha1', - 'metadata': {'globusID': globus_id, 'name': name, 'email': email, - 'phone': phone, 'institution': institution, - 'public_key': public_key, - 'unix_name': unix_name, 'superuser': superuser, - 'service_account': service_account}} + post_user = { + "apiVersion": "v1alpha1", + "metadata": { + "globusID": globus_id, + "name": name, + "email": email, + "phone": phone, + "institution": institution, + "public_key": public_key, + "unix_name": unix_name, + "superuser": superuser, + "service_account": service_account, + }, + } else: - post_user = {"apiVersion": 'v1alpha1', - 'metadata': {'globusID': globus_id, 'name': name, 'email': email, - 'phone': phone, 'institution': institution, - 'unix_name': unix_name, 'superuser': superuser, - 'service_account': service_account}} - r = requests.post(ciconnect_api_endpoint + - '/v1alpha1/users', params=query, json=post_user) + post_user = { + "apiVersion": "v1alpha1", + "metadata": { + "globusID": globus_id, + "name": name, + "email": email, + "phone": phone, + "institution": institution, + "unix_name": unix_name, + "superuser": superuser, + "service_account": service_account, + }, + } + r = requests.post( + ciconnect_api_endpoint + "/v1alpha1/users", params=query, json=post_user + ) # print("REQUEST RESPONSE: {}".format(r)) # print("REQUEST URL: {}".format(r.url)) if r.status_code == requests.codes.ok: - r = r.json()['metadata'] - session['name'] = r['name'] - session['email'] = r['email'] - session['phone'] = r['phone'] - session['institution'] = r['institution'] - session['unix_name'] = r['unix_name'] + r = r.json()["metadata"] + session["name"] = r["name"] + session["email"] = r["email"] + session["phone"] = r["phone"] + session["institution"] = r["institution"] + session["unix_name"] = r["unix_name"] # Auto generate group membership into connect group # put_query = {"apiVersion": 'v1alpha1', @@ -614,162 +789,202 @@ def create_profile(): # '/v1alpha1/groups/' + # session['url_host']['unix_name'] + '/members/' + unix_name, # params=query, json=put_query) - group_name = session['url_host']['unix_name'] - status = 'pending' + group_name = session["url_host"]["unix_name"] + status = "pending" update_user_group_status(group_name, unix_name, status, session) - flash_message = flash_message_parser('create_profile') - flash(flash_message, 'success') + flash_message = flash_message_parser("create_profile") + flash(flash_message, "success") - if 'next' in session: - redirect_to = session['next'] - session.pop('next') - else: - redirect_to = url_for('profile') - return redirect(url_for('profile')) + # This seems to be unused. We never use the redirect_to variable. + if "next" in session: + # redirect_to = session["next"] + session.pop("next") + # else: + # redirect_to = url_for("profile") + return redirect(url_for("profile")) else: - error_msg = r.json()['message'] - flash( - 'Failed to create your account: {}'.format(error_msg), 'warning') - return render_template('profile_create.html', name=name, unix_name=unix_name, - email=email, phone=phone, institution=institution, - public_key=public_key) - - -@app.route('/profile/edit/', methods=['GET', 'POST']) + error_msg = r.json()["message"] + flash("Failed to create your account: {}".format(error_msg), "warning") + return render_template( + "profile_create.html", + name=name, + unix_name=unix_name, + email=email, + phone=phone, + institution=institution, + public_key=public_key, + ) + + +@app.route("/profile/edit/", methods=["GET", "POST"]) @authenticated def edit_profile(unix_name): - identity_id = session.get('primary_identity') - query = {'token': ciconnect_api_token, - 'globus_id': identity_id} + identity_id = session.get("primary_identity") + query = {"token": ciconnect_api_token, "globus_id": identity_id} user = get_user_info(session) - expected_unix_name = user['metadata']['unix_name'] + expected_unix_name = user["metadata"]["unix_name"] try: unix_name == expected_unix_name except Exception: - return redirect(url_for('handle_exception', e=Exception)) + return redirect(url_for("handle_exception", e=Exception)) - if request.method == 'GET': + if request.method == "GET": # Get user info, pass through as args, convert to json and load input fields profile = get_user_profile(unix_name) - profile = profile['metadata'] - - return render_template('profile_edit.html', profile=profile, unix_name=unix_name) - - elif request.method == 'POST': - name = request.form['name'] - email = request.form['email'] - phone = request.form['phone-number'] - institution = request.form['institution'] - public_key = request.form['sshpubstring'] - globus_id = session['primary_identity'] - x509dn = request.form['x509dn'] + profile = profile["metadata"] + + return render_template( + "profile_edit.html", profile=profile, unix_name=unix_name + ) + + elif request.method == "POST": + name = request.form["name"] + email = request.form["email"] + phone = request.form["phone-number"] + institution = request.form["institution"] + public_key = request.form["sshpubstring"] + x509dn = request.form["x509dn"] access_token = get_user_access_token(session) - query = {'token': access_token, - 'globus_id': identity_id} + query = {"token": access_token, "globus_id": identity_id} # Schema and query for adding users to CI Connect DB - if public_key != ' ': - post_user = {"apiVersion": 'v1alpha1', - 'metadata': {'name': name, 'email': email, - 'phone': phone, 'institution': institution, - 'public_key': public_key, - 'X.509_DN': x509dn}} + if public_key != " ": + post_user = { + "apiVersion": "v1alpha1", + "metadata": { + "name": name, + "email": email, + "phone": phone, + "institution": institution, + "public_key": public_key, + "X.509_DN": x509dn, + }, + } else: - post_user = {"apiVersion": 'v1alpha1', - 'metadata': {'name': name, 'email': email, - 'phone': phone, 'institution': institution, - 'X.509_DN': x509dn}} + post_user = { + "apiVersion": "v1alpha1", + "metadata": { + "name": name, + "email": email, + "phone": phone, + "institution": institution, + "X.509_DN": x509dn, + }, + } # PUT request to update user information - r = requests.put(ciconnect_api_endpoint + '/v1alpha1/users/' + - unix_name, params=query, json=post_user) + requests.put( + ciconnect_api_endpoint + "/v1alpha1/users/" + unix_name, + params=query, + json=post_user, + ) - session['name'] = name - session['email'] = email - session['phone'] = phone - session['institution'] = institution + session["name"] = name + session["email"] = email + session["phone"] = phone + session["institution"] = institution - flash_message = flash_message_parser('edit_profile') - flash(flash_message, 'success') + flash_message = flash_message_parser("edit_profile") + flash(flash_message, "success") - if 'next' in session: - redirect_to = session['next'] - session.pop('next') - else: - redirect_to = url_for('profile') + # As before, not sure that the redirect_to is ever used, and I don't + # know that I understand it well enough to make a direct change in the + # return value. + if "next" in session: + # redirect_to = session["next"] + session.pop("next") + # else: + # redirect_to = url_for("profile") - return redirect(url_for('profile')) + return redirect(url_for("profile")) -@app.route('/profile', methods=['GET']) +@app.route("/profile", methods=["GET"]) @authenticated def profile(): """User profile information. Assocated with a Globus Auth identity.""" - if request.method == 'GET': - identity_id = session.get('primary_identity') + if request.method == "GET": + session.get("primary_identity") try: user = get_user_info(session) - unix_name = user['metadata']['unix_name'] + unix_name = user["metadata"]["unix_name"] profile = get_user_profile(unix_name) except: profile = None if profile: print("Found profile: {}".format(profile)) - profile = profile['metadata'] - unix_name = profile['unix_name'] - group_name = session['url_host']['unix_name'] + profile = profile["metadata"] + unix_name = profile["unix_name"] + group_name = session["url_host"]["unix_name"] user_status = get_user_group_status(unix_name, group_name, session) else: flash( - 'Please complete any missing profile fields and press Save.', 'warning') - return redirect(url_for('create_profile')) + "Please complete any missing profile fields and press Save.", "warning" + ) + return redirect(url_for("create_profile")) - if request.args.get('next'): - session['next'] = get_safe_redirect() + if request.args.get("next"): + session["next"] = get_safe_redirect() group_memberships = [] - for group in profile['group_memberships']: - if ((session['url_host']['unix_name'] in group['name']) and (len(group['name'].split('.')) > 1)): + for group in profile["group_memberships"]: + if (session["url_host"]["unix_name"] in group["name"]) and ( + len(group["name"].split(".")) > 1 + ): group_memberships.append(group) domain_name = domain_name_edgecase() - with open(brand_dir + '/' + domain_name + "/form_descriptions/group_unix_name_description.md", "r") as file: + with open( + brand_dir + + "/" + + domain_name + + "/form_descriptions/group_unix_name_description.md", + "r", + ) as file: group_unix_name_description = file.read() - return render_template('profile.html', profile=profile, - user_status=user_status, - group_memberships=group_memberships, - group_unix_name_description=group_unix_name_description) + return render_template( + "profile.html", + profile=profile, + user_status=user_status, + group_memberships=group_memberships, + group_unix_name_description=group_unix_name_description, + ) -@app.route('/authcallback', methods=['GET']) +@app.route("/authcallback", methods=["GET"]) def authcallback(): """Handles the interaction with Globus Auth.""" # If we're coming back from Globus Auth in an error state, the error # will be in the "error" query string parameter. - if 'error' in request.args: - flash("You could not be logged into the portal: " + - request.args.get('error_description', request.args['error']), 'warning') - return redirect(url_for('home')) + if "error" in request.args: + flash( + "You could not be logged into the portal: " + + request.args.get("error_description", request.args["error"]), + "warning", + ) + return redirect(url_for("home")) # Set up our Globus Auth/OAuth2 state - redirect_uri = url_for('authcallback', _external=True) + redirect_uri = url_for("authcallback", _external=True) client = load_portal_client() client.oauth2_start_flow(redirect_uri, refresh_tokens=True) # If there's no "code" query string parameter, we're in this route # starting a Globus Auth login flow. - if 'code' not in request.args: + if "code" not in request.args: # print("SIGNUP: {} ".format(request.args)) next_url = get_safe_redirect() additional_authorize_params = ( - {'signup': 1} if request.args.get('signup') else {'next': next_url}) + {"signup": 1} if request.args.get("signup") else {"next": next_url} + ) auth_uri = client.oauth2_get_authorize_url( - additional_params=additional_authorize_params) + additional_params=additional_authorize_params + ) print("ADDITIONAL AUTHORIZED PARAMS: {}".format(additional_authorize_params)) print("NEXT URL: {}".format(next_url)) @@ -780,107 +995,129 @@ def authcallback(): print("GOT OUT OF AUTH URI LOOP") next_url = get_safe_redirect() print("NEXT URL: {}".format(next_url)) - code = request.args.get('code') + code = request.args.get("code") tokens = client.oauth2_exchange_code_for_tokens(code) id_token = tokens.decode_id_token(client) session.update( tokens=tokens.by_resource_server, is_authenticated=True, - name=id_token.get('name', ''), - email=id_token.get('email', ''), - institution=id_token.get('organization', ''), - primary_username=id_token.get('preferred_username'), - primary_identity=id_token.get('sub'), + name=id_token.get("name", ""), + email=id_token.get("email", ""), + institution=id_token.get("organization", ""), + primary_username=id_token.get("preferred_username"), + primary_identity=id_token.get("sub"), ) - access_token = session['tokens']['auth.globus.org']['access_token'] + access_token = session["tokens"]["auth.globus.org"]["access_token"] token_introspect = client.oauth2_token_introspect( - token=access_token, include='identity_set') - identity_set = token_introspect.data['identity_set'] + token=access_token, include="identity_set" + ) + identity_set = token_introspect.data["identity_set"] profile = None for identity in identity_set: - query = {'token': ciconnect_api_token, - 'globus_id': identity} + query = {"token": ciconnect_api_token, "globus_id": identity} try: r = requests.get( - ciconnect_api_endpoint + '/v1alpha1/find_user', params=query) + ciconnect_api_endpoint + "/v1alpha1/find_user", params=query + ) # r = get_user_info(session) if r.status_code == requests.codes.ok: user_info = r.json() # user_access_token = user_info['metadata']['access_token'] - unix_name = user_info['metadata']['unix_name'] + unix_name = user_info["metadata"]["unix_name"] profile = requests.get( - ciconnect_api_endpoint + '/v1alpha1/users/' + unix_name, params=query) + ciconnect_api_endpoint + "/v1alpha1/users/" + unix_name, + params=query, + ) profile = profile.json() - session['primary_identity'] = identity + session["primary_identity"] = identity except: print("NO PROFILE FOUND WITH IDENTITY: {}".format(identity)) - connect_keynames = {'atlas': {'name': 'atlas-connect', - 'display_name': 'Atlas Connect', - 'unix_name': 'root.atlas'}, - 'cms': {'name': 'cms-connect', - 'display_name': 'CMS Connect', - 'unix_name': 'root.cms'}, - 'duke': {'name': 'duke-connect', - 'display_name': 'Duke Connect', - 'unix_name': 'root.duke'}, - 'uchicago': {'name': 'uchicago-connect', - 'display_name': 'UChicago Connect', - 'unix_name': 'root.uchicago'}, - 'spt': {'name': 'spt-connect', - 'display_name': 'SPT Connect', - 'unix_name': 'root.spt'}, - 'psdconnect': {'name': 'psd-connect', - 'display_name': 'PSD Connect', - 'unix_name': 'root.uchicago'}, - 'snowmass21': {'name': 'snowmass21-connect', - 'display_name': 'Snowmass21 Connect', - 'unix_name': 'root.snowmass21'}, - 'localhost': {'name': 'snowmass21-connect', - 'display_name': 'Snowmass21 Connect', - 'unix_name': 'root.snowmass21'}} + connect_keynames = { + "atlas": { + "name": "atlas-connect", + "display_name": "Atlas Connect", + "unix_name": "root.atlas", + }, + "cms": { + "name": "cms-connect", + "display_name": "CMS Connect", + "unix_name": "root.cms", + }, + "duke": { + "name": "duke-connect", + "display_name": "Duke Connect", + "unix_name": "root.duke", + }, + "uchicago": { + "name": "uchicago-connect", + "display_name": "UChicago Connect", + "unix_name": "root.uchicago", + }, + "spt": { + "name": "spt-connect", + "display_name": "SPT Connect", + "unix_name": "root.spt", + }, + "psdconnect": { + "name": "psd-connect", + "display_name": "PSD Connect", + "unix_name": "root.uchicago", + }, + "snowmass21": { + "name": "snowmass21-connect", + "display_name": "Snowmass21 Connect", + "unix_name": "root.snowmass21", + }, + "localhost": { + "name": "snowmass21-connect", + "display_name": "Snowmass21 Connect", + "unix_name": "root.snowmass21", + }, + } url_host = request.host try: referrer = urlparse(request.referrer) # print("REFERRER: {}".format(referrer)) queries = parse_qs(referrer.query) # print("QUERIES: {}".format(queries)) - redirect_uri = queries['redirect_uri'][0] + redirect_uri = queries["redirect_uri"][0] # print("REDIRECT URI: {}".format(redirect_uri)) - next_url = queries['next'][0] + next_url = queries["next"][0] # print("AFTER QUERIES NEXT URL: {}".format(next_url)) except: - next_url = '/' - if 'ci-connect' in url_host: - session['url_host'] = {'name': 'ci-connect', - 'display_name': 'CI Connect', - 'unix_name': 'root'} + next_url = "/" + if "ci-connect" in url_host: + session["url_host"] = { + "name": "ci-connect", + "display_name": "CI Connect", + "unix_name": "root", + } for key, value in list(connect_keynames.items()): if key in url_host: - session['url_host'] = value + session["url_host"] = value if profile: - profile = profile['metadata'] - session['name'] = profile['name'] - session['email'] = profile['email'] - session['phone'] = profile['phone'] - session['institution'] = profile['institution'] - session['unix_name'] = profile['unix_name'] - session['url_root'] = request.url_root + profile = profile["metadata"] + session["name"] = profile["name"] + session["email"] = profile["email"] + session["phone"] = profile["phone"] + session["institution"] = profile["institution"] + session["unix_name"] = profile["unix_name"] + session["url_root"] = request.url_root # session['url_host'] = (request.host).split(':')[0] - session['admin'] = admin_check(profile['unix_name']) + session["admin"] = admin_check(profile["unix_name"]) else: - session['url_root'] = request.url_root - return redirect(url_for('create_profile', - next=url_for('profile'))) + session["url_root"] = request.url_root + return redirect(url_for("create_profile", next=url_for("profile"))) # print("FINAL NEXT URL: {}".format(next_url)) - if next_url == '/': - return redirect(url_for('profile')) + if next_url == "/": + return redirect(url_for("profile")) else: return redirect(next_url) @@ -891,9 +1128,15 @@ def admin_check(unix_name): :param unix_name: unix name of user :return: user's status in Connect group """ - query = {'token': ciconnect_api_token} + query = {"token": ciconnect_api_token} # Query to return user's membership status in a group specifically the root connect group r = requests.get( - ciconnect_api_endpoint + '/v1alpha1/users/' + unix_name + '/groups/' + session['url_host']['unix_name'], params=query) - user_status = r.json()['membership']['state'] + ciconnect_api_endpoint + + "/v1alpha1/users/" + + unix_name + + "/groups/" + + session["url_host"]["unix_name"], + params=query, + ) + user_status = r.json()["membership"]["state"] return user_status diff --git a/portal/views/error_handling.py b/portal/views/error_handling.py index 133e34e..77729d1 100644 --- a/portal/views/error_handling.py +++ b/portal/views/error_handling.py @@ -1,26 +1,28 @@ -from flask import (render_template, request) +from flask import render_template, request import traceback import time import sys from werkzeug.exceptions import HTTPException from portal import app + # Create a custom error handler for Exceptions @app.errorhandler(Exception) def exception_occurred(e): trace = traceback.format_tb(sys.exc_info()[2]) - app.logger.error("{0} Traceback occurred:\n".format(time.ctime()) + - "{0}\nTraceback completed".format("n".join(trace))) + app.logger.error( + "{0} Traceback occurred:\n".format(time.ctime()) + + "{0}\nTraceback completed".format("n".join(trace)) + ) trace = "
".join(trace) - trace.replace('\n', '
') - return render_template('error.html', exception=trace, - debug=app.config['DEBUG']) + trace.replace("\n", "
") + return render_template("error.html", exception=trace, debug=app.config["DEBUG"]) -@app.route('/error', methods=['GET']) +@app.route("/error", methods=["GET"]) def errorpage(): - if request.method == 'GET': - return render_template('error.html') + if request.method == "GET": + return render_template("error.html") @app.errorhandler(404) diff --git a/portal/views/group_views.py b/portal/views/group_views.py index 0b3598e..9cf9f01 100644 --- a/portal/views/group_views.py +++ b/portal/views/group_views.py @@ -1,110 +1,126 @@ -from flask import (flash, redirect, render_template, request, - session, url_for, jsonify) +from flask import flash, redirect, render_template, request, session, url_for, jsonify import requests import json -try: - from urllib.parse import urlencode -except ImportError: - from urllib import urlencode - from portal import app from portal.decorators import authenticated -from portal.utils import flash_message_parser -from portal.connect_api import (get_user_info, get_multiplex, - get_user_connect_status, - get_subgroups, get_group_info, - get_group_members, - get_user_group_status, - get_enclosing_group_status, - update_user_group_status, domain_name_edgecase, - get_group_members_emails) +from portal.connect_api import ( + get_user_info, + get_multiplex, + get_user_connect_status, + get_subgroups, + get_group_info, + get_group_members, + get_user_group_status, + get_enclosing_group_status, + update_user_group_status, + domain_name_edgecase, + get_group_members_emails, +) import sys # Read configurable tokens and endpoints from config file, values must be set -ciconnect_api_token = app.config['CONNECT_API_TOKEN'] -ciconnect_api_endpoint = app.config['CONNECT_API_ENDPOINT'] -mailgun_api_token = app.config['MAILGUN_API_TOKEN'] +ciconnect_api_token = app.config["CONNECT_API_TOKEN"] +ciconnect_api_endpoint = app.config["CONNECT_API_ENDPOINT"] +mailgun_api_token = app.config["MAILGUN_API_TOKEN"] # Read Brand Dir from config and insert path to read -brand_dir = app.config['MARKDOWN_DIR'] +brand_dir = app.config["MARKDOWN_DIR"] sys.path.insert(0, brand_dir) -@app.route('/groups', methods=['GET']) +@app.route("/groups", methods=["GET"]) @authenticated def groups(): """Connect groups""" - if request.method == 'GET': - connect_group = session['url_host']['unix_name'] + if request.method == "GET": + connect_group = session["url_host"]["unix_name"] # Get group's subgroups information groups = get_subgroups(connect_group, session) # Filter subgroups directly one level nested under group - group_index = len(connect_group.split('.')) - groups = [group for group in groups if ( - len(group['name'].split('.')) == (group_index + 1) and not group['pending'])] + group_index = len(connect_group.split(".")) + groups = [ + group + for group in groups + if ( + len(group["name"].split(".")) == (group_index + 1) + and not group["pending"] + ) + ] # Check user's member status of connect group specifically - user_status = get_user_connect_status( - session['unix_name'], connect_group) - - domain_name = request.headers['Host'] - - if 'usatlas' in domain_name: - domain_name = 'atlas.ci-connect.net' - elif 'uscms' in domain_name: - domain_name = 'cms.ci-connect.net' - elif 'uchicago' in domain_name: - domain_name = 'psdconnect.uchicago.edu' - elif 'snowmass21' in domain_name: - domain_name = 'snowmass21.ci-connect.net' - - with open(brand_dir + '/' + domain_name + "/form_descriptions/group_unix_name_description.md", "r") as file: + user_status = get_user_connect_status(session["unix_name"], connect_group) + + domain_name = request.headers["Host"] + + if "usatlas" in domain_name: + domain_name = "atlas.ci-connect.net" + elif "uscms" in domain_name: + domain_name = "cms.ci-connect.net" + elif "uchicago" in domain_name: + domain_name = "psdconnect.uchicago.edu" + elif "snowmass21" in domain_name: + domain_name = "snowmass21.ci-connect.net" + + with open( + brand_dir + + "/" + + domain_name + + "/form_descriptions/group_unix_name_description.md", + "r", + ) as file: group_unix_name_description = file.read() - return render_template('groups.html', groups=groups, - user_status=user_status, - group_unix_name_description=group_unix_name_description) + return render_template( + "groups.html", + groups=groups, + user_status=user_status, + group_unix_name_description=group_unix_name_description, + ) -@app.route('/groups/', methods=['GET', 'POST']) +@app.route("/groups/", methods=["GET", "POST"]) @authenticated def view_group(group_name): """Detailed view of specific groups""" - query = {'token': ciconnect_api_token, - 'globus_id': session['primary_identity']} + # Appears unused. + # query = {"token": ciconnect_api_token, "globus_id": session["primary_identity"]} user = get_user_info(session) - unix_name = user['metadata']['unix_name'] + unix_name = user["metadata"]["unix_name"] - if request.method == 'GET': + if request.method == "GET": # Get group information group = get_group_info(group_name, session) # print(group) - group_creation_date = group['creation_date'].split(' ')[0] + group_creation_date = group["creation_date"].split(" ")[0] # Get User's Group Status user_status = get_user_group_status(unix_name, group_name, session) # Query to return user's enclosing group membership status enclosing_status = get_enclosing_group_status(group_name, unix_name) # Query to check user's connect group membership status - connect_group = session['url_host']['unix_name'] + connect_group = session["url_host"]["unix_name"] # print(connect_group) connect_status = get_user_connect_status(unix_name, connect_group) - return render_template('group_profile_overview.html', group=group, - group_name=group_name, user_status=user_status, - enclosing_status=enclosing_status, - connect_status=connect_status, - group_creation_date=group_creation_date) - elif request.method == 'POST': - ''' + return render_template( + "group_profile_overview.html", + group=group, + group_name=group_name, + user_status=user_status, + enclosing_status=enclosing_status, + connect_status=connect_status, + group_creation_date=group_creation_date, + ) + elif request.method == "POST": + """ Request group membership by setting user status to pending - ''' - status = 'pending' + """ + status = "pending" update_user_group_status(group_name, unix_name, status, session) # print("UPDATED MEMBERSHIP: {}".format(user_status)) - return redirect(url_for('view_group', group_name=group_name)) + return redirect(url_for("view_group", group_name=group_name)) -@app.route('/groups-xhr/', methods=['GET']) +@app.route("/groups-xhr/", methods=["GET"]) @authenticated def view_group_ajax(group_name): group, user_status = view_group_ajax_request(group_name) @@ -114,7 +130,7 @@ def view_group_ajax(group_name): def view_group_ajax_request(group_name): # Get user info user = get_user_info(session) - unix_name = user['metadata']['unix_name'] + unix_name = user["metadata"]["unix_name"] # Get group info group = get_group_info(group_name, session) # Get User's Group Status @@ -122,29 +138,33 @@ def view_group_ajax_request(group_name): return group, user_status -@app.route('/groups//members', methods=['GET', 'POST']) +@app.route("/groups//members", methods=["GET", "POST"]) @authenticated def view_group_members(group_name): """Detailed view of group's members""" - if request.method == 'GET': + if request.method == "GET": # Get group information group = get_group_info(group_name, session) # Get User's Group Status - unix_name = session['unix_name'] + unix_name = session["unix_name"] user_status = get_user_group_status(unix_name, group_name, session) # Query to return user's enclosing group's membership status enclosing_status = get_enclosing_group_status(group_name, unix_name) # Query to check user's connect status - connect_group = session['url_host']['unix_name'] + connect_group = session["url_host"]["unix_name"] connect_status = get_user_connect_status(unix_name, connect_group) - return render_template('group_profile_members.html', group_name=group_name, - user_status=user_status, group=group, - connect_status=connect_status, - enclosing_status=enclosing_status) + return render_template( + "group_profile_members.html", + group_name=group_name, + user_status=user_status, + group=group, + connect_status=connect_status, + enclosing_status=enclosing_status, + ) -@app.route('/groups-xhr//members', methods=['GET']) +@app.route("/groups-xhr//members", methods=["GET"]) @authenticated def view_group_members_ajax(group_name): user_dict, users_statuses = view_group_members_ajax_request(group_name) @@ -153,18 +173,17 @@ def view_group_members_ajax(group_name): def view_group_members_ajax_request(group_name): """Detailed view of group's members""" - query = {'token': ciconnect_api_token} - if request.method == 'GET': + query = {"token": ciconnect_api_token} + if request.method == "GET": group_members = get_group_members(group_name, session) multiplexJson = {} users_statuses = {} # Get detailed user information from list of users for user in group_members: - unix_name = user['user_name'] - user_state = user['state'] - if (user_state != 'nonmember' and unix_name != 'root'): - user_query = "/v1alpha1/users/" + \ - unix_name + "?token=" + query['token'] + unix_name = user["user_name"] + user_state = user["state"] + if user_state != "nonmember" and unix_name != "root": + user_query = "/v1alpha1/users/" + unix_name + "?token=" + query["token"] multiplexJson[user_query] = {"method": "GET"} users_statuses[unix_name] = user_state @@ -174,18 +193,18 @@ def view_group_members_ajax_request(group_name): group_user_dict = {} for user in multiplex: - user_name = user.split('/')[3].split('?')[0] - user_dict[user_name] = json.loads(multiplex[user]['body']) + user_name = user.split("/")[3].split("?")[0] + user_dict[user_name] = json.loads(multiplex[user]["body"]) for user, info in user_dict.items(): - for group_membership in info['metadata']['group_memberships']: - if group_membership['name'] == group_name: + for group_membership in info["metadata"]["group_memberships"]: + if group_membership["name"] == group_name: group_user_dict[user] = info return user_dict, users_statuses -@app.route('/groups-pending-members-count-xhr//members', methods=['GET']) +@app.route("/groups-pending-members-count-xhr//members", methods=["GET"]) @authenticated def group_pending_members_count_ajax(group_name): pending_user_count = group_pending_members_count_request(group_name) @@ -194,23 +213,23 @@ def group_pending_members_count_ajax(group_name): def group_pending_members_count_request(group_name): """Get a group's pending members count""" - if request.method == 'GET': + if request.method == "GET": group_members = get_group_members(group_name, session) pending_user_count = 0 for user in group_members: - if user['state'] == 'pending': + if user["state"] == "pending": pending_user_count += 1 return pending_user_count -@app.route('/groups//members-requests', methods=['GET', 'POST']) +@app.route("/groups//members-requests", methods=["GET", "POST"]) @authenticated def view_group_members_requests(group_name): """Detailed view of group's pending members""" - query = {'token': ciconnect_api_token} - if request.method == 'GET': + query = {"token": ciconnect_api_token} + if request.method == "GET": # Get group information and group members group = get_group_info(group_name, session) group_members = get_group_members(group_name, session) @@ -219,11 +238,10 @@ def view_group_members_requests(group_name): multiplexJson = {} users_statuses = {} for user in group_members: - unix_name = user['user_name'] - if user['state'] == 'pending': - user_state = user['state'] - user_query = "/v1alpha1/users/" + \ - unix_name + "?token=" + query['token'] + unix_name = user["user_name"] + if user["state"] == "pending": + user_state = user["state"] + user_query = "/v1alpha1/users/" + unix_name + "?token=" + query["token"] multiplexJson[user_query] = {"method": "GET"} users_statuses[unix_name] = user_state @@ -233,65 +251,73 @@ def view_group_members_requests(group_name): # Clean up multiplex return queries in user_dict user_dict = {} for user in multiplex: - user_name = user.split('/')[3].split('?')[0] - user_dict[user_name] = json.loads(multiplex[user]['body']) + user_name = user.split("/")[3].split("?")[0] + user_dict[user_name] = json.loads(multiplex[user]["body"]) # Get User's Group Status - unix_name = session['unix_name'] + unix_name = session["unix_name"] user_status = get_user_group_status(unix_name, group_name, session) # Query user's enclosing group status enclosing_status = get_enclosing_group_status(group_name, unix_name) # Query user's status in root connect group - connect_group = session['url_host']['unix_name'] + connect_group = session["url_host"]["unix_name"] connect_status = get_user_connect_status(unix_name, connect_group) - return render_template('group_profile_members_requests.html', - group_members=user_dict, group_name=group_name, - user_status=user_status, - users_statuses=users_statuses, - connect_status=connect_status, - enclosing_status=enclosing_status, - group=group) + return render_template( + "group_profile_members_requests.html", + group_members=user_dict, + group_name=group_name, + user_status=user_status, + users_statuses=users_statuses, + connect_status=connect_status, + enclosing_status=enclosing_status, + group=group, + ) -@app.route('/groups//add_members', methods=['GET', 'POST']) +@app.route("/groups//add_members", methods=["GET", "POST"]) @authenticated def view_group_add_members(group_name): """Detailed view of group's non-members""" - query = {'token': ciconnect_api_token} - if request.method == 'GET': + query = {"token": ciconnect_api_token} + if request.method == "GET": # Get group information group = get_group_info(group_name, session) # Get User's Group Status - unix_name = session['unix_name'] + unix_name = session["unix_name"] user_status = get_user_group_status(unix_name, group_name, session) # Query user's enclosing group status enclosing_status = get_enclosing_group_status(group_name, unix_name) # Query user's status in root connect group - connect_group = session['url_host']['unix_name'] + connect_group = session["url_host"]["unix_name"] connect_status = get_user_connect_status(unix_name, connect_group) user_super = requests.get( - ciconnect_api_endpoint + '/v1alpha1/users/' + session['unix_name'], params=query) + ciconnect_api_endpoint + "/v1alpha1/users/" + session["unix_name"], + params=query, + ) try: - user_super = user_super.json()['metadata']['superuser'] + user_super = user_super.json()["metadata"]["superuser"] except: user_super = False - return render_template('group_profile_add_members.html', - group_name=group_name, - user_status=user_status, - enclosing_status=enclosing_status, - user_super=user_super, group=group, - connect_status=connect_status) + return render_template( + "group_profile_add_members.html", + group_name=group_name, + user_status=user_status, + enclosing_status=enclosing_status, + user_super=user_super, + group=group, + connect_status=connect_status, + ) -@app.route('/groups-xhr//add_members', methods=['GET', 'POST']) +@app.route("/groups-xhr//add_members", methods=["GET", "POST"]) @authenticated def view_group_add_members_xhr(group_name): """Detailed view of group's 'add members' page""" @@ -301,89 +327,100 @@ def view_group_add_members_xhr(group_name): def view_group_add_members_request(group_name): """Detailed view of group's non-members""" - query = {'token': ciconnect_api_token} - if request.method == 'GET': + query = {"token": ciconnect_api_token} + if request.method == "GET": # Get root base group users # If enclosing group is root # just display group_name connect group users # rather than all users in root i.e. from other connects - group_name_list = group_name.split('.') + group_name_list = group_name.split(".") if len(group_name_list) > 1: - enclosing_group_name = '.'.join(group_name_list[:-1]) + enclosing_group_name = ".".join(group_name_list[:-1]) else: enclosing_group_name = group_name # Get all active members of enclosing group if enclosing_group_name: enclosing_group = get_group_members(enclosing_group_name, session) enclosing_group_members_names = [ - member['user_name'] for member in enclosing_group if member['state'] != 'pending'] + member["user_name"] + for member in enclosing_group + if member["state"] != "pending" + ] else: enclosing_group_members_names = [] # Get all members of current group group_members = get_group_members(group_name, session) - memberships_names = [member['user_name'] for member in group_members] + memberships_names = [member["user_name"] for member in group_members] # Set the difference to filter all non-members of current group - non_members = list( - set(enclosing_group_members_names) - set(memberships_names)) + non_members = list(set(enclosing_group_members_names) - set(memberships_names)) # Set up multiplex to query detailed info about all non-members multiplexJson = {} for user in non_members: unix_name = user - user_query = "/v1alpha1/users/" + \ - unix_name + "?token=" + query['token'] + user_query = "/v1alpha1/users/" + unix_name + "?token=" + query["token"] multiplexJson[user_query] = {"method": "GET"} # POST request for multiplex return and set up user_dict with user info multiplex = get_multiplex(multiplexJson) user_dict = {} for user in multiplex: - user_name = user.split('/')[3].split('?')[0] - user_dict[user_name] = json.loads(multiplex[user]['body']) + user_name = user.split("/")[3].split("?")[0] + user_dict[user_name] = json.loads(multiplex[user]["body"]) return user_dict -@app.route('/groups//subgroups', methods=['GET', 'POST']) +@app.route("/groups//subgroups", methods=["GET", "POST"]) @authenticated def view_group_subgroups(group_name): """Detailed view of group's subgroups""" - if request.method == 'GET': + if request.method == "GET": # Get group information group = get_group_info(group_name, session) # Get User's Group Status - unix_name = session['unix_name'] + unix_name = session["unix_name"] user_status = get_user_group_status(unix_name, group_name, session) # Query to return user's enclosing group membership status enclosing_status = get_enclosing_group_status(group_name, unix_name) # Query to check if user's status in root brand group, i.e. CMS, SPT, OSG - connect_group = session['url_host']['unix_name'] + connect_group = session["url_host"]["unix_name"] connect_status = get_user_connect_status(unix_name, connect_group) - domain_name = request.headers['Host'] - - if 'usatlas' in domain_name: - domain_name = 'atlas.ci-connect.net' - elif 'uscms' in domain_name: - domain_name = 'cms.ci-connect.net' - elif 'uchicago' in domain_name: - domain_name = 'psdconnect.uchicago.edu' - elif 'snowmass21' in domain_name: - domain_name = 'snowmass21.ci-connect.net' - - with open(brand_dir + '/' + domain_name + "/form_descriptions/group_unix_name_description.md", "r") as file: + domain_name = request.headers["Host"] + + if "usatlas" in domain_name: + domain_name = "atlas.ci-connect.net" + elif "uscms" in domain_name: + domain_name = "cms.ci-connect.net" + elif "uchicago" in domain_name: + domain_name = "psdconnect.uchicago.edu" + elif "snowmass21" in domain_name: + domain_name = "snowmass21.ci-connect.net" + + with open( + brand_dir + + "/" + + domain_name + + "/form_descriptions/group_unix_name_description.md", + "r", + ) as file: group_unix_name_description = file.read() - return render_template('group_profile_subgroups.html', group_name=group_name, - user_status=user_status, group=group, - connect_status=connect_status, - enclosing_status=enclosing_status, - group_unix_name_description=group_unix_name_description) + return render_template( + "group_profile_subgroups.html", + group_name=group_name, + user_status=user_status, + group=group, + connect_status=connect_status, + enclosing_status=enclosing_status, + group_unix_name_description=group_unix_name_description, + ) -@app.route('/groups-xhr//subgroups', methods=['GET', 'POST']) +@app.route("/groups-xhr//subgroups", methods=["GET", "POST"]) @authenticated def view_group_subgroups_xhr(group_name): """Detailed view of group's subgroups""" @@ -392,57 +429,70 @@ def view_group_subgroups_xhr(group_name): def view_group_subgroups_request(group_name): - if request.method == 'GET': + if request.method == "GET": # Get group's subgroups information - group_index = len(group_name.split('.')) + group_index = len(group_name.split(".")) subgroups = get_subgroups(group_name, session) # Split subgroup name by . to see how nested the group is # return subgroups that are group_index + 1 to ensure direct subgroup - subgroups = [subgroup for subgroup in subgroups if (len( - subgroup['name'].split('.')) == (group_index + 1) and not subgroup['pending'])] + subgroups = [ + subgroup + for subgroup in subgroups + if ( + len(subgroup["name"].split(".")) == (group_index + 1) + and not subgroup["pending"] + ) + ] # Strip the root from display for subgroup in subgroups: - clean_unix_name = '.'.join(subgroup['name'].split('.')[1:]) - subgroup['clean_unix_name'] = clean_unix_name + clean_unix_name = ".".join(subgroup["name"].split(".")[1:]) + subgroup["clean_unix_name"] = clean_unix_name return subgroups -@app.route('/groups//subgroups-requests', methods=['GET', 'POST']) +@app.route("/groups//subgroups-requests", methods=["GET", "POST"]) @authenticated def view_group_subgroups_requests(group_name): """List view of group's subgroups requests""" - query = {'token': ciconnect_api_token} - if request.method == 'GET': + query = {"token": ciconnect_api_token} + if request.method == "GET": # Get group information group = get_group_info(group_name, session) # Get User's Group Status - unix_name = session['unix_name'] + unix_name = session["unix_name"] user_status = get_user_group_status(unix_name, group_name, session) subgroup_requests = requests.get( - ciconnect_api_endpoint + '/v1alpha1/groups/' + group_name + '/subgroup_requests', params=query) - subgroup_requests = subgroup_requests.json()['groups'] + ciconnect_api_endpoint + + "/v1alpha1/groups/" + + group_name + + "/subgroup_requests", + params=query, + ) + subgroup_requests = subgroup_requests.json()["groups"] # Query to return user's enclosing membership status enclosing_status = get_enclosing_group_status(group_name, unix_name) # Query to check if user's status in root connect group - connect_group = session['url_host']['unix_name'] + connect_group = session["url_host"]["unix_name"] connect_status = get_user_connect_status(unix_name, connect_group) - return render_template('group_profile_subgroups_requests.html', - subgroup_requests=subgroup_requests, - group_name=group_name, - user_status=user_status, - group=group, - connect_status=connect_status, - enclosing_status=enclosing_status) + return render_template( + "group_profile_subgroups_requests.html", + subgroup_requests=subgroup_requests, + group_name=group_name, + user_status=user_status, + group=group, + connect_status=connect_status, + enclosing_status=enclosing_status, + ) -@app.route('/groups-xhr//subgroups-requests', methods=['GET', 'POST']) +@app.route("/groups-xhr//subgroups-requests", methods=["GET", "POST"]) @authenticated def view_group_subgroups_ajax(group_name): subgroup_requests = view_group_subgroups_ajax_requests(group_name) @@ -452,41 +502,50 @@ def view_group_subgroups_ajax(group_name): def view_group_subgroups_ajax_requests(group_name): """List view of group's subgroups requests""" - query = {'token': ciconnect_api_token} - if request.method == 'GET': + query = {"token": ciconnect_api_token} + if request.method == "GET": subgroup_requests = requests.get( - ciconnect_api_endpoint + '/v1alpha1/groups/' + group_name + '/subgroup_requests', params=query) - subgroup_requests = subgroup_requests.json()['groups'] + ciconnect_api_endpoint + + "/v1alpha1/groups/" + + group_name + + "/subgroup_requests", + params=query, + ) + subgroup_requests = subgroup_requests.json()["groups"] return subgroup_requests -@app.route('/groups//email', methods=['GET', 'POST']) +@app.route("/groups//email", methods=["GET", "POST"]) @authenticated def view_group_email(group_name): """View for email form to members""" - if request.method == 'GET': + if request.method == "GET": # Get group information group = get_group_info(group_name, session) # Get User's Group Status - unix_name = session['unix_name'] + unix_name = session["unix_name"] user_status = get_user_group_status(unix_name, group_name, session) # Query to return user's enclosing group's membership status enclosing_status = get_enclosing_group_status(group_name, unix_name) # Query to check user's connect status - connect_group = session['url_host']['unix_name'] + connect_group = session["url_host"]["unix_name"] connect_status = get_user_connect_status(unix_name, connect_group) - return render_template('group_profile_email.html', group_name=group_name, - user_status=user_status, group=group, - connect_status=connect_status, - enclosing_status=enclosing_status) - elif request.method == 'POST': - subject = request.form['subject'] - body = request.form['description'] + return render_template( + "group_profile_email.html", + group_name=group_name, + user_status=user_status, + group=group, + connect_status=connect_status, + enclosing_status=enclosing_status, + ) + elif request.method == "POST": + subject = request.form["subject"] + body = request.form["description"] try: - html = request.form['html-enabled'] + request.form["html-enabled"] body_or_html = "html" except: body_or_html = "text" @@ -494,35 +553,36 @@ def view_group_email(group_name): # mailgun setup here domain_name = domain_name_edgecase() support_emails = { - "cms.ci-connect.net": "cms-connect-support@cern.ch", - "duke.ci-connect.net": "scsc@duke.edu", - "spt.ci-connect.net": "jlstephen@uchicago.edu", - "atlas.ci-connect.net": "atlas-connect-l@lists.bnl.gov", - "psdconnect.uchicago.edu": "support@ci-connect.uchicago.edu", - "www.ci-connect.net": "support@ci-connect.net", - "localhost:5000": "jeremyvan614@gmail.com" - } - + "cms.ci-connect.net": "cms-connect-support@cern.ch", + "duke.ci-connect.net": "scsc@duke.edu", + "spt.ci-connect.net": "spt-connect-approvers@api.ci-connect.net", + "atlas.ci-connect.net": "atlas-connect-l@lists.bnl.gov", + "psdconnect.uchicago.edu": "support@ci-connect.uchicago.edu", + "www.ci-connect.net": "support@ci-connect.net", + "localhost:5000": "localhost@localdomain", + } try: support_email = support_emails[domain_name] except: support_email = "support@ci-connect.net" - + user_dict, users_statuses = get_group_members_emails(group_name) - user_emails = [user_dict[user]['metadata']['email'] for user in user_dict] + user_emails = [user_dict[user]["metadata"]["email"] for user in user_dict] # print(user_emails) - r = requests.post("https://api.mailgun.net/v3/api.ci-connect.net/messages", - auth=('api', mailgun_api_token), - data={ - "from": "<" + support_email + ">", - "to": [support_email], - "bcc": user_emails, - "subject": subject, - body_or_html: body, - }) + r = requests.post( + "https://api.mailgun.net/v3/api.ci-connect.net/messages", + auth=("api", mailgun_api_token), + data={ + "from": "<" + support_email + ">", + "to": [support_email], + "bcc": user_emails, + "subject": subject, + body_or_html: body, + }, + ) if r.status_code == requests.codes.ok: - flash("Your message has been sent to the members of this group", 'success') - return redirect(url_for('view_group_email', group_name=group_name)) + flash("Your message has been sent to the members of this group", "success") + return redirect(url_for("view_group_email", group_name=group_name)) else: - flash("Unable to send message: {}".format(r.json()), 'warning') - return redirect(url_for('view_group_email', group_name=group_name)) \ No newline at end of file + flash("Unable to send message: {}".format(r.json()), "warning") + return redirect(url_for("view_group_email", group_name=group_name)) diff --git a/portal/views/slate_views.py b/portal/views/slate_views.py index 0d39f92..b9d7ce2 100644 --- a/portal/views/slate_views.py +++ b/portal/views/slate_views.py @@ -2,17 +2,24 @@ import requests from portal import app from portal.decorators import authenticated -from portal.slate_api import get_app_config, get_app_readme, list_users_instances_request, get_instance_details, get_instance_logs, delete_instance +from portal.slate_api import ( + get_app_config, + get_app_readme, + list_users_instances_request, + get_instance_details, + get_instance_logs, + delete_instance, +) from portal.connect_api import get_user_profile, get_user_connect_status import os -import json import yaml from base64 import b64encode import random -slate_api_token = app.config['SLATE_API_TOKEN'] -slate_api_endpoint = app.config['SLATE_API_ENDPOINT'] -query = {'token': slate_api_token} +slate_api_token = app.config["SLATE_API_TOKEN"] +slate_api_endpoint = app.config["SLATE_API_ENDPOINT"] +query = {"token": slate_api_token} + def generateToken(): token_bytes = os.urandom(32) @@ -23,7 +30,7 @@ def generateToken(): def generateRandomPort(): """Generate random number between 30000 and 32767 for External Condor Port""" random.seed() - port = random.randrange(30000,32767) + port = random.randrange(30000, 32767) print("Now using port: {}".format(port)) return port @@ -32,200 +39,226 @@ def createTokenSecret(generated_token, user_unix_name): # Initialize empty contents dict contents = {} # Hardcode values while Jupyter-Notebook is the only app being launched - group = 'group_2Q9yPCOLxMg' - cluster = 'uchicago-river-v2' - secret_name = '{}-jupyter-token'.format(user_unix_name) - key_name = 'token' + group = "group_2Q9yPCOLxMg" + cluster = "uchicago-river-v2" + secret_name = "{}-jupyter-token".format(user_unix_name) + key_name = "token" key_contents = generated_token # Add secret contents key-value to dict # for key_name, key_contents in zip (request.form.getlist('key_name'), request.form.getlist('key_contents')): # contents[key_name] = base64.b64encode(key_contents) contents[key_name] = key_contents - add_secret = {"apiVersion": 'v1alpha3', - 'metadata': {'name': secret_name, 'group': group, 'cluster': cluster}, - 'contents': contents} + add_secret = { + "apiVersion": "v1alpha3", + "metadata": {"name": secret_name, "group": group, "cluster": cluster}, + "contents": contents, + } # Add secret to Group print("Adding Secret to Group") response = requests.post( - slate_api_endpoint + '/v1alpha3/secrets', params=query, json=add_secret) + slate_api_endpoint + "/v1alpha3/secrets", params=query, json=add_secret + ) print("Response: {}, {}".format(response, response.json())) return response -@app.route('/instances', methods=['GET', 'POST']) +@app.route("/instances", methods=["GET", "POST"]) @authenticated def view_instances(): """Connect groups""" - query = {'token': slate_api_token, 'dev': 'true'} - if request.method == 'GET': - app_name = 'jupyter-notebook' - profile = get_user_profile(session['unix_name']) + # query = {"token": slate_api_token, "dev": "true"} + if request.method == "GET": + app_name = "jupyter-notebook" + profile = get_user_profile(session["unix_name"]) try: - public_key = profile['metadata']['public_key'] + public_key = profile["metadata"]["public_key"] except: public_key = None instances = list_users_instances_request(session) # Check user's member status of connect group specifically - connect_group = session['url_host']['unix_name'] - user_status = get_user_connect_status( - session['unix_name'], connect_group) + connect_group = session["url_host"]["unix_name"] + user_status = get_user_connect_status(session["unix_name"], connect_group) - return render_template('instances.html', name=app_name, - public_key=public_key, - instances=instances, - user_status=user_status) + return render_template( + "instances.html", + name=app_name, + public_key=public_key, + instances=instances, + user_status=user_status, + ) -@app.route('/instances/', methods=['GET']) +@app.route("/instances/", methods=["GET"]) @authenticated def view_instance(instance_id): """View instance details""" - if request.method == 'GET': + if request.method == "GET": instance_details = get_instance_details(instance_id) instance_logs = get_instance_logs(instance_id) instance_status = True - if instance_details['kind'] == 'Error': + if instance_details["kind"] == "Error": instance_status = False - return render_template('404.html') + return render_template("404.html") try: - config = instance_details['metadata']['configuration'] - print('Trying to load yaml') + config = instance_details["metadata"]["configuration"] + print("Trying to load yaml") yaml_config = yaml.load(config, Loader=yaml.FullLoader) - print('Successfully loaded yaml config') - token = yaml_config['Jupyter']['Token'] + print("Successfully loaded yaml config") + token = yaml_config["Jupyter"]["Token"] except: token = None - - return render_template('instance_profile.html', - instance_details=instance_details, - instance_status=instance_status, - instance_logs=instance_logs, token=token) + + return render_template( + "instance_profile.html", + instance_details=instance_details, + instance_status=instance_status, + instance_logs=instance_logs, + token=token, + ) -@app.route('/instances/delete/', methods=['GET']) +@app.route("/instances/delete/", methods=["GET"]) @authenticated def view_delete_instance(instance_id): """View instance details""" - if request.method == 'GET': + if request.method == "GET": deleted_instance_response = delete_instance(instance_id) print(deleted_instance_response) - return redirect(url_for('view_instances')) + return redirect(url_for("view_instances")) -@app.route('/instances/deploy', methods=['GET', 'POST']) +@app.route("/instances/deploy", methods=["GET", "POST"]) @authenticated def create_application(): """Connect groups""" - query = {'token': slate_api_token, 'dev': 'true'} - if request.method == 'GET': - app_name = 'jupyter-notebook' - profile = get_user_profile(session['unix_name']) + query = {"token": slate_api_token, "dev": "true"} + if request.method == "GET": + app_name = "jupyter-notebook" + profile = get_user_profile(session["unix_name"]) try: - public_key = profile['metadata']['public_key'] + public_key = profile["metadata"]["public_key"] except: public_key = None - return render_template('instance_create.html', name=app_name, public_key=public_key) - elif request.method == 'POST': - app_name = 'jupyter-notebook' + return render_template( + "instance_create.html", name=app_name, public_key=public_key + ) + elif request.method == "POST": + app_name = "jupyter-notebook" app_config = get_app_config(app_name) - app_config = app_config.json()['spec']['body'] + app_config = app_config.json()["spec"]["body"] # The FullLoader parameter handles the conversion from YAML # scalar values to Python the dictionary format app_config_yaml = yaml.load(app_config, Loader=yaml.FullLoader) # Extract connect group name and replace dot notation with dash for app name format compatibility - connect_group_name = session['url_host']['unix_name'].replace('.','-') - app_config_yaml['Instance'] = '{}-{}'.format(session['unix_name'], connect_group_name) + connect_group_name = session["url_host"]["unix_name"].replace(".", "-") + app_config_yaml["Instance"] = "{}-{}".format( + session["unix_name"], connect_group_name + ) - app_config_yaml['Ingress']['Subdomain'] = '{}-jupyter'.format(session['unix_name']) - app_config_yaml['Jupyter']['NB_USER'] = session['unix_name'] + app_config_yaml["Ingress"]["Subdomain"] = "{}-jupyter".format( + session["unix_name"] + ) + app_config_yaml["Jupyter"]["NB_USER"] = session["unix_name"] # Get user unix ID - user_profile = get_user_profile(session['unix_name']) - user_unix_id = user_profile['metadata']['unix_id'] - app_config_yaml['Jupyter']['NB_UID'] = user_unix_id + user_profile = get_user_profile(session["unix_name"]) + user_unix_id = user_profile["metadata"]["unix_id"] + app_config_yaml["Jupyter"]["NB_UID"] = user_unix_id # Generate base64 encoded random 32-bytes token base64_encoded_token = generateToken() - app_config_yaml['Jupyter']['Token'] = base64_encoded_token + app_config_yaml["Jupyter"]["Token"] = base64_encoded_token # Set default resource values - app_config_yaml['Resources']['Memory'] = 16000 - app_config_yaml['Resources']['CPU'] = 4000 + app_config_yaml["Resources"]["Memory"] = 16000 + app_config_yaml["Resources"]["CPU"] = 4000 - app_config_yaml['CondorConfig']['Enabled'] = True - app_config_yaml['CondorConfig']['CollectorHost'] = 'flock.opensciencegrid.org' - app_config_yaml['CondorConfig']['CollectorPort'] = 9618 - app_config_yaml['CondorConfig']['IsExternalPool'] = True - app_config_yaml['CondorConfig']['ExternalCondorPort'] = generateRandomPort() - app_config_yaml['CondorConfig']['AuthTokenSecret'] = 'submit-auth-token' - app_config_yaml['SSH']['Enabled'] = True + app_config_yaml["CondorConfig"]["Enabled"] = True + app_config_yaml["CondorConfig"]["CollectorHost"] = "flock.opensciencegrid.org" + app_config_yaml["CondorConfig"]["CollectorPort"] = 9618 + app_config_yaml["CondorConfig"]["IsExternalPool"] = True + app_config_yaml["CondorConfig"]["ExternalCondorPort"] = generateRandomPort() + app_config_yaml["CondorConfig"]["AuthTokenSecret"] = "submit-auth-token" + app_config_yaml["SSH"]["Enabled"] = True try: - extra_ports_enabled = request.form['extra-ports'] - low_port = request.form['low-port'] - high_port = request.form['high-port'] - - app_config_yaml['ExtraPort']['Enabled'] = True - app_config_yaml['ExtraPort']['HighPort'] = low_port - app_config_yaml['ExtraPort']['LowPort'] = high_port - print("Using App Config with Extra Ports: {} - {}".format(low_port, high_port)) + # extra_ports_enabled = request.form["extra-ports"] + low_port = request.form["low-port"] + high_port = request.form["high-port"] + + app_config_yaml["ExtraPort"]["Enabled"] = True + app_config_yaml["ExtraPort"]["HighPort"] = low_port + app_config_yaml["ExtraPort"]["LowPort"] = high_port + print( + "Using App Config with Extra Ports: {} - {}".format(low_port, high_port) + ) except: - extra_ports_enabled = False + # extra_ports_enabled = False print("Using App Config without Extra Ports") - try: - app_config_yaml['SSH']['SSH_Public_Key'] = request.form['sshpubstring'] + app_config_yaml["SSH"]["SSH_Public_Key"] = request.form["sshpubstring"] except: - profile = get_user_profile(session['unix_name']) - public_key = profile['metadata']['public_key'] - app_config_yaml['SSH']['SSH_Public_Key'] = public_key + profile = get_user_profile(session["unix_name"]) + public_key = profile["metadata"]["public_key"] + app_config_yaml["SSH"]["SSH_Public_Key"] = public_key # Group name: snowmass21-ciconnect - group = 'group_2Q9yPCOLxMg' - cluster = 'uchicago-river-v2' + group = "group_2Q9yPCOLxMg" + cluster = "uchicago-river-v2" configuration = yaml.dump(app_config_yaml) # SLATE API: slate app install jupyter-notebook --dev --group --cluster --conf jupyter.conf - install_app = {"apiVersion": 'v1alpha3', "group": group, "cluster": cluster, "configuration": configuration} + install_app = { + "apiVersion": "v1alpha3", + "group": group, + "cluster": cluster, + "configuration": configuration, + } # Post query to install application config app_install = requests.post( - slate_api_endpoint + '/v1alpha3/apps/' + app_name, params=query, json=install_app) + slate_api_endpoint + "/v1alpha3/apps/" + app_name, + params=query, + json=install_app, + ) # print(app_install) # print(app_install.json()) if app_install.status_code == requests.codes.ok: - flash("Your application has been deployed.", 'success') - return redirect(url_for('view_instances')) + flash("Your application has been deployed.", "success") + return redirect(url_for("view_instances")) elif app_install.status_code == 400: - err_message = app_install.json()['message'] - flash('Unable to deploy application: You already have a launched instance of this application', 'warning') - return redirect(url_for('create_application')) + err_message = app_install.json()["message"] + flash( + "Unable to deploy application: You already have a launched instance of this application", + "warning", + ) + return redirect(url_for("create_application")) else: - err_message = app_install.json()['message'] - if 'port is not in the valid range' in err_message: + err_message = app_install.json()["message"] + if "port is not in the valid range" in err_message: print("Port was invalid, retrying with new external condor port") # Flask code 307 preserve the POST request to retry method - return redirect(url_for('create_application'), code=307) + return redirect(url_for("create_application"), code=307) - return redirect(url_for('view_instances')) + return redirect(url_for("view_instances")) -@app.route('/apps_readme_xhr/', methods=['GET']) +@app.route("/apps_readme_xhr/", methods=["GET"]) @authenticated def view_apps_readme_xhr(name): app_readme = get_app_readme(name) return jsonify(app_readme) -@app.route('/apps_config_ajax/', methods=['GET']) +@app.route("/apps_config_ajax/", methods=["GET"]) @authenticated def apps_config_ajax(name): app_config = get_app_config(name) diff --git a/portal/views/users_groups.py b/portal/views/users_groups.py index fb045cc..64bc23f 100644 --- a/portal/views/users_groups.py +++ b/portal/views/users_groups.py @@ -1,95 +1,121 @@ -from flask import (render_template, request, session) +from flask import render_template, request, session import json -try: - from urllib.parse import urlencode -except ImportError: - from urllib import urlencode - from portal import app from portal.decorators import authenticated -from portal.connect_api import (get_multiplex, get_user_connect_status, - get_user_info, get_user_group_memberships, - get_user_pending_project_requests, domain_name_edgecase) +from portal.connect_api import ( + get_multiplex, + get_user_connect_status, + get_user_info, + get_user_group_memberships, + get_user_pending_project_requests, + domain_name_edgecase, +) import sys # Read configurable tokens and endpoints from config file, values must be set -ciconnect_api_token = app.config['CONNECT_API_TOKEN'] -ciconnect_api_endpoint = app.config['CONNECT_API_ENDPOINT'] -mailgun_api_token = app.config['MAILGUN_API_TOKEN'] +ciconnect_api_token = app.config["CONNECT_API_TOKEN"] +ciconnect_api_endpoint = app.config["CONNECT_API_ENDPOINT"] +mailgun_api_token = app.config["MAILGUN_API_TOKEN"] # Read Brand Dir from config and insert path to read -brand_dir = app.config['MARKDOWN_DIR'] +brand_dir = app.config["MARKDOWN_DIR"] sys.path.insert(0, brand_dir) -@app.route('/users-groups', methods=['GET']) +@app.route("/users-groups", methods=["GET"]) @authenticated def users_groups(): """Groups that user's are specifically members of""" - if request.method == 'GET': - query = {'token': ciconnect_api_token, - 'globus_id': session['primary_identity']} + if request.method == "GET": + query = {"token": ciconnect_api_token, "globus_id": session["primary_identity"]} # Get user info to derive unix name user = get_user_info(session) - unix_name = user['metadata']['unix_name'] + unix_name = user["metadata"]["unix_name"] # Get user's group membership info based on session unix name - users_group_memberships = get_user_group_memberships( - session, unix_name) + users_group_memberships = get_user_group_memberships(session, unix_name) multiplexJson = {} group_membership_status = {} for group in users_group_memberships: - if group['state'] not in ['nonmember']: - group_name = group['name'] - group_query = "/v1alpha1/groups/" + \ - group_name + "?token=" + query['token'] + if group["state"] not in ["nonmember"]: + group_name = group["name"] + group_query = ( + "/v1alpha1/groups/" + group_name + "?token=" + query["token"] + ) multiplexJson[group_query] = {"method": "GET"} - group_membership_status[group_query] = group['state'] + group_membership_status[group_query] = group["state"] # POST request for multiplex return multiplex = get_multiplex(multiplexJson) users_groups = [] for group in multiplex: - if ((session['url_host']['unix_name'] in (json.loads(multiplex[group]['body'])['metadata']['name'])) and (len((json.loads(multiplex[group]['body'])['metadata']['name']).split('.')) > 1)): + if ( + session["url_host"]["unix_name"] + in (json.loads(multiplex[group]["body"])["metadata"]["name"]) + ) and ( + len( + (json.loads(multiplex[group]["body"])["metadata"]["name"]).split( + "." + ) + ) + > 1 + ): users_groups.append( - (json.loads(multiplex[group]['body']), group_membership_status[group])) + ( + json.loads(multiplex[group]["body"]), + group_membership_status[group], + ) + ) # users_groups = [group for group in users_groups if len(group['name'].split('.')) == 3] # Query user's pending project requests pending_project_requests = get_user_pending_project_requests(unix_name) # Check user's member status of root connect group - connect_group = session['url_host']['unix_name'] + connect_group = session["url_host"]["unix_name"] user_status = get_user_connect_status(unix_name, connect_group) domain_name = domain_name_edgecase() - with open(brand_dir + '/' + domain_name + "/form_descriptions/group_unix_name_description.md", "r") as file: + with open( + brand_dir + + "/" + + domain_name + + "/form_descriptions/group_unix_name_description.md", + "r", + ) as file: group_unix_name_description = file.read() - return render_template('users_groups.html', groups=users_groups, - project_requests=pending_project_requests, - user_status=user_status, - group_unix_name_description=group_unix_name_description) + return render_template( + "users_groups.html", + groups=users_groups, + project_requests=pending_project_requests, + user_status=user_status, + group_unix_name_description=group_unix_name_description, + ) -@app.route('/users-groups/pending', methods=['GET']) +@app.route("/users-groups/pending", methods=["GET"]) @authenticated def users_groups_pending(): """Groups that user's are specifically members of""" - if request.method == 'GET': - query = {'token': ciconnect_api_token, - 'globus_id': session['primary_identity']} + if request.method == "GET": + # query = {"token": ciconnect_api_token, "globus_id": session["primary_identity"]} # Get user info user = get_user_info(session) - unix_name = user['metadata']['unix_name'] + unix_name = user["metadata"]["unix_name"] # Query user's pending project requests project_requests = get_user_pending_project_requests(unix_name) - project_requests = [project_request for project_request in project_requests if session['url_host'] - ['unix_name'] in project_request['name']] + project_requests = [ + project_request + for project_request in project_requests + if session["url_host"]["unix_name"] in project_request["name"] + ] # Check user status of root connect group - connect_group = session['url_host']['unix_name'] + connect_group = session["url_host"]["unix_name"] user_status = get_user_connect_status(unix_name, connect_group) - return render_template('users_groups_pending.html', - project_requests=project_requests, - user_status=user_status) + return render_template( + "users_groups_pending.html", + project_requests=project_requests, + user_status=user_status, + ) diff --git a/setup.cfg b/setup.cfg index f49adb3..3db05fa 100644 --- a/setup.cfg +++ b/setup.cfg @@ -1,3 +1,4 @@ [flake8] +ignore = E501 exclude = venv/,venv27/,.venv/,portal/__init__.py,service/__init__.py