Skip to content

Commit

Permalink
[core] Add a public API endpoint to retrieve the banners
Browse files Browse the repository at this point in the history
This can be used from both the login page and inside the app to retrieve any system and configured banners
  • Loading branch information
JohanAhlen committed Dec 14, 2022
1 parent 0ceb875 commit f4a36e2
Show file tree
Hide file tree
Showing 5 changed files with 53 additions and 18 deletions.
11 changes: 9 additions & 2 deletions desktop/core/src/desktop/api2.py
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@

from desktop import appmanager
from desktop.auth.backend import is_admin
from desktop.conf import ENABLE_CONNECTORS, ENABLE_GIST_PREVIEW, get_clusters, IS_K8S_ONLY, ENABLE_SHARING
from desktop.conf import ENABLE_CONNECTORS, ENABLE_GIST_PREVIEW, CUSTOM, get_clusters, IS_K8S_ONLY, ENABLE_SHARING
from desktop.lib.conf import BoundContainer, GLOBAL_CONFIG, is_anonymous
from desktop.lib.django_util import JsonResponse, login_notrequired, render
from desktop.lib.exceptions_renderable import PopupException
Expand All @@ -54,7 +54,7 @@
from desktop.lib.paths import get_desktop_root
from desktop.models import Document2, Document, Directory, FilesystemException, uuid_default, \
UserPreferences, get_user_preferences, set_user_preferences, get_cluster_config, __paginate, _get_gist_document
from desktop.views import serve_403_error
from desktop.views import get_banner_message, serve_403_error

from hadoop.cluster import is_yarn

Expand Down Expand Up @@ -84,6 +84,13 @@ def decorator(*args, **kwargs):

return decorator

@api_error_handler
def get_banners(request):
banners = {
'system': get_banner_message(request),
'configured': CUSTOM.BANNER_TOP_HTML.get()
}
return JsonResponse(banners)

@api_error_handler
def get_config(request):
Expand Down
7 changes: 6 additions & 1 deletion desktop/core/src/desktop/api_public.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,8 @@
import json

from django.http import QueryDict, HttpResponse
from rest_framework.decorators import api_view
from rest_framework.permissions import AllowAny
from rest_framework.decorators import api_view, authentication_classes, permission_classes

from filebrowser import views as filebrowser_views, api as filebrowser_api
from indexer import api3 as indexer_api3
Expand Down Expand Up @@ -52,6 +53,10 @@ def get_context_namespaces(request, interface):
django_request = get_django_request(request)
return desktop_api.get_context_namespaces(django_request, interface)

@api_view(["GET"])
@permission_classes([AllowAny])
def get_banners(request):
return desktop_api.get_banners(request)

# Editor

Expand Down
39 changes: 33 additions & 6 deletions desktop/core/src/desktop/api_public_tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,21 +25,48 @@
from nose.tools import assert_true, assert_false, assert_equal, assert_not_equal, assert_raises

from useradmin.models import User

from desktop.conf import CUSTOM
from desktop.api_public import get_django_request
from desktop.lib.django_test_util import make_logged_in_client
from desktop.lib.test_utils import grant_access

from desktop.lib.django_test_util import Client, make_logged_in_client

if sys.version_info[0] > 2:
from unittest.mock import patch, Mock, MagicMock
else:
from mock import patch, Mock, MagicMock


class TestCoreApi():
def setUp(self):
self.unauthorized_client = Client()

def test_banners(self):
with patch('desktop.api2.get_banner_message') as get_banner_message:
try:
configured_banner = '<div>Some config banner</div>'
system_banner = '<div>Some system banner</div>'
done = CUSTOM.BANNER_TOP_HTML.set_for_testing(configured_banner)
get_banner_message.return_value = system_banner

response = self.unauthorized_client.get(reverse('api:core_banners'))

get_banner_message.assert_called()
json_resp = json.loads(response.content)
assert_equal(json_resp['configured'], configured_banner)
assert_equal(json_resp['system'], system_banner)
finally:
done()


class TestEditorApi():
TEST_INTERPRETER = {
'name': 'MySql', 'displayName': 'MySql', 'type': '1', 'interface': 'sqlalchemy', 'options': {'url': 'mysql://hue:hue@localhost:3306/hue', 'has_ssh': False, 'ssh_server_host': '127.0.0.1'}, 'dialect': 'mysql', 'dialect_properties': {'is_sql': True, 'sql_identifier_quote': '`', 'sql_identifier_comment_single': '--', 'has_catalog': True, 'has_database': True, 'has_table': True, 'has_live_queries': False, 'has_optimizer_risks': True, 'has_optimizer_values': True, 'has_auto_limit': False, 'has_reference_language': False, 'has_reference_functions': False, 'has_use_statement': False}, 'category': 'editor', 'is_sql': True, 'is_catalog': False
'name': 'MySql', 'displayName': 'MySql', 'type': '1', 'interface': 'sqlalchemy',
'options': {'url': 'mysql://hue:hue@localhost:3306/hue', 'has_ssh': False, 'ssh_server_host': '127.0.0.1'},
'dialect': 'mysql',
'dialect_properties': {'is_sql': True, 'sql_identifier_quote': '`', 'sql_identifier_comment_single': '--',
'has_catalog': True, 'has_database': True, 'has_table': True, 'has_live_queries': False,
'has_optimizer_risks': True, 'has_optimizer_values': True, 'has_auto_limit': False,
'has_reference_language': False, 'has_reference_functions': False,
'has_use_statement': False}, 'category': 'editor', 'is_sql': True, 'is_catalog': False
}

def setUp(self):
Expand All @@ -58,7 +85,7 @@ def test_editor_execute(self):
execute.return_value = HttpResponse()
_get_interpreter_from_dialect.return_value = TestEditorApi.TEST_INTERPRETER

self.client.post(reverse('api:editor_execute', args=['hive']), {'statement':'SHOW TABLES'})
self.client.post(reverse('api:editor_execute', args=['hive']), {'statement': 'SHOW TABLES'})

execute.assert_called()
if not execute.call_args.args[1]:
Expand Down
1 change: 1 addition & 0 deletions desktop/core/src/desktop/api_public_urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@
# Compatibility with "old" private API.
# e.g. https://demo.gethue.com/notebook/api/execute/hive
urlpatterns += [
re_path(r'^banners/?$', api_public.get_banners, name='core_banners'),
re_path(r'^get_config/?$', api_public.get_config),
re_path(r'^get_namespaces/(?P<interface>[\w\-]+)/?$', api_public.get_context_namespaces), # To remove

Expand Down
13 changes: 4 additions & 9 deletions desktop/core/src/desktop/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -554,24 +554,19 @@ def get_banner_message(request):
forwarded_host = request.get_host()

if hasattr(request, 'environ'):
message = None
path_info = request.environ.get("PATH_INFO")
if path_info.find("/hue") < 0 and path_info.find("accounts/login") < 0 and not request.path.startswith('/api/'):
url = request.build_absolute_uri("/hue")
link = '<a href="%s" style="color: #FFF; font-weight: bold">%s</a>' % (url, url)
message = _('You are accessing an older version of Hue, please switch to the latest version: %s.') % link
link = '<a href="%s">%s</a>' % (url, url)
banner_message = _('You are accessing an older version of Hue, please switch to the latest version: %s.') % link
LOG.warning('User %s is using Hue 3 UI' % request.user.username)

if HUE_LOAD_BALANCER.get() and HUE_LOAD_BALANCER.get() != [''] and \
(not forwarded_host or not any(forwarded_host in lb for lb in HUE_LOAD_BALANCER.get())):
message = _('You are accessing a non-optimized Hue, please switch to one of the available addresses: %s') % \
(", ".join(['<a href="%s" style="color: #FFF; font-weight: bold">%s</a>' % (host, host) for host in HUE_LOAD_BALANCER.get()]))
banner_message = _('You are accessing a non-optimized Hue, please switch to one of the available addresses: %s') % \
(", ".join(['<a href="%s">%s</a>' % (host, host) for host in HUE_LOAD_BALANCER.get()]))
LOG.warning('User %s is bypassing the load balancer' % request.user.username)

if message:
banner_message = '<div style="padding: 4px; text-align: center; background-color: #003F6C; height: 24px; color: #DBE8F1">%s</div>' \
% message

return banner_message

def commonshare():
Expand Down

0 comments on commit f4a36e2

Please sign in to comment.