diff --git a/.docker-compose.env b/.docker-compose.env index 9cb7a59e274..3b7fd616b6d 100644 --- a/.docker-compose.env +++ b/.docker-compose.env @@ -17,6 +17,6 @@ MFR_SERVER_URL=http://localhost:7778 #SHARE_URL=http://192.168.168.167:8000/ BROKER_URL=amqp://guest:guest@192.168.168.167:5672/ REDIS_URL=redis://192.168.168.167:6379/1 -EMBER_DOMAIN=192.168.168.167 +PRIMARY_WEB_APP_DOMAIN=192.168.168.167 #PYTHONUNBUFFERED=0 # This when set to 0 will allow print statements to be visible in the Docker logs diff --git a/addons/osfstorage/tests/test_views.py b/addons/osfstorage/tests/test_views.py index d6c1fffff33..ba4ebe01482 100644 --- a/addons/osfstorage/tests/test_views.py +++ b/addons/osfstorage/tests/test_views.py @@ -36,7 +36,7 @@ from osf_tests.factories import ProjectFactory, ApiOAuth2PersonalTokenFactory, PreprintFactory from website.files.utils import attach_versions -from website.settings import EXTERNAL_EMBER_APPS +from website.settings import EXTERNAL_WEB_APPS from api_tests.draft_nodes.views.test_draft_node_files_lists import prepare_mock_wb_response @@ -1419,7 +1419,7 @@ def test_file_view_updates_history(self): file = GithubFile.objects.get(_path='/testpath', provider='github') assert file.history - @mock.patch('website.views.stream_emberapp') + @mock.patch('website.views.stream_web_app') def test_file_views(self, mock_ember): with override_flag(features.EMBER_FILE_PROJECT_DETAIL, active=True): file = create_test_file(target=self.node, user=self.user) @@ -1433,8 +1433,8 @@ def test_file_views(self, mock_ember): assert mock_ember.called args, kwargs = mock_ember.call_args - assert args[0] == EXTERNAL_EMBER_APPS['ember_osf_web']['server'] - assert args[1] == EXTERNAL_EMBER_APPS['ember_osf_web']['path'].rstrip('/') + assert args[0] == EXTERNAL_WEB_APPS['ember_osf_web']['server'] + assert args[1] == EXTERNAL_WEB_APPS['ember_osf_web']['path'].rstrip('/') def test_download_file(self): file = create_test_file(target=self.node, user=self.user) diff --git a/addons/wiki/views.py b/addons/wiki/views.py index 11009c10b07..bdbf1306f52 100644 --- a/addons/wiki/views.py +++ b/addons/wiki/views.py @@ -17,7 +17,7 @@ from website.profile.utils import get_profile_image_url from website.project.views.node import _view_project from website.project.model import has_anonymous_link -from website.ember_osf_web.decorators import ember_flag_is_active +from website.external_web_app.decorators import ember_flag_is_active from website.project.decorators import ( must_be_contributor_or_public, must_have_addon, must_not_be_registration, diff --git a/docker-compose.yml b/docker-compose.yml index f00b589f7e0..e7823381993 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -284,6 +284,23 @@ services: - ember_osf_web_dist_vol:/code/dist stdin_open: true + ################# + # Anguler OSF # + ################# + + angular_osf: + image: chiku314/angular-osf:latest + ports: + - '4300:4300' + depends_on: + - api + - web + environment: + - CHOKIDAR_USEPOLLING=true + - WATCHPACK_POLLING=true + - NG_CLI_ANALYTICS=false + command: ['npx', 'ng', 'serve', '--host', '0.0.0.0', '--port', '4300', '--poll', '2000'] + ############# # Preprints # ############# diff --git a/framework/auth/views.py b/framework/auth/views.py index 26aa494ddd4..c259a85aeb8 100644 --- a/framework/auth/views.py +++ b/framework/auth/views.py @@ -35,7 +35,7 @@ from osf.models.tag import Tag from osf.utils.requests import check_select_for_update from website.util.metrics import CampaignClaimedTags, CampaignSourceTags -from website.ember_osf_web.decorators import ember_flag_is_active +from website.external_web_app.decorators import ember_flag_is_active from osf import features diff --git a/osf_tests/test_guid.py b/osf_tests/test_guid.py index 5a77042e460..1271dfee519 100644 --- a/osf_tests/test_guid.py +++ b/osf_tests/test_guid.py @@ -269,8 +269,8 @@ def test_resolve_guid_download_file(self): assert res.status_code == 302 assert f'{WATERBUTLER_URL}/v1/resources/{unpub_pp._id}/providers/{unpub_pp.primary_file.provider}{unpub_pp.primary_file.path}?version=1&action=download&direct' in res.location - @mock.patch('website.settings.USE_EXTERNAL_EMBER', True) - @mock.patch('website.settings.EXTERNAL_EMBER_APPS', { + @mock.patch('website.settings.USE_EXTERNAL_WEB_APP', True) + @mock.patch('website.settings.EXTERNAL_WEB_APPS', { 'preprints': { 'server': 'http://localhost:4200', 'path': '/preprints/' @@ -289,8 +289,8 @@ def test_resolve_guid_download_file_from_emberapp_preprints(self): assert res.status_code == 302 assert f'{WATERBUTLER_URL}/v1/resources/{pp._id}/providers/{pp.primary_file.provider}{pp.primary_file.path}?action=download&direct&version=1' in res.location - @mock.patch('website.settings.USE_EXTERNAL_EMBER', True) - @mock.patch('website.settings.EXTERNAL_EMBER_APPS', { + @mock.patch('website.settings.USE_EXTERNAL_WEB_APP', True) + @mock.patch('website.settings.EXTERNAL_WEB_APPS', { 'preprints': { 'server': 'http://localhost:4200', 'path': '/preprints/' diff --git a/tests/test_addons.py b/tests/test_addons.py index f6fda06a024..531f01abefc 100644 --- a/tests/test_addons.py +++ b/tests/test_addons.py @@ -46,7 +46,7 @@ from framework import sentry from api.base.settings.defaults import API_BASE from tests.json_api_test_app import JSONAPITestApp -from website.settings import EXTERNAL_EMBER_APPS +from website.settings import EXTERNAL_WEB_APPS from waffle.testutils import override_flag from django.conf import settings as django_conf_settings @@ -1360,7 +1360,7 @@ def test_action_download_redirects_to_download_with_version(self): # Note: version is added but us but all other url params are added as well assert_urls_equal(location.url, file_node.generate_waterbutler_url(action='download', direct=None, revision=1, version='')) - @mock.patch('website.views.stream_emberapp') + @mock.patch('website.views.stream_web_app') @pytest.mark.enable_bookmark_creation def test_action_view_calls_view_file(self, mock_ember): self.user.reload() @@ -1374,10 +1374,10 @@ def test_action_view_calls_view_file(self, mock_ember): args, kwargs = mock_ember.call_args assert kwargs == {} - assert args[0] == EXTERNAL_EMBER_APPS['ember_osf_web']['server'] - assert args[1] == EXTERNAL_EMBER_APPS['ember_osf_web']['path'].rstrip('/') + assert args[0] == EXTERNAL_WEB_APPS['ember_osf_web']['server'] + assert args[1] == EXTERNAL_WEB_APPS['ember_osf_web']['path'].rstrip('/') - @mock.patch('website.views.stream_emberapp') + @mock.patch('website.views.stream_web_app') @pytest.mark.enable_bookmark_creation def test_no_action_calls_view_file(self, mock_ember): self.user.reload() @@ -1391,8 +1391,8 @@ def test_no_action_calls_view_file(self, mock_ember): args, kwargs = mock_ember.call_args assert kwargs == {} - assert args[0] == EXTERNAL_EMBER_APPS['ember_osf_web']['server'] - assert args[1] == EXTERNAL_EMBER_APPS['ember_osf_web']['path'].rstrip('/') + assert args[0] == EXTERNAL_WEB_APPS['ember_osf_web']['server'] + assert args[1] == EXTERNAL_WEB_APPS['ember_osf_web']['path'].rstrip('/') def test_download_create_guid(self): file_node = self.get_test_file() @@ -1462,7 +1462,7 @@ def test_nonstorage_addons_raise(self): ) assert resp.status_code == 400 - @mock.patch('website.views.stream_emberapp') + @mock.patch('website.views.stream_web_app') def test_head_returns_url_and_redriect(self, mock_ember): file_node = self.get_test_file() guid = file_node.get_guid(create=True) @@ -1473,8 +1473,8 @@ def test_head_returns_url_and_redriect(self, mock_ember): args, kwargs = mock_ember.call_args assert kwargs == {} - assert args[0] == EXTERNAL_EMBER_APPS['ember_osf_web']['server'] - assert args[1] == EXTERNAL_EMBER_APPS['ember_osf_web']['path'].rstrip('/') + assert args[0] == EXTERNAL_WEB_APPS['ember_osf_web']['server'] + assert args[1] == EXTERNAL_WEB_APPS['ember_osf_web']['path'].rstrip('/') def test_head_returns_url_with_version_and_redirect(self): diff --git a/tests/test_ember_osf_web.py b/tests/test_ember_osf_web.py index f25ac1af961..53451ab10cd 100644 --- a/tests/test_ember_osf_web.py +++ b/tests/test_ember_osf_web.py @@ -2,7 +2,7 @@ from flask import request from tests.base import OsfTestCase -from website.ember_osf_web.decorators import ember_flag_is_active +from website.external_web_app.decorators import ember_flag_is_active from osf_tests.factories import FlagFactory, UserFactory from django.contrib.auth.models import Group @@ -16,24 +16,26 @@ def setUp(self): FlagFactory(name='inactive_flag', everyone=False).save() self.mock_func = lambda: 'test value' - @mock.patch('website.ember_osf_web.decorators.use_ember_app') - def test_use_ember_app(self, mock_use_ember_app): + # TODO: This test case is not Ember App specific. + @mock.patch('website.external_web_app.decorators.use_primary_web_app') + def test_use_primary_web_app(self, mock_use_primary_web_app): ember_flag_is_active('active_flag')(self.mock_func)() - mock_use_ember_app.assert_called_with() + mock_use_primary_web_app.assert_called_with() - @mock.patch('website.ember_osf_web.decorators.use_ember_app') - def test_dont_use_ember_app(self, mock_use_ember_app): + # TODO: This test case is not Ember App specific. + @mock.patch('website.external_web_app.decorators.use_primary_web_app') + def test_dont_use_primary_web_app(self, mock_use_primary_web_app): # mock over external module 'waflle.flag_is_active` not ours ember_flag_is_active('inactive_flag')(self.mock_func)() - assert not mock_use_ember_app.called + assert not mock_use_primary_web_app.called @mock.patch('api.waffle.utils._get_current_user') - @mock.patch('website.ember_osf_web.decorators.flag_is_active') - @mock.patch('website.ember_osf_web.decorators.use_ember_app') - def test_ember_flag_is_active_authenticated_user(self, mock_use_ember_app, mock_flag_is_active, mock__get_current_user): + @mock.patch('website.external_web_app.decorators.flag_is_active') + @mock.patch('website.external_web_app.decorators.use_primary_web_app') + def test_ember_flag_is_active_authenticated_user(self, mock_use_primary_web_app, mock_flag_is_active, mock__get_current_user): # mock over external module 'waflle.flag_is_active` not ours user = UserFactory() @@ -42,12 +44,12 @@ def test_ember_flag_is_active_authenticated_user(self, mock_use_ember_app, mock_ ember_flag_is_active('active_flag')(self.mock_func)() mock_flag_is_active.assert_called_with(request, 'active_flag') - mock_use_ember_app.assert_called_with() + mock_use_primary_web_app.assert_called_with() @mock.patch('api.waffle.utils._get_current_user', return_value=None) - @mock.patch('website.ember_osf_web.decorators.flag_is_active') - @mock.patch('website.ember_osf_web.decorators.use_ember_app') - def test_ember_flag_is_active_unauthenticated_user(self, mock_use_ember_app, mock_flag_is_active, mock__get_current_user): + @mock.patch('website.external_web_app.decorators.flag_is_active') + @mock.patch('website.external_web_app.decorators.use_primary_web_app') + def test_ember_flag_is_active_unauthenticated_user(self, mock_use_primary_web_app, mock_flag_is_active, mock__get_current_user): # mock over external module 'waflle.flag_is_active` not ours ember_flag_is_active('active_flag')(self.mock_func)() @@ -56,4 +58,4 @@ def test_ember_flag_is_active_unauthenticated_user(self, mock_use_ember_app, moc self.flag.groups.add(group) mock_flag_is_active.assert_called_with(request, 'active_flag') - mock_use_ember_app.assert_called_with() + mock_use_primary_web_app.assert_called_with() diff --git a/tests/test_misc_views.py b/tests/test_misc_views.py index 814ab0556f1..99fb8e8cb63 100644 --- a/tests/test_misc_views.py +++ b/tests/test_misc_views.py @@ -775,27 +775,27 @@ def test_find_unread_includes_edited_comments(self): n_unread = Comment.find_n_unread(user=user, node=project, page='node') assert n_unread == 1 -@mock.patch('website.views.PROXY_EMBER_APPS', False) +@mock.patch('website.views.PROXY_WEB_APPS', False) class TestResolveGuid(OsfTestCase): def setUp(self): super().setUp() - @mock.patch('website.views.use_ember_app') - def test_preprint_provider_without_domain(self, mock_use_ember_app): + @mock.patch('website.views.use_primary_web_app') + def test_preprint_provider_without_domain(self, mock_use_primary_web_app): provider = PreprintProviderFactory(domain='') preprint = PreprintFactory(provider=provider) url = web_url_for('resolve_guid', _guid=True, guid=preprint._id) res = self.app.get(url) - mock_use_ember_app.assert_called_with() + mock_use_primary_web_app.assert_called_with() - @mock.patch('website.views.use_ember_app') - def test_preprint_provider_with_domain_without_redirect(self, mock_use_ember_app): + @mock.patch('website.views.use_primary_web_app') + def test_preprint_provider_with_domain_without_redirect(self, mock_use_primary_web_app): domain = 'https://test.com/' provider = PreprintProviderFactory(_id='test', domain=domain, domain_redirect_enabled=False) preprint = PreprintFactory(provider=provider) url = web_url_for('resolve_guid', _guid=True, guid=preprint._id) res = self.app.get(url) - mock_use_ember_app.assert_called_with() + mock_use_primary_web_app.assert_called_with() def test_preprint_provider_with_domain_with_redirect(self): domain = 'https://test.com/' @@ -809,10 +809,10 @@ def test_preprint_provider_with_domain_with_redirect(self): assert res.headers['location'] == f'{domain}{preprint._id}/' assert res.request.path == f'/{preprint._id}/' - @mock.patch('website.views.use_ember_app') - def test_preprint_provider_with_osf_domain(self, mock_use_ember_app): + @mock.patch('website.views.use_primary_web_app') + def test_preprint_provider_with_osf_domain(self, mock_use_primary_web_app): provider = PreprintProviderFactory(_id='osf', domain='https://osf.io/') preprint = PreprintFactory(provider=provider) url = web_url_for('resolve_guid', _guid=True, guid=preprint._id) res = self.app.get(url) - mock_use_ember_app.assert_called_with() + mock_use_primary_web_app.assert_called_with() diff --git a/website/conferences/views.py b/website/conferences/views.py index cf7dbfd6d3b..5897f7cd9f7 100644 --- a/website/conferences/views.py +++ b/website/conferences/views.py @@ -15,7 +15,7 @@ from website import settings from website.conferences import utils from website.conferences.message import ConferenceMessage, ConferenceError -from website.ember_osf_web.decorators import ember_flag_is_active +from website.external_web_app.decorators import ember_flag_is_active from website.mails import CONFERENCE_SUBMITTED, CONFERENCE_INACTIVE, CONFERENCE_FAILED, CONFERENCE_DEPRECATION from website.mails import send_mail from website.util import web_url_for diff --git a/website/ember_osf_web/views.py b/website/ember_osf_web/views.py deleted file mode 100644 index 84f23ad8327..00000000000 --- a/website/ember_osf_web/views.py +++ /dev/null @@ -1,26 +0,0 @@ -import os -import json -from website import settings -from framework.status import pop_status_messages - -from website.settings import EXTERNAL_EMBER_APPS - -ember_osf_web_dir = os.path.abspath(os.path.join(os.getcwd(), EXTERNAL_EMBER_APPS['ember_osf_web']['path'])) - -routes = [ - '/institutions/', -] - -def use_ember_app(**kwargs): - from website.views import stream_emberapp - resp = stream_emberapp(EXTERNAL_EMBER_APPS['ember_osf_web']['server'], ember_osf_web_dir) - messages = pop_status_messages() - if messages: - try: - status = [{'id': stat[5] if stat[5] else stat[0], 'class': stat[2], 'jumbo': stat[1], 'dismiss': stat[3], 'extra': stat[6]} for stat in messages] - resp.set_cookie(settings.COOKIE_NAME + '_status', json.dumps(status)) - except IndexError: - # Ignoring the error as it will only occur when statuses were created prior to merging the changes that add - # extra and id, (patch to prevent breaking the app meanwhile) - pass - return resp diff --git a/website/ember_osf_web/__init__.py b/website/external_web_app/__init__.py similarity index 100% rename from website/ember_osf_web/__init__.py rename to website/external_web_app/__init__.py diff --git a/website/ember_osf_web/decorators.py b/website/external_web_app/decorators.py similarity index 82% rename from website/ember_osf_web/decorators.py rename to website/external_web_app/decorators.py index 978445f2bf3..86478727cea 100644 --- a/website/ember_osf_web/decorators.py +++ b/website/external_web_app/decorators.py @@ -3,7 +3,7 @@ from flask import request from api.waffle.utils import flag_is_active -from website.ember_osf_web.views import use_ember_app +from website.external_web_app.views import use_primary_web_app def ember_flag_is_active(flag_name): @@ -15,7 +15,7 @@ def decorator(func): @functools.wraps(func) def wrapped(*args, **kwargs): if flag_is_active(request, flag_name): - return use_ember_app() + return use_primary_web_app() else: return func(*args, **kwargs) return wrapped diff --git a/website/external_web_app/views.py b/website/external_web_app/views.py new file mode 100644 index 00000000000..525bc7d33e4 --- /dev/null +++ b/website/external_web_app/views.py @@ -0,0 +1,44 @@ +import os +import json +from website import settings +from framework.status import pop_status_messages + +from website.settings import EXTERNAL_WEB_APPS + +def get_primary_app_config(): + from website.settings import PRIMARY_WEB_APP + return EXTERNAL_WEB_APPS.get(PRIMARY_WEB_APP, {}) + +def get_primary_app_dir(): + app_config = get_primary_app_config() + if 'path' in app_config: + return os.path.abspath(os.path.join(os.getcwd(), app_config['path'])) + return None + +routes = [ + '/institutions/', +] + +def use_primary_web_app(**kwargs): + from rest_framework import status as http_status + from framework.exceptions import HTTPError + from website.views import stream_web_app + + app_config = get_primary_app_config() + if not app_config: + raise HTTPError( + http_status.HTTP_500_INTERNAL_SERVER_ERROR, + data={'message': 'Primary web app not configured'} + ) + + resp = stream_web_app(app_config['server'], get_primary_app_dir()) + messages = pop_status_messages() + if messages: + try: + status = [{'id': stat[5] if stat[5] else stat[0], 'class': stat[2], 'jumbo': stat[1], 'dismiss': stat[3], 'extra': stat[6]} for stat in messages] + resp.set_cookie(settings.COOKIE_NAME + '_status', json.dumps(status)) + except IndexError: + # Ignoring the error as it will only occur when statuses were created prior to merging the changes that add + # extra and id, (patch to prevent breaking the app meanwhile) + pass + return resp diff --git a/website/institutions/views.py b/website/institutions/views.py index 9477fa8c910..59c638b7e28 100644 --- a/website/institutions/views.py +++ b/website/institutions/views.py @@ -1,7 +1,7 @@ -from website.ember_osf_web.views import use_ember_app +from website.external_web_app.views import use_primary_web_app def view_institution(inst_id, **kwargs): - return use_ember_app() + return use_primary_web_app() def view_institution_dashboard(inst_id, **kwargs): - return use_ember_app() + return use_primary_web_app() diff --git a/website/profile/views.py b/website/profile/views.py index c4d49147454..57e7abd1c49 100644 --- a/website/profile/views.py +++ b/website/profile/views.py @@ -33,7 +33,7 @@ from website import mailchimp_utils from website import settings from website import language -from website.ember_osf_web.decorators import ember_flag_is_active +from website.external_web_app.decorators import ember_flag_is_active from website.oauth.utils import get_available_scopes from website.profile import utils as profile_utils from website.util import api_v2_url, web_url_for, paths diff --git a/website/project/views/drafts.py b/website/project/views/drafts.py index e4ee762c992..d480a0fc2e0 100644 --- a/website/project/views/drafts.py +++ b/website/project/views/drafts.py @@ -25,7 +25,7 @@ must_have_permission, ) from website import settings -from website.ember_osf_web.decorators import ember_flag_is_active +from website.external_web_app.decorators import ember_flag_is_active from website.project import utils from website.project.metadata.schemas import METASCHEMA_ORDERING diff --git a/website/project/views/file.py b/website/project/views/file.py index 780b26a740c..3ed435e7aae 100644 --- a/website/project/views/file.py +++ b/website/project/views/file.py @@ -10,7 +10,7 @@ from website.util import rubeus from website.project.decorators import must_be_contributor_or_public, must_not_be_retracted_registration from website.project.views.node import _view_project -from website.ember_osf_web.views import use_ember_app +from website.external_web_app.views import use_primary_web_app @must_not_be_retracted_registration @@ -20,10 +20,10 @@ def collect_file_trees(auth, node, **kwargs): format data as appropriate. """ if isinstance(node, Node) and flag_is_active(request, features.EMBER_PROJECT_FILES): - return use_ember_app() + return use_primary_web_app() if isinstance(node, Registration) and flag_is_active(request, features.EMBER_REGISTRATION_FILES): - return use_ember_app() + return use_primary_web_app() serialized = _view_project(node, auth, primary=True) # Add addon static assets diff --git a/website/project/views/node.py b/website/project/views/node.py index 32048444c7a..9a8d26e9ff2 100644 --- a/website/project/views/node.py +++ b/website/project/views/node.py @@ -18,7 +18,7 @@ from framework.auth.decorators import must_be_logged_in, collect_auth from osf.external.gravy_valet.request_helpers import get_gv_citation_url_list_for_project from osf.external.gravy_valet.translations import EphemeralAddonConfig -from website.ember_osf_web.decorators import ember_flag_is_active +from website.external_web_app.decorators import ember_flag_is_active from api.waffle.utils import flag_is_active, storage_i18n_flag_active, storage_usage_flag_active from framework.exceptions import HTTPError from osf.models.nodelog import NodeLog @@ -31,7 +31,7 @@ from website import language from website.util import rubeus -from website.ember_osf_web.views import use_ember_app +from website.external_web_app.views import use_primary_web_app from osf.exceptions import NodeStateError from website.project import new_node, new_private_link from website.project.decorators import ( @@ -269,7 +269,7 @@ def project_before_template(auth, node, **kwargs): def node_registrations(auth, node, **kwargs): if request.path.startswith('/project/'): return redirect(f'/{node._id}/registrations/') - return use_ember_app() + return use_primary_web_app() @must_be_valid_project @@ -278,7 +278,7 @@ def node_registrations(auth, node, **kwargs): def node_forks(auth, node, **kwargs): if request.path.startswith('/project/'): return redirect('/' + node._id + '/forks/') - return use_ember_app() + return use_primary_web_app() @must_be_valid_project @@ -576,7 +576,7 @@ def project_reorder_components(node, **kwargs): def project_statistics(auth, node, **kwargs): if request.path.startswith('/project/'): return redirect('/' + node._id + '/analytics/') - return use_ember_app() + return use_primary_web_app() ############################################################################### diff --git a/website/project/views/register.py b/website/project/views/register.py index 265fda1edea..7129a2e009d 100644 --- a/website/project/views/register.py +++ b/website/project/views/register.py @@ -20,7 +20,7 @@ from website.project.utils import serialize_node from osf.utils.permissions import ADMIN from website import language -from website.ember_osf_web.decorators import ember_flag_is_active +from website.external_web_app.decorators import ember_flag_is_active from website.project.metadata.schemas import _id_to_name from website import util from website.project.metadata.utils import serialize_meta_schema diff --git a/website/routes.py b/website/routes.py index 2a3415e1051..b4a6ab52b0a 100644 --- a/website/routes.py +++ b/website/routes.py @@ -57,10 +57,10 @@ from website.reviews import views as reviews_views from website.institutions import views as institution_views from website.notifications import views as notification_views -from website.ember_osf_web import views as ember_osf_web_views +from website.external_web_app import views as external_web_app_views from website.closed_challenges import views as closed_challenges_views from website.identifiers import views as identifier_views -from website.settings import EXTERNAL_EMBER_APPS, EXTERNAL_EMBER_SERVER_TIMEOUT +from website.settings import EXTERNAL_WEB_APPS, EXTERNAL_APP_SERVER_TIMEOUT from api.waffle.utils import flag_is_active @@ -244,9 +244,9 @@ def ember_app(path=None): ember_app = None - for k in EXTERNAL_EMBER_APPS.keys(): + for k in EXTERNAL_WEB_APPS.keys(): if request.path.strip('/').startswith(k): - ember_app = EXTERNAL_EMBER_APPS[k] + ember_app = EXTERNAL_WEB_APPS[k] if k == 'preprints': # If a valid guid is provided w/o version, find and redirect to the latest version. This only applies # to route preprints//: e.g. /preprints/osf/abcde -> /preprints/osf/abcde_v3 @@ -258,16 +258,20 @@ def ember_app(path=None): if preprint and preprint._id != guid_str: return redirect(f"{settings.DOMAIN}preprints/{path_values[0]}/{preprint._id}", code=302) # For all other cases, let ember app handle it - ember_app = EXTERNAL_EMBER_APPS.get('ember_osf_web', False) or ember_app + ember_app = EXTERNAL_WEB_APPS.get('ember_osf_web', False) or ember_app break if not ember_app: raise HTTPError(http_status.HTTP_404_NOT_FOUND) - if settings.PROXY_EMBER_APPS: - path = request.path[len(ember_app['path']):] + if settings.PROXY_WEB_APPS: + strip_prefix = ember_app.get('strip_prefix') + if strip_prefix or strip_prefix is None: + path = request.path[len(ember_app['path']):] + else: + path = request.path url = urljoin(ember_app['server'], path) - resp = requests.get(url, stream=True, timeout=EXTERNAL_EMBER_SERVER_TIMEOUT, headers={'accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8'}) + resp = requests.get(url, stream=True, timeout=EXTERNAL_APP_SERVER_TIMEOUT, headers={'accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8'}) excluded_headers = ['content-encoding', 'content-length', 'transfer-encoding', 'connection'] headers = [(name, value) for (name, value) in resp.raw.headers.items() if name.lower() not in excluded_headers] return Response(resp.content, resp.status_code, headers) @@ -348,10 +352,10 @@ def make_url_map(app): Rule('/sitemaps/', 'get', sitemap_file, json_renderer), ]) - # Ember Applications - if settings.USE_EXTERNAL_EMBER: - # Routes that serve up the Ember application. Hide behind feature flag. - for prefix in EXTERNAL_EMBER_APPS.keys(): + # External Applications + if settings.USE_EXTERNAL_WEB_APP: + # Routes that serve up the external application. Hide behind feature flag. + for prefix in EXTERNAL_WEB_APPS.keys(): process_rules(app, [ Rule( [ @@ -378,17 +382,21 @@ def make_url_map(app): ), ], prefix='/' + prefix) - if EXTERNAL_EMBER_APPS.get('ember_osf_web'): + # Import PRIMARY_WEB_APP setting + from website.settings import PRIMARY_WEB_APP + + primary_app_config = EXTERNAL_WEB_APPS.get(PRIMARY_WEB_APP) + if primary_app_config: process_rules(app, [ Rule( - ember_osf_web_views.routes, + external_web_app_views.routes, 'get', - ember_osf_web_views.use_ember_app, + external_web_app_views.use_primary_web_app, notemplate ) ]) - if 'routes' in EXTERNAL_EMBER_APPS['ember_osf_web']: - for route in EXTERNAL_EMBER_APPS['ember_osf_web']['routes']: + if 'routes' in primary_app_config: + for route in primary_app_config['routes']: process_rules(app, [ Rule( [ @@ -396,7 +404,7 @@ def make_url_map(app): '/', ], 'get', - ember_osf_web_views.use_ember_app, + external_web_app_views.use_primary_web_app, notemplate, endpoint_suffix='__' + route ) diff --git a/website/search/views.py b/website/search/views.py index 416536a79e6..aef35c526d7 100644 --- a/website/search/views.py +++ b/website/search/views.py @@ -16,7 +16,7 @@ from osf.models import OSFUser, AbstractNode from website import settings from website.project.views.contributor import get_node_contributors_abbrev -from website.ember_osf_web.decorators import ember_flag_is_active +from website.external_web_app.decorators import ember_flag_is_active from website.search import exceptions import website.search.search as search from website.search.util import build_query diff --git a/website/settings/defaults.py b/website/settings/defaults.py index 80cc6b18ed1..5f82b89ce0d 100644 --- a/website/settings/defaults.py +++ b/website/settings/defaults.py @@ -94,12 +94,12 @@ def parent_dir(path): 'prefix': PROTOCOL, 'suffix': '/' } -# External Ember App Local Development -USE_EXTERNAL_EMBER = False -PROXY_EMBER_APPS = False +# External Web App Local Development +USE_EXTERNAL_WEB_APP = False +PROXY_WEB_APPS = False # http://docs.python-requests.org/en/master/user/advanced/#timeouts -EXTERNAL_EMBER_SERVER_TIMEOUT = 3.05 -EXTERNAL_EMBER_APPS = {} +EXTERNAL_APP_SERVER_TIMEOUT = 3.05 +EXTERNAL_WEB_APPS = {} LOG_PATH = os.path.join(APP_PATH, 'logs') TEMPLATES_PATH = os.path.join(BASE_PATH, 'templates') diff --git a/website/settings/local-ci.py b/website/settings/local-ci.py index c63fce5a86a..c9cb895c20c 100644 --- a/website/settings/local-ci.py +++ b/website/settings/local-ci.py @@ -26,8 +26,9 @@ 'prefix': 'http://local.', 'suffix': ':4201/' } -USE_EXTERNAL_EMBER = True -EXTERNAL_EMBER_APPS = { +USE_EXTERNAL_WEB_APP = True +PRIMARY_WEB_APP = 'ember_osf_web' +EXTERNAL_WEB_APPS = { 'ember_osf_web': { 'server': 'http://localhost:4200', 'path': os.environ.get('HOME') + 'website/ember_osf_web/' diff --git a/website/settings/local-dist.py b/website/settings/local-dist.py index 212b9926f7e..4c68b42d2bb 100644 --- a/website/settings/local-dist.py +++ b/website/settings/local-dist.py @@ -29,13 +29,15 @@ 'prefix': 'http://local.', 'suffix': ':4201/' } -USE_EXTERNAL_EMBER = True -PROXY_EMBER_APPS = True -EMBER_DOMAIN = environ.get('EMBER_DOMAIN', 'localhost') -LIVE_RELOAD_DOMAIN = f'http://{EMBER_DOMAIN}:4200' # Change port for the current app -EXTERNAL_EMBER_APPS = { +USE_EXTERNAL_WEB_APP = True +PROXY_WEB_APPS = True +PRIMARY_WEB_APP_DOMAIN = environ.get('PRIMARY_WEB_APP_DOMAIN', 'localhost') + +# Primary web app configuration - change this to switch between ember and angular +PRIMARY_WEB_APP = 'angular_osf' +EXTERNAL_WEB_APPS = { 'ember_osf_web': { - 'server': f'http://{EMBER_DOMAIN}:4200/', + 'server': f'http://{PRIMARY_WEB_APP_DOMAIN}:4200/', 'path': '/ember_osf_web/', 'routes': [ 'collections', @@ -43,16 +45,28 @@ 'handbook', ], }, + 'angular_osf': { + 'server': f'http://{PRIMARY_WEB_APP_DOMAIN}:4300/', + 'path': '/angular_osf/', + 'strip_prefix': False, + 'routes': [ + 'collections', + 'registries', + 'handbook', + ], + }, 'preprints': { - 'server': f'http://{EMBER_DOMAIN}:4201/', + 'server': f'http://{PRIMARY_WEB_APP_DOMAIN}:4201/', 'path': '/preprints/' }, 'reviews': { - 'server': f'http://{EMBER_DOMAIN}:4203/', + 'server': f'http://{PRIMARY_WEB_APP_DOMAIN}:4203/', 'path': '/reviews/' }, } +LIVE_RELOAD_DOMAIN = EXTERNAL_WEB_APPS[PRIMARY_WEB_APP]['server'] + SEARCH_ENGINE = 'elastic' ELASTIC_TIMEOUT = 10 diff --git a/website/templates/public/pages/preprint_landing.mako b/website/templates/public/pages/preprint_landing.mako index b405eaa38ab..fd4d432b73a 100644 --- a/website/templates/public/pages/preprint_landing.mako +++ b/website/templates/public/pages/preprint_landing.mako @@ -6,8 +6,8 @@

Preprints service is not activated.

  • Set the following in local.py:
  • -
    USE_EXTERNAL_EMBER = True
    -EXTERNAL_EMBER_APPS = {
    +
    USE_EXTERNAL_WEB_APP = True
    +EXTERNAL_WEB_APPS = {
       'preprints': {
         'url': '/preprints/',
         'server': 'http://localhost:4200',
    diff --git a/website/templates/public/pages/registries_landing.mako b/website/templates/public/pages/registries_landing.mako
    index ff974f4e270..ac92c7eae4f 100644
    --- a/website/templates/public/pages/registries_landing.mako
    +++ b/website/templates/public/pages/registries_landing.mako
    @@ -6,8 +6,8 @@
     

    Registries service is not activated.

    • Set the following in local.py:
    • -
      USE_EXTERNAL_EMBER = True
      -EXTERNAL_EMBER_APPS = {
      +
      USE_EXTERNAL_WEB_APP = True
      +EXTERNAL_WEB_APPS = {
         'registries': {
           'url': '/registries/',
           'server': 'http://localhost:4300',
      diff --git a/website/templates/public/pages/reviews_landing.mako b/website/templates/public/pages/reviews_landing.mako
      index 0a7fa40575e..10882912d98 100644
      --- a/website/templates/public/pages/reviews_landing.mako
      +++ b/website/templates/public/pages/reviews_landing.mako
      @@ -6,8 +6,8 @@
       

      Reviews service is not activated.

      • Set the following in local.py:
      • -
        USE_EXTERNAL_EMBER = True
        -EXTERNAL_EMBER_APPS = {
        +
        USE_EXTERNAL_WEB_APP = True
        +EXTERNAL_WEB_APPS = {
           'reviews': {
             'url': '/reviews/',
             'server': 'http://localhost:4400',
        diff --git a/website/views.py b/website/views.py
        index a0b3daeec3a..ff5ebbec0cf 100644
        --- a/website/views.py
        +++ b/website/views.py
        @@ -24,9 +24,9 @@
         from osf import features, exceptions
         from osf.models import Guid, Preprint, AbstractNode, Node, DraftNode, Registration, BaseFileNode
         
        -from website.settings import EXTERNAL_EMBER_APPS, PROXY_EMBER_APPS, EXTERNAL_EMBER_SERVER_TIMEOUT, DOMAIN
        -from website.ember_osf_web.decorators import ember_flag_is_active
        -from website.ember_osf_web.views import use_ember_app
        +from website.settings import EXTERNAL_WEB_APPS, PROXY_WEB_APPS, EXTERNAL_APP_SERVER_TIMEOUT, DOMAIN
        +from website.external_web_app.decorators import ember_flag_is_active
        +from website.external_web_app.views import use_primary_web_app
         from website.project.decorators import check_contributor_auth
         from website.project.model import has_anonymous_link
         from osf.utils import permissions
        @@ -35,7 +35,14 @@
         from api.waffle.utils import storage_i18n_flag_active, flag_is_active
         
         logger = logging.getLogger(__name__)
        -ember_osf_web_dir = os.path.abspath(os.path.join(os.getcwd(), EXTERNAL_EMBER_APPS['ember_osf_web']['path']))
        +def get_primary_web_app_dir():
        +    from website.settings import PRIMARY_WEB_APP
        +    primary_app_config = EXTERNAL_WEB_APPS.get(PRIMARY_WEB_APP, {})
        +    if 'path' in primary_app_config:
        +        return os.path.abspath(os.path.join(os.getcwd(), primary_app_config['path']))
        +    return None
        +
        +primary_web_app_dir = get_primary_web_app_dir()
         
         
         def serialize_contributors_for_summary(node, max_count=3):
        @@ -132,7 +139,7 @@ def serialize_node_summary(node, auth, primary=True, show_path=False):
             return summary
         
         def index():
        -    return use_ember_app()
        +    return use_primary_web_app()
         
         def find_bookmark_collection(user):
             Collection = apps.get_model('osf.Collection')
        @@ -140,7 +147,7 @@ def find_bookmark_collection(user):
         
         @must_be_logged_in
         def dashboard(auth):
        -    return use_ember_app()
        +    return use_primary_web_app()
         
         @must_be_logged_in
         @ember_flag_is_active(features.EMBER_MY_PROJECTS)
        @@ -230,9 +237,9 @@ def resolve_guid_download(guid, provider=None):
             return proxy_url(_build_guid_url(unquote(resource.deep_url)))
         
         
        -def stream_emberapp(server, directory):
        -    if PROXY_EMBER_APPS:
        -        resp = requests.get(server, stream=True, timeout=EXTERNAL_EMBER_SERVER_TIMEOUT)
        +def stream_web_app(server, directory):
        +    if PROXY_WEB_APPS:
        +        resp = requests.get(server, stream=True, timeout=EXTERNAL_APP_SERVER_TIMEOUT)
                 return Response(stream_with_context(resp.iter_content()), resp.status_code)
             return send_from_directory(directory, 'index.html')
         
        @@ -299,40 +306,40 @@ def resolve_guid(guid, suffix=None):
                 if format_arg:
                     return guid_metadata_download(guid, resource, format_arg)
                 else:
        -            return use_ember_app()
        +            return use_primary_web_app()
         
             # Stream to ember app if resource has emberized view
             if isinstance(resource, Preprint):
                 if resource.provider.domain_redirect_enabled:
                     return redirect(resource.absolute_url, http_status.HTTP_301_MOVED_PERMANENTLY)
        -        return use_ember_app()
        +        return use_primary_web_app()
         
             elif isinstance(resource, Registration) and (clean_suffix in ('', 'comments', 'links', 'components', 'resources',)) and flag_is_active(request, features.EMBER_REGISTRIES_DETAIL_PAGE):
        -        return use_ember_app()
        +        return use_primary_web_app()
         
             elif isinstance(resource, Registration) and clean_suffix and clean_suffix.startswith('metadata') and flag_is_active(request, features.EMBER_REGISTRIES_DETAIL_PAGE):
        -        return use_ember_app()
        +        return use_primary_web_app()
         
             elif isinstance(resource, Registration) and (clean_suffix in ('files', 'files/osfstorage')) and flag_is_active(request, features.EMBER_REGISTRATION_FILES):
        -        return use_ember_app()
        +        return use_primary_web_app()
         
             elif isinstance(resource, Registration) and clean_suffix and (clean_suffix.startswith('recent-activity')):
        -        return use_ember_app()
        +        return use_primary_web_app()
         
             elif isinstance(resource, Node) and clean_suffix and clean_suffix.startswith('files') and flag_is_active(request, features.EMBER_PROJECT_FILES):
        -        return use_ember_app()
        +        return use_primary_web_app()
         
             elif isinstance(resource, Node) and clean_suffix and (clean_suffix.startswith('metadata') or clean_suffix.startswith('components') or clean_suffix.startswith('links')):
        -        return use_ember_app()
        +        return use_primary_web_app()
         
             elif isinstance(resource, OsfStorageFile) and isinstance(resource.target, DraftNode):
        -        return use_ember_app()
        +        return use_primary_web_app()
         
             elif isinstance(resource, BaseFileNode) and resource.is_file and not isinstance(resource.target, Preprint):
                 if isinstance(resource.target, Registration) and flag_is_active(request, features.EMBER_FILE_REGISTRATION_DETAIL):
        -            return use_ember_app()
        +            return use_primary_web_app()
                 if isinstance(resource.target, Node) and flag_is_active(request, features.EMBER_FILE_PROJECT_DETAIL):
        -            return use_ember_app()
        +            return use_primary_web_app()
         
             # Redirect to legacy endpoint for Nodes, Wikis etc.
             url = _build_guid_url(unquote(resource.deep_url), suffix)