Skip to content

Commit

Permalink
Merge pull request #56 from citysciencelab/sharing-users-interface
Browse files Browse the repository at this point in the history
Introduce more interfaces for sharing functionality
  • Loading branch information
KaiVolland authored Oct 11, 2024
2 parents cc0a3be + bfb1f4f commit 6ac90b4
Show file tree
Hide file tree
Showing 4 changed files with 60 additions and 13 deletions.
9 changes: 9 additions & 0 deletions src/ump/api/keycloak_utils.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
"""Keycloak helper functions"""

import hashlib
from os import environ as env

from keycloak import KeycloakAdmin, KeycloakOpenIDConnection
Expand Down Expand Up @@ -30,3 +32,10 @@ def get_user_name(user_id):
"""Retrieve the username by user id"""
user = keycloak_admin.get_user(user_id)
return user["username"] if user else None


def get_gravatar_url(user_id):
"""Retrieve the gravatar url by user id"""
email = keycloak_admin.get_user(user_id)["email"].strip().lower()
hash_email = hashlib.md5(email.encode("utf-8")).hexdigest()
return f"https://www.gravatar.com/avatar/{hash_email}"
21 changes: 18 additions & 3 deletions src/ump/api/routes/ensembles.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
"""The ensemble related routes"""

import builtins
import copy
import json
Expand Down Expand Up @@ -136,14 +137,28 @@ def get_comments(ensemble_id):
return results


@ensembles.route("/<path:ensemble_id>/users", methods=["GET"])
def get_users(ensemble_id=None):
"""Get all users that have access to an ensemble"""
auth = g.get("auth_token")
if auth is None:
return Response("[]", mimetype="application/json")
with Session(engine) as session:
stmt = select(EnsemblesUsers).where(EnsemblesUsers.ensemble_id == ensemble_id)
list = []
for user in session.scalars(stmt).fetchall():
list.append(user.to_dict())
return list


@ensembles.route("/<path:ensemble_id>/share/<path:email>", methods=["GET"])
def share(ensemble_id=None, email=None):
"""Share an ensemble with another user"""
auth = g.get('auth_token')
auth = g.get("auth_token")
user_id = find_user_id_by_email(email)
if user_id is None:
logging.error("Unable to find user by email %s.", email)
return Response(status = 404)
return Response(status=404)
with Session(engine) as session:
stmt = (
select(Ensemble)
Expand All @@ -162,7 +177,7 @@ def share(ensemble_id=None, email=None):
if ensemble is None:
return Response(status=404)

row = EnsemblesUsers(ensemble_id = ensemble_id, user_id = user_id)
row = EnsemblesUsers(ensemble_id=ensemble_id, user_id=user_id)
session.add(row)
session.commit()
return Response(status=201)
Expand Down
34 changes: 26 additions & 8 deletions src/ump/api/routes/jobs.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,24 +35,40 @@ def get_results(job_id=None):
job = Job(job_id, None if auth is None else auth["sub"])
return Response(json.dumps(asyncio.run(job.results())), mimetype="application/json")


@jobs.route("/<path:job_id>/users", methods=["GET"])
def get_users(job_id=None):
"""Get all users that have access to a job"""
auth = g.get("auth_token")
if auth is None:
return Response("[]", mimetype="application/json")
with Session(engine) as session:
stmt = select(JobsUsers).where(JobsUsers.job_id == job_id)
list = []
for user in session.scalars(stmt).fetchall():
list.append(user.to_dict())
return list


@jobs.route("/<path:job_id>/share/<path:email>", methods=["GET"])
def share(job_id=None, email=None):
"""Share a job with another user"""
auth = g.get('auth_token')
auth = g.get("auth_token")
user_id = find_user_id_by_email(email)
if user_id is None:
logging.error("Unable to find user by email %s.", email)
return Response(status = 404)
job = Job(job_id, None if auth is None else auth['sub'])
return Response(status=404)
job = Job(job_id, None if auth is None else auth["sub"])
if job is None:
logging.error("Unable to find job with id %s.", job_id)
return Response(status = 404)
return Response(status=404)

with Session(engine) as session:
row = JobsUsers(job_id = job_id, user_id = user_id)
row = JobsUsers(job_id=job_id, user_id=user_id)
session.add(row)
session.commit()
return Response(status = 201)
return Response(status=201)


@jobs.route("/<path:job_id>/comments", methods=["GET"])
def get_comments(job_id):
Expand All @@ -63,8 +79,10 @@ def get_comments(job_id):
with Session(engine) as session:
stmt = (
select(JobComment)
.join(JobsUsers, JobsUsers.job_id == JobComment.job_id, isouter = True)
.where(or_(JobComment.user_id == auth["sub"], JobsUsers.user_id == auth['sub']))
.join(JobsUsers, JobsUsers.job_id == JobComment.job_id, isouter=True)
.where(
or_(JobComment.user_id == auth["sub"], JobsUsers.user_id == auth["sub"])
)
.where(JobComment.job_id == job_id)
)
results = []
Expand Down
9 changes: 7 additions & 2 deletions src/ump/api/routes/users.py
Original file line number Diff line number Diff line change
@@ -1,24 +1,29 @@
"""Endpoints to access user information via keycloak"""

import json

from apiflask import APIBlueprint
from flask import Response, g

from ump.api.keycloak_utils import get_user_name
from ump.api.keycloak_utils import get_gravatar_url, get_user_name

users = APIBlueprint("users", __name__)

@users.route("/<path:user_id>/name")

@users.route("/<path:user_id>/details", methods=["GET"])
def index(user_id=None):
"Retrieve user name by user id"
auth = g.get("auth_token")
if auth is None:
return Response(mimetype="application/json", status=401)

user_name = get_user_name(user_id)
gravatar_url = get_gravatar_url(user_id)

response_data = {
"user_id": user_id,
"username": user_name,
"gravatar_url": gravatar_url,
}

return Response(json.dumps(response_data), mimetype="application/json")

0 comments on commit 6ac90b4

Please sign in to comment.