Skip to content

Commit 3bdaa6e

Browse files
committed
Merge branch 'release/0.106.0'
2 parents 49ad44f + ae68cc1 commit 3bdaa6e

File tree

518 files changed

+1998
-36196
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

518 files changed

+1998
-36196
lines changed

.docker-compose.wb.env

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,3 +10,5 @@ OSFSTORAGE_PROVIDER_CONFIG_HMAC_SECRET=changeme
1010

1111
SERVER_CONFIG_ADDRESS=0.0.0.0
1212
OSF_AUTH_CONFIG_API_URL=http://192.168.168.167:5000/api/v1/files/auth/
13+
14+
TASKS_CONFIG_BROKER_URL=amqp://guest:[email protected]:5672//

CHANGELOG

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,28 @@
22
Changelog
33
*********
44

5+
0.106.0 (2017-04-21)
6+
====================
7+
8+
- Registrations with 100+ nodes fail with content_length_mismatch error
9+
- [Win 10] DropZone patch for Windows folder uploads (IE / Firefox)
10+
- Submitting to OSF4M using deleted project name does not create new project
11+
- Fangorn edit undefined
12+
- API 502s when refreshing github metadata (was: TypeError: Can't compare datetime.datetime to NoneType)
13+
- API 502s when requesting Github file metadata w/ version=2.2
14+
- Search unhappy with some users
15+
- Registries: "Withdrawn" label not appearing on newly-withdrawn registrations
16+
- Retraction detail pages throw mithril mounting error
17+
- Preprint Provider detail not 404-ing if not found
18+
- Sitemap index datemod -> lastmod
19+
- Cannot change GitHub branches on staging/staging3
20+
- When project marked spam, update EZID DOI status to Unavailable
21+
- Populate Fangorn text input on rename
22+
- Allow UVA dataverse-specific Pop-up in Fangorn upon publishing dataset/verse
23+
- Linked Registrations on Nodes in API
24+
- OSF - Convert all Dropbox v1 API code/clients to v2 API before deadline
25+
- Update dockerfile to support running registries locally
26+
527
0.105.0 (2017-04-02)
628
====================
729

MANIFEST.in

Lines changed: 0 additions & 3 deletions
This file was deleted.

README-docker-compose.md

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,11 @@
2626
- Ubuntu
2727
- Add loopback alias
2828
`sudo ifconfig lo:0 192.168.168.167 netmask 255.255.255.255 up`
29+
2930
- For persistance, add to /etc/network/interfaces...
31+
Add lo:0 to auto line...
32+
```auto lo lo:0```
33+
Add stanza for lo:0...
3034
```iface lo:0 inet static
3135
address 192.168.168.167
3236
netmask 255.255.255.255
@@ -93,6 +97,8 @@
9397
wb:
9498
volumes_from:
9599
- container:wb-sync
100+
101+
...
96102
```
97103

98104
- In `docker-sync.yml`:
@@ -106,6 +112,8 @@
106112
sync_excludes_type: 'Name'
107113
sync_excludes: ['.DS_Store', '*.pyc', '*.tmp', '.git', '.idea']
108114
watch_excludes: ['.*\.DS_Store', '.*\.pyc', '.*\.tmp', '.*/\.git', '.*/\.idea']
115+
116+
...
109117
```
110118

111119
Modifying these files will show up as changes in git. To avoid committing these files, run:
@@ -168,8 +176,8 @@ Ubuntu: Skip install of docker-sync, fswatch, and unison. instead...
168176
- `$ docker-compose up -d mfr wb fakecas sharejs`
169177
5. Run migrations and create preprint providers
170178
- When starting with an empty database you will need to run migrations and populate preprint providers. See the [Running arbitrary commands](#running-arbitrary-commands) section below for instructions.
171-
6. Start the OSF Web, API Server, and Preprints (Detached)
172-
- `$ docker-compose up -d worker web api admin preprints`
179+
6. Start the OSF Web, API Server, Preprints, and Registries (Detached)
180+
- `$ docker-compose up -d worker web api admin preprints registries`
173181
7. View the OSF at [http://localhost:5000](http://localhost:5000).
174182

175183

@@ -180,7 +188,7 @@ Ubuntu: Skip install of docker-sync, fswatch, and unison. instead...
180188
```
181189
$ docker-sync start
182190
# Wait until you see "Nothing to do: replicas have not changed since last sync."
183-
$ docker-compose up -d assets admin_assets mfr wb fakecas sharejs worker web api admin preprints
191+
$ docker-compose up -d assets admin_assets mfr wb fakecas sharejs worker web api admin preprints registries
184192
```
185193

186194
- To view the logs for a given container:

README.md

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -456,12 +456,6 @@ By default, Karma will run tests using a PhantomJS headless browser. You can run
456456
$ inv karma -b Firefox
457457
```
458458

459-
If you want to run cross browser tests with SauceLabs, use "sauce" parameter:
460-
461-
```bash
462-
$ inv karma --sauce
463-
```
464-
465459
#### Testing Addons
466460

467461
Addons tests are not run by default. To execute addons tests, run

addons/base/apps.py

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
from framework.routing import process_rules
99
from framework.flask import app
1010
from website import settings
11+
from website.util import rubeus
1112

1213

1314
def _is_image(filename):
@@ -28,6 +29,26 @@ def _is_image(filename):
2829
)
2930

3031

32+
def generic_root_folder(addon_short_name):
33+
def _root_folder(node_settings, auth, **kwargs):
34+
"""Return the Rubeus/HGrid-formatted response for the root folder only."""
35+
# Quit if node settings does not have authentication
36+
if not node_settings.has_auth or not node_settings.folder_id:
37+
return None
38+
node = node_settings.owner
39+
root = rubeus.build_addon_root(
40+
node_settings=node_settings,
41+
name=node_settings.fetch_folder_name(),
42+
permissions=auth,
43+
nodeUrl=node.url,
44+
nodeApiUrl=node.api_url,
45+
private_key=kwargs.get('view_only', None),
46+
)
47+
return [root]
48+
_root_folder.__name__ = '{0}_root_folder'.format(addon_short_name)
49+
return _root_folder
50+
51+
3152
class BaseAddonAppConfig(AppConfig):
3253
name = 'addons.base'
3354
label = 'addons_base'

addons/base/generic_views.py

Lines changed: 1 addition & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99

1010
from website.oauth.models import ExternalAccount
1111

12-
from website.util import permissions, rubeus
12+
from website.util import permissions
1313
from website.project.decorators import (
1414
must_have_addon, must_be_addon_authorizer,
1515
must_have_permission, must_not_be_registration,
@@ -67,26 +67,6 @@ def _folder_list(node_addon, **kwargs):
6767
_folder_list.__name__ = '{0}_folder_list'.format(addon_short_name)
6868
return _folder_list
6969

70-
def root_folder(addon_short_name):
71-
def _root_folder(node_settings, auth, **kwargs):
72-
"""Return the Rubeus/HGrid-formatted response for the root folder only."""
73-
# Quit if node settings does not have authentication
74-
if not node_settings.has_auth or not node_settings.folder_id:
75-
return None
76-
node = node_settings.owner
77-
root = rubeus.build_addon_root(
78-
node_settings=node_settings,
79-
name=node_settings.fetch_folder_name(),
80-
permissions=auth,
81-
nodeUrl=node.url,
82-
nodeApiUrl=node.api_url,
83-
private_key=kwargs.get('view_only', None),
84-
)
85-
return [root]
86-
_root_folder.__name__ = '{0}_root_folder'.format(addon_short_name)
87-
return _root_folder
88-
89-
9070
def get_config(addon_short_name, Serializer):
9171
@must_be_logged_in
9272
@must_have_addon(addon_short_name, 'node')

addons/base/models.py

Lines changed: 13 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -468,9 +468,9 @@ def before_fork(self, node, user):
468468
if hasattr(self, 'user_settings'):
469469
if self.user_settings is None:
470470
return (
471-
u'Because you have not configured the authorization for this {addon} add-on, this '
472-
u'{category} will not transfer your authentication to '
473-
u'the forked {category}.'
471+
u'Because you have not configured the {addon} add-on, your authentication will not be '
472+
u'transferred to the forked {category}. You may authorize and configure the {addon} add-on '
473+
u'in the new fork on the settings page.'
474474
).format(
475475
addon=self.config.full_name,
476476
category=node.project_or_component,
@@ -489,7 +489,8 @@ def before_fork(self, node, user):
489489
return (
490490
u'Because the {addon} add-on has been authorized by a different '
491491
u'user, forking it will not transfer authentication to the forked '
492-
u'{category}.'
492+
u'{category}. You may authorize and configure the {addon} add-on '
493+
u'in the new fork on the settings page.'
493494
).format(
494495
addon=self.config.full_name,
495496
category=node.project_or_component,
@@ -502,7 +503,7 @@ def after_fork(self, node, fork, user, save=True):
502503
:param Node fork:
503504
:param User user:
504505
:param bool save:
505-
:returns: Tuple of cloned settings and alert message
506+
:returns: cloned settings
506507
507508
"""
508509
clone = self.clone()
@@ -512,7 +513,7 @@ def after_fork(self, node, fork, user, save=True):
512513
if save:
513514
clone.save()
514515

515-
return clone, None
516+
return clone
516517

517518
def before_register(self, node, user):
518519
"""
@@ -653,6 +654,9 @@ def folder_path(self):
653654
"BaseOAuthNodeSettings subclasses must expose a 'folder_path' property."
654655
)
655656

657+
def fetch_folder_name(self):
658+
return self.folder_name
659+
656660
@property
657661
def nodelogger(self):
658662
auth = None
@@ -798,9 +802,9 @@ def after_fork(self, node, fork, user, save=True):
798802
"""After forking, copy user settings if the user is the one who authorized
799803
the addon.
800804
801-
:return: A tuple of the form (cloned_settings, message)
805+
:return: the cloned settings
802806
"""
803-
clone, _ = super(BaseOAuthNodeSettings, self).after_fork(
807+
clone = super(BaseOAuthNodeSettings, self).after_fork(
804808
node=node,
805809
fork=fork,
806810
user=user,
@@ -814,24 +818,11 @@ def after_fork(self, node, fork, user, save=True):
814818
except (KeyError, AttributeError):
815819
pass
816820
clone.set_auth(self.external_account, user, metadata=metadata, log=False)
817-
message = '{addon} authorization copied to forked {category}.'.format(
818-
addon=self.config.full_name,
819-
category=fork.project_or_component,
820-
)
821821
else:
822822
clone.clear_settings()
823-
message = (
824-
u'{addon} authorization not copied to forked {category}. You may '
825-
u'authorize this fork on the <u><a href="{url}">Settings</a></u> '
826-
u'page.'
827-
).format(
828-
addon=self.config.full_name,
829-
url=fork.web_url_for('node_setting'),
830-
category=fork.project_or_component,
831-
)
832823
if save:
833824
clone.save()
834-
return clone, message
825+
return clone
835826

836827
def before_register_message(self, node, user):
837828
"""Return warning text to display if user auth will be copied to a

addons/base/testing/serializers.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -109,7 +109,7 @@ def test_user_is_owner_node_not_authorized_user_has_accounts(self):
109109

110110
def test_user_is_owner_node_authorized_user_is_not_owner(self):
111111
self.node_settings.external_account = self.ExternalAccountFactory()
112-
with mock.patch('website.addons.base.AddonOAuthUserSettingsBase.verify_oauth_access', return_value=True):
112+
with mock.patch('addons.base.models.BaseOAuthUserSettings.verify_oauth_access', return_value=True):
113113
self.user.external_accounts = []
114114
assert_false(self.ser.user_is_owner)
115115

addons/base/tests/models.py

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -421,25 +421,20 @@ def test_create_log(self):
421421

422422
def test_after_fork_by_authorized_user(self):
423423
fork = ProjectFactory()
424-
clone, message = self.node_settings.after_fork(
424+
clone = self.node_settings.after_fork(
425425
node=self.node, fork=fork, user=self.user_settings.owner
426426
)
427427
assert_equal(clone.user_settings, self.user_settings)
428428

429429
def test_after_fork_by_unauthorized_user(self):
430430
fork = ProjectFactory()
431431
user = UserFactory()
432-
clone, message = self.node_settings.after_fork(
432+
clone = self.node_settings.after_fork(
433433
node=self.node, fork=fork, user=user,
434434
save=True
435435
)
436436
assert_is(clone.user_settings, None)
437437

438-
def test_before_fork(self):
439-
node = ProjectFactory()
440-
message = self.node_settings.before_fork(node, self.user)
441-
assert_true(message)
442-
443438
def test_before_remove_contributor_message(self):
444439
message = self.node_settings.before_remove_contributor(
445440
self.node, self.user)

addons/base/views.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -289,6 +289,7 @@ def get_auth(auth, **kwargs):
289289
'callback_url': node.api_url_for(
290290
('create_waterbutler_log' if not node.is_registration else 'registration_callbacks'),
291291
_absolute=True,
292+
_internal=True
292293
),
293294
}
294295
}, settings.WATERBUTLER_JWT_SECRET, algorithm=settings.WATERBUTLER_JWT_ALGORITHM), WATERBUTLER_JWE_KEY)}

addons/box/apps.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
1-
from addons.base.apps import BaseAddonAppConfig
1+
from addons.base.apps import BaseAddonAppConfig, generic_root_folder
22

3-
from addons.box.views import box_root_folder
3+
box_root_folder = generic_root_folder('box')
44

55
class BoxAddonAppConfig(BaseAddonAppConfig):
66

addons/box/models.py

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -114,9 +114,6 @@ def api(self):
114114
def display_name(self):
115115
return '{0}: {1}'.format(self.config.full_name, self.folder_id)
116116

117-
def fetch_folder_name(self):
118-
return self.folder_name
119-
120117
def fetch_full_folder_path(self):
121118
return self.folder_path
122119

addons/box/tests/utils.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -185,7 +185,7 @@ def patch_client(target, mock_client=None):
185185
186186
Usage: ::
187187
188-
with patch_client('website.addons.box.views.BoxClient') as client:
188+
with patch_client('addons.box.views.BoxClient') as client:
189189
# test view that uses the box client.
190190
"""
191191
with mock.patch(target) as client_getter:

addons/box/views.py

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,3 @@ def _set_folder(node_addon, folder, auth):
4848
box_deauthorize_node = generic_views.deauthorize_node(
4949
SHORT_NAME
5050
)
51-
52-
box_root_folder = generic_views.root_folder(
53-
SHORT_NAME
54-
)

addons/dataverse/client.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
from framework.exceptions import HTTPError
77

88
from addons.dataverse import settings
9+
from website.util.sanitize import strip_html
910

1011
def _connect(host, token):
1112
try:
@@ -112,3 +113,9 @@ def get_dataverse(connection, alias):
112113
if connection is None:
113114
return
114115
return connection.get_dataverse(alias)
116+
117+
118+
def get_custom_publish_text(connection):
119+
if connection is None:
120+
return ''
121+
return strip_html(connection.get_custom_publish_text(), tags=['strong', 'li', 'ul'])

addons/dataverse/static/dataverseFangornConfig.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,8 @@ var _dataverseItemButtons = {
3737
var toPublish = both ? 'Dataverse and dataset' : 'dataset';
3838
// Set the modal content to reflect the file's external host
3939
var modalContent = [
40+
// for now, only display custom publish text for UVA's dataverse
41+
m('p.m-md', item.data.host == 'dataverse.lib.virginia.edu' ? m.trust(item.data.hostCustomPublishText) : ''),
4042
m('p.m-md', both ? 'This dataset cannot be published until the ' + item.data.dataverse + ' Dataverse is published. ' : ''),
4143
m('p.m-md', 'By publishing this ' + toPublish + ', all content will be made available through ' + host + ' using their internal privacy settings, regardless of your OSF project settings. '),
4244
m('p.font-thick.m-md', both ? 'Do you want to publish this Dataverse AND this dataset?' : 'Are you sure you want to publish this dataset?')

addons/dataverse/tests/test_views.py

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -149,11 +149,13 @@ def test_set_config_no_dataset(self, mock_connection):
149149

150150
class TestHgridViews(DataverseAddonTestCase, OsfTestCase, unittest.TestCase):
151151

152+
@mock.patch('addons.dataverse.views.client.get_custom_publish_text')
152153
@mock.patch('addons.dataverse.views.client.connect_from_settings')
153154
@mock.patch('addons.dataverse.views.client.get_files')
154-
def test_dataverse_root_published(self, mock_files, mock_connection):
155+
def test_dataverse_root_published(self, mock_files, mock_connection, mock_text):
155156
mock_connection.return_value = create_mock_connection()
156157
mock_files.return_value = ['mock_file']
158+
mock_text.return_value = 'Do you want to publish?'
157159

158160
self.project.set_privacy('public')
159161
self.project.save()
@@ -184,11 +186,13 @@ def test_dataverse_root_published(self, mock_files, mock_connection):
184186
assert_true(res.json[0]['hasPublishedFiles'])
185187
assert_equal(res.json[0]['version'], 'latest-published')
186188

189+
@mock.patch('addons.dataverse.views.client.get_custom_publish_text')
187190
@mock.patch('addons.dataverse.views.client.connect_from_settings')
188191
@mock.patch('addons.dataverse.views.client.get_files')
189-
def test_dataverse_root_not_published(self, mock_files, mock_connection):
192+
def test_dataverse_root_not_published(self, mock_files, mock_connection, mock_text):
190193
mock_connection.return_value = create_mock_connection()
191194
mock_files.return_value = []
195+
mock_text.return_value = 'Do you want to publish?'
192196

193197
self.project.set_privacy('public')
194198
self.project.save()

0 commit comments

Comments
 (0)