diff --git a/api_tests/nodes/views/test_node_files_list.py b/api_tests/nodes/views/test_node_files_list.py index 68eb345199a..46afa3b3289 100644 --- a/api_tests/nodes/views/test_node_files_list.py +++ b/api_tests/nodes/views/test_node_files_list.py @@ -4,6 +4,7 @@ from furl import furl import responses from django.utils import timezone +from waffle.testutils import override_flag from framework.auth.core import Auth @@ -13,6 +14,8 @@ from api.base.settings.defaults import API_BASE from api.base.utils import waterbutler_api_url_for from api_tests import utils as api_utils +from osf.models import AbstractNode +from osf_tests.external.gravy_valet.gv_fakes import FakeGravyValet from tests.base import ApiTestCase from osf.models.files import FileVersionUserMetadata from osf_tests.factories import ( @@ -24,6 +27,7 @@ from osf.utils.permissions import READ from dateutil.parser import parse as parse_date from website import settings +from osf.features import ENABLE_GV def prepare_mock_wb_response( @@ -435,6 +439,110 @@ def test_files_list_contains_relationships_object(self): assert res.status_code == 200 assert 'relationships' in res.json['data'][0] +class TestGVNodeFileList(ApiTestCase): + def setUp(self): + super().setUp() + self.flag_override = override_flag(ENABLE_GV, True) + self.flag_override.__enter__() + self.user = AuthUserFactory() + self.project = ProjectFactory(creator=self.user) + self.private_url = f"/{API_BASE}nodes/{self.project._id}/files/" + self.resource_reference_id = '2fe95af1-e06e-4f5a-9fef-6fe85a88f62a' + self.configured_storage_addon_id = 'self.configured_storage_addon_id' + + self.user_two = AuthUserFactory() + + self.public_project = ProjectFactory(creator=self.user, is_public=True) + self.public_url = f"/{API_BASE}nodes/{self.public_project._id}/files/" + self.fake_gv = FakeGravyValet() + self.fake_gv.configure_resource(self.project) + self.fake_gv.configure_resource(self.public_project) + + def tearDown(self): + super().tearDown() + self.flag_override.__exit__(None, None, None) + + def configure_account(self): + self.fake_gv.configure_fake_provider('box') + return self.fake_gv.configure_fake_account(self.user, 'box') + + def configure_addon(self, project: AbstractNode): + account = self.configure_account() + return self.fake_gv.configure_fake_addon(project, account) + + @responses.activate + def test_returns_public_files_logged_out_with_gv_response(self): + self.configure_addon(self.public_project) + with self.fake_gv.run_fake(): + res = self.app.get(self.public_url, expect_errors=True) + assert res.status_code == 200 + assert res.json['data'][0]['attributes']['provider'] == 'osfstorage' + assert res.json['data'][1]['attributes']['provider'] == 'box' + assert res.content_type == 'application/vnd.api+json' + + @responses.activate + def test_returns_public_files_logged_in_no_gv_response(self): + with self.fake_gv.run_fake(): + res = self.app.get(self.public_url, auth=self.user.auth) + assert res.status_code == 200 + assert res.content_type == 'application/vnd.api+json' + assert len(res.json['data']) == 1 + assert res.json['data'][0]['attributes']['provider'] == 'osfstorage' + + @responses.activate + def test_returns_public_files_logged_in_with_gv_response(self): + self.configure_addon(self.public_project) + with self.fake_gv.run_fake(): + res = self.app.get(self.public_url, auth=self.user.auth) + assert res.status_code == 200 + assert res.content_type == 'application/vnd.api+json' + assert len(res.json['data']) == 2, 'invalid addon count' + assert res.json['data'][0]['attributes']['provider'] == 'osfstorage' + assert (res.json['data'][1]['attributes']['provider'] == 'box'), 'addon returned from gv is not of expected provider' + + @responses.activate + def test_returns_storage_addons_link(self): + self.configure_addon(self.project) + with self.fake_gv.run_fake(): + res = self.app.get(self.private_url, auth=self.user.auth) + assert 'storage_addons' in res.json['data'][1]['links'] + + def test_returns_private_files_logged_out(self): + res = self.app.get(self.private_url, expect_errors=True) + assert res.status_code == 401 + assert 'detail' in res.json['errors'][0] + + @responses.activate + def test_returns_private_files_logged_in_contributor(self): + self.configure_addon(self.project) + with self.fake_gv.run_fake(): + res = self.app.get(self.private_url, auth=self.user.auth) + assert res.status_code == 200 + assert res.content_type == 'application/vnd.api+json' + assert len(res.json['data']) == 2 + assert res.json['data'][0]['attributes']['provider'] == 'osfstorage' + assert res.json['data'][1]['attributes']['provider'] == 'box' + + @responses.activate + def test_returns_private_files_logged_in_non_contributor(self): + res = self.app.get( + self.private_url, auth=self.user_two.auth, expect_errors=True + ) + assert res.status_code == 403 + assert 'detail' in res.json['errors'][0] + + @responses.activate + def test_returns_private_files_logged_in_osf_group_member(self): + self.configure_addon(self.project) + group_mem = AuthUserFactory() + group = OSFGroupFactory(creator=group_mem) + self.project.add_osf_group(group, READ) + with self.fake_gv.run_fake(): + res = self.app.get( + self.private_url, auth=group_mem.auth, expect_errors=True + ) + assert res.status_code == 200 + class TestNodeFilesListFiltering(ApiTestCase): diff --git a/osf/external/gravy_valet/request_helpers.py b/osf/external/gravy_valet/request_helpers.py index 72a7911e6bb..22fe2a925f4 100644 --- a/osf/external/gravy_valet/request_helpers.py +++ b/osf/external/gravy_valet/request_helpers.py @@ -105,7 +105,7 @@ def get_gv_result( params=params, ).json() - if not response_json['data']: + if not response_json.get('data'): return None data = response_json['data'] if isinstance(data, list): diff --git a/osf/external/gravy_valet/translations.py b/osf/external/gravy_valet/translations.py index a004515002b..b81661876a5 100644 --- a/osf/external/gravy_valet/translations.py +++ b/osf/external/gravy_valet/translations.py @@ -1,6 +1,7 @@ import enum import dataclasses +from dataclasses import asdict from addons.box.apps import BoxAddonAppConfig from . import request_helpers as gv_requests @@ -46,6 +47,10 @@ class EphemeralAddonConfig: short_name: str full_name: str + @property + def has_hgrid_files(self): + return True + @classmethod def from_legacy_config(cls, legacy_config): return cls( @@ -55,6 +60,9 @@ def from_legacy_config(cls, legacy_config): short_name=legacy_config.short_name, ) + def to_json(self): + return asdict(self) + @dataclasses.dataclass class EphemeralNodeSettings: @@ -84,6 +92,9 @@ def configured(self): attribute_name='credentials_available' ) + def before_page_load(self, *args, **kwargs): + pass + @property def folder_id(self): return self.gv_data.get_attribute('root_folder') diff --git a/osf_tests/external/gravy_valet/gv_fakes.py b/osf_tests/external/gravy_valet/gv_fakes.py index 3144484fdd1..82630bfc831 100644 --- a/osf_tests/external/gravy_valet/gv_fakes.py +++ b/osf_tests/external/gravy_valet/gv_fakes.py @@ -202,7 +202,7 @@ def _serialize_relationships(self): } -class FakeGravyValet(): +class FakeGravyValet: ROUTES = { r'v1/user-references(/(?P\d+)|(\?filter\[user_uri\]=(?P[^&]+)))': '_get_user', @@ -250,6 +250,9 @@ def _get_or_create_user_entry(self, user: OSFUser): self._known_users[user_pk] = user_uri return user_uri, user_pk + def configure_resource(self, resource: AbstractNode): + return self._get_or_create_resource_entry(resource) + def _get_or_create_resource_entry(self, resource: AbstractNode): resource_uri = resource.get_semantic_iri() resource_pk = self._known_resources.get(resource_uri) diff --git a/website/project/views/node.py b/website/project/views/node.py index c0e30b9630b..6d4d1b2984b 100644 --- a/website/project/views/node.py +++ b/website/project/views/node.py @@ -15,6 +15,7 @@ from framework.utils import iso8601format from framework.flask import redirect # VOL-aware redirect from framework.auth.decorators import must_be_logged_in, collect_auth +from osf.external.gravy_valet.translations import EphemeralAddonConfig from website.ember_osf_web.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 @@ -668,11 +669,12 @@ def _render_addons(addons): for addon in addons: configs[addon.config.short_name] = addon.config.to_json() - js.extend(addon.config.include_js.get('widget', [])) - css.extend(addon.config.include_css.get('widget', [])) + if not isinstance(addon.config, EphemeralAddonConfig): + js.extend(addon.config.include_js.get('widget', [])) + css.extend(addon.config.include_css.get('widget', [])) - js.extend(addon.config.include_js.get('files', [])) - css.extend(addon.config.include_css.get('files', [])) + js.extend(addon.config.include_js.get('files', [])) + css.extend(addon.config.include_css.get('files', [])) return widgets, configs, js, css diff --git a/website/settings/defaults.py b/website/settings/defaults.py index 63535dac1dd..8d951346ffa 100644 --- a/website/settings/defaults.py +++ b/website/settings/defaults.py @@ -319,7 +319,7 @@ def parent_dir(path): DEFAULT_HMAC_ALGORITHM = hashlib.sha256 WATERBUTLER_URL = 'http://localhost:7777' WATERBUTLER_INTERNAL_URL = WATERBUTLER_URL -GRAVYVALET_URL = 'https://localhost:8004' +GRAVYVALET_URL = 'http://192.168.168.167:8004' #################### # Identifiers # diff --git a/website/templates/project/project.mako b/website/templates/project/project.mako index 356fa93a562..f22b1c2a58c 100644 --- a/website/templates/project/project.mako +++ b/website/templates/project/project.mako @@ -616,7 +616,7 @@ % if addons: % for addon in addons_enabled: - % if addons[addon]['has_widget']: + % if addons[addon].get('has_widget'): %if addon != 'wiki': ## We already show the wiki widget at the top ${ render_addon_widget.render_addon_widget(addon, addons_widget_data[addon]) } %endif diff --git a/website/templates/project/project_header.mako b/website/templates/project/project_header.mako index a5a054ba681..b45a9c47a55 100644 --- a/website/templates/project/project_header.mako +++ b/website/templates/project/project_header.mako @@ -48,7 +48,7 @@ % for addon in addons_enabled: - % if addons[addon]['has_page']: + % if addons[addon].get('has_page', False):