Skip to content

Commit 299f26b

Browse files
Merge pull request #641 from oliver-sanders/list-jupyter-server-extensions
add jupyter extensions to userprofile handler
2 parents 8461385 + 77dec99 commit 299f26b

File tree

2 files changed

+32
-1
lines changed

2 files changed

+32
-1
lines changed

cylc/uiserver/handlers.py

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
import json
1919
import getpass
2020
import os
21+
import re
2122
from typing import TYPE_CHECKING, Callable, Dict
2223

2324
from graphene_tornado.tornado_graphql_handler import TornadoGraphQLHandler
@@ -44,6 +45,7 @@
4445

4546

4647
ME = getpass.getuser()
48+
RE_SLASH = re.compile(r'\/+')
4749

4850

4951
def authorised(fun: Callable) -> Callable:
@@ -258,7 +260,6 @@ def set_default_headers(self) -> None:
258260
self.set_header("Content-Type", 'application/json')
259261

260262
@web.authenticated
261-
# @authorised TODO: I can't think why we would want to authorise this
262263
def get(self):
263264
user_info = {
264265
**self.current_user.__dict__,
@@ -281,6 +282,19 @@ def get(self):
281282
user_info['mode'] = 'single user'
282283
else:
283284
user_info['mode'] = 'multi user'
285+
286+
user_info['extensions'] = {
287+
app.name: RE_SLASH.sub(
288+
'/', f'{self.serverapp.base_url}/{app.default_url}'
289+
)
290+
for extension_apps
291+
in self.serverapp.extension_manager.extension_apps.values()
292+
# filter out extensions that do not provide a default_url OR
293+
# set it to the root endpoint.
294+
for app in extension_apps
295+
if getattr(app, 'default_url', '/') != '/'
296+
}
297+
284298
self.write(json.dumps(user_info))
285299

286300

cylc/uiserver/tests/test_handlers.py

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515

1616
from functools import partial
1717
from getpass import getuser
18+
import json
1819
from unittest import mock
1920
from unittest.mock import MagicMock
2021
import pytest
@@ -120,3 +121,19 @@ def test_assert_callback_handler_gets_called(self):
120121
self.io_loop.run_sync(handler.open,
121122
get_async_test_timeout())
122123
handler.subscription_server.handle.assert_called_once()
124+
125+
126+
@pytest.mark.integration
127+
async def test_userprofile(
128+
jp_fetch, cylc_uis, jp_serverapp,
129+
):
130+
"""Test the userprofile endpoint."""
131+
# patch the default_url back to how it is set in cylc.uiserver.app
132+
cylc_uis.default_url = '/cylc'
133+
134+
response = await jp_fetch('cylc', 'userprofile')
135+
user_profile = json.loads(response.body.decode())
136+
assert user_profile['username'] == getuser()
137+
assert user_profile['owner'] == getuser()
138+
assert 'read' in user_profile['permissions']
139+
assert 'cylc' in user_profile['extensions']

0 commit comments

Comments
 (0)