Skip to content

Commit 8ff61fc

Browse files
authored
Merge pull request #7981 from Johnetordoff/final-fix-for-addon-asset-loading
[OSF-8056] Fix for addon asset loading
2 parents 7577ffa + c4c8937 commit 8ff61fc

File tree

5 files changed

+97
-12
lines changed

5 files changed

+97
-12
lines changed

addons.json

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,9 @@
1818
"googledrive",
1919
"bitbucket"
2020
],
21+
"addons_default": [
22+
"osfstorage"
23+
],
2124
"addons_archivable": {
2225
"osfstorage": "full",
2326
"box": "partial",

tests/test_addons.py

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
# -*- coding: utf-8 -*-
22

3+
import os
34
import datetime
45
import httplib as http
56
import time
@@ -21,6 +22,7 @@
2122
from osf_tests.factories import (AuthUserFactory, ProjectFactory,
2223
RegistrationFactory)
2324
from website import settings
25+
from website.util.paths import webpack_asset
2426
from addons.base import views
2527
from addons.github.exceptions import ApiError
2628
from addons.github.models import GithubFolder, GithubFile, GithubFileNode
@@ -30,6 +32,7 @@
3032
from osf.models.files import BaseFileNode, TrashedFileNode
3133
from website.project import new_private_link
3234
from website.project.views.node import _view_project as serialize_node
35+
from website.project.views.node import serialize_addons, collect_node_config_js
3336
from website.util import api_url_for, rubeus
3437
from dateutil.parser import parse as parse_date
3538
from framework import sentry
@@ -1099,3 +1102,56 @@ def test_other_addon_redirect_download(self):
10991102
provider='mycooladdon',
11001103
)
11011104
assert_urls_equal(res.location, expected_url)
1105+
1106+
class TestViewUtils(OsfTestCase):
1107+
1108+
def setUp(self):
1109+
super(TestViewUtils, self).setUp()
1110+
self.user = AuthUserFactory()
1111+
self.auth_obj = Auth(user=self.user)
1112+
self.node = ProjectFactory(creator=self.user)
1113+
self.session = Session(data={'auth_user_id': self.user._id})
1114+
self.session.save()
1115+
self.cookie = itsdangerous.Signer(settings.SECRET_KEY).sign(self.session._id)
1116+
self.configure_addon()
1117+
self.JWE_KEY = jwe.kdf(settings.WATERBUTLER_JWE_SECRET.encode('utf-8'), settings.WATERBUTLER_JWE_SALT.encode('utf-8'))
1118+
1119+
def configure_addon(self):
1120+
self.user.add_addon('github')
1121+
self.user_addon = self.user.get_addon('github')
1122+
self.oauth_settings = GitHubAccountFactory(display_name='john')
1123+
self.oauth_settings.save()
1124+
self.user.external_accounts.add(self.oauth_settings)
1125+
self.user.save()
1126+
self.node.add_addon('github', self.auth_obj)
1127+
self.node_addon = self.node.get_addon('github')
1128+
self.node_addon.user = 'john'
1129+
self.node_addon.repo = 'youre-my-best-friend'
1130+
self.node_addon.user_settings = self.user_addon
1131+
self.node_addon.external_account = self.oauth_settings
1132+
self.node_addon.save()
1133+
self.user_addon.oauth_grants[self.node._id] = {self.oauth_settings._id: []}
1134+
self.user_addon.save()
1135+
1136+
def test_serialize_addons(self):
1137+
addon_dicts = serialize_addons(self.node)
1138+
1139+
enabled_addons = [addon for addon in addon_dicts if addon['enabled']]
1140+
assert len(enabled_addons) == 2
1141+
assert enabled_addons[0]['short_name'] == 'github'
1142+
assert enabled_addons[1]['short_name'] == 'osfstorage'
1143+
1144+
default_addons = [addon for addon in addon_dicts if addon['default']]
1145+
assert len(default_addons) == 1
1146+
assert default_addons[0]['short_name'] == 'osfstorage'
1147+
1148+
def test_collect_node_config_js(self):
1149+
1150+
addon_dicts = serialize_addons(self.node)
1151+
1152+
asset_paths = collect_node_config_js(addon_dicts)
1153+
1154+
# Default addons should be in addon dicts, but they have no js assets because you can't
1155+
# connect/disconnect from them, think osfstorage, there's no node-cfg for that.
1156+
default_addons = [addon['short_name'] for addon in addon_dicts if addon['default']]
1157+
assert not any('/{}/'.format(addon) in asset_paths for addon in default_addons)

website/project/views/node.py

Lines changed: 36 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -281,6 +281,24 @@ def node_addons(auth, node, **kwargs):
281281

282282
ret = _view_project(node, auth, primary=True)
283283

284+
addon_settings = serialize_addons(node)
285+
286+
ret['addon_capabilities'] = settings.ADDON_CAPABILITIES
287+
288+
# If an addon is default you cannot connect/disconnect so we don't have to load it.
289+
ret['addon_settings'] = [addon for addon in addon_settings]
290+
291+
# Addons can have multiple categories, but we only want a set of unique ones being used.
292+
ret['addon_categories'] = set([item for addon in addon_settings for item in addon['categories']])
293+
294+
# The page only needs to load enabled addons and it refreshes when a new addon is being enabled.
295+
ret['addon_js'] = collect_node_config_js([addon for addon in addon_settings if addon['enabled']])
296+
297+
return ret
298+
299+
300+
def serialize_addons(node):
301+
284302
addon_settings = []
285303
addons_available = [addon for addon in settings.ADDONS_AVAILABLE
286304
if addon not in settings.SYSTEM_ADDED_ADDONS['node']
@@ -296,18 +314,12 @@ def node_addons(auth, node, **kwargs):
296314
config['addon_full_name'] = addon.full_name
297315
config['categories'] = addon.categories
298316
config['enabled'] = node.has_addon(addon.short_name)
299-
config['default'] = addon.short_name in ['osfstorage']
317+
config['default'] = addon.short_name in settings.ADDONS_DEFAULT
300318
addon_settings.append(config)
301319

302320
addon_settings = sorted(addon_settings, key=lambda addon: addon['full_name'].lower())
303321

304-
ret['addon_capabilities'] = settings.ADDON_CAPABILITIES
305-
ret['addon_categories'] = set([item for addon in addon_settings for item in addon['categories']])
306-
ret['addon_settings'] = addon_settings
307-
ret['addon_js'] = collect_node_config_js([addon for addon in addon_settings if addon['enabled']])
308-
309-
return ret
310-
322+
return addon_settings
311323

312324
def collect_node_config_js(addons):
313325
"""Collect webpack bundles for each of the addons' node-cfg.js modules. Return
@@ -317,9 +329,22 @@ def collect_node_config_js(addons):
317329
"""
318330
js_modules = []
319331
for addon in addons:
320-
js_path = os.path.join('/', 'static', 'public', 'js', addon['short_name'], 'node-cfg.js')
321-
if os.path.exists(js_path):
322-
js_modules.append(js_path)
332+
source_path = os.path.join(
333+
settings.ADDON_PATH,
334+
addon['short_name'],
335+
'static',
336+
'node-cfg.js',
337+
)
338+
if os.path.exists(source_path):
339+
asset_path = os.path.join(
340+
'/',
341+
'static',
342+
'public',
343+
'js',
344+
addon['short_name'],
345+
'node-cfg.js',
346+
)
347+
js_modules.append(asset_path)
323348

324349
return js_modules
325350

website/settings/defaults.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -262,6 +262,7 @@ def parent_dir(path):
262262
ADDONS_BASED_ON_IDS = addon_settings['addons_based_on_ids']
263263
ADDONS_DESCRIPTION = addon_settings['addons_description']
264264
ADDONS_URL = addon_settings['addons_url']
265+
ADDONS_DEFAULT = addon_settings['addons_default']
265266

266267
ADDON_CATEGORIES = [
267268
'documentation',

website/templates/project/addons.mako

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -112,7 +112,7 @@
112112
</div>
113113
</div>
114114
<div style="padding: 10px">
115-
% for addon in [addon for addon in addon_settings if addon['enabled']]:
115+
% for addon in [addon for addon in addon_settings if addon['enabled'] and not addon['default']]:
116116
% if addon.get('node_settings_template'):
117117
${render_node_settings(addon)}
118118
% endif

0 commit comments

Comments
 (0)