Public Activity

-
+

New and noteworthy projects

${node_list(new_and_noteworthy_projects, prefix='newest_public', metric='date_created')} From 93e33d6ddb9c7716ba8323292001d82aac9a49fe Mon Sep 17 00:00:00 2001 From: Casey Rollins Date: Tue, 30 May 2017 15:24:49 -0400 Subject: [PATCH 036/163] Add test for adding unconfirmed users as contributors. --- .../views/test_node_contributors_list.py | 26 ++++++++++++++++++- 1 file changed, 25 insertions(+), 1 deletion(-) diff --git a/api_tests/nodes/views/test_node_contributors_list.py b/api_tests/nodes/views/test_node_contributors_list.py index a6368ba3fa7..8fa5dcc9d53 100644 --- a/api_tests/nodes/views/test_node_contributors_list.py +++ b/api_tests/nodes/views/test_node_contributors_list.py @@ -19,7 +19,8 @@ from osf_tests.factories import ( ProjectFactory, AuthUserFactory, - UserFactory + UserFactory, + UnconfirmedUserFactory ) from tests.utils import assert_logs @@ -1089,6 +1090,29 @@ def test_add_inactive_merged_user_as_contributor(self): contributor_added = res.json['data']['embeds']['users']['data']['id'] assert_equal(contributor_added, primary_user._id) + def test_add_unconfirmed_user_by_guid(self): + unconfirmed_user = UnconfirmedUserFactory() + payload = { + 'data': { + 'type':'contributors', + 'attributes': {}, + 'relationships': { + 'users': { + 'data': { + 'type': 'users', + 'id': unconfirmed_user._id + } + } + } + } + } + res = self.app.post_json_api(self.public_url, payload, auth=self.user.auth, expect_errors=True) + assert_equal(res.status_code, 404) + assert_equal( + res.json['errors'][0]['detail'], + 'Cannot add unconfirmed user {} to node {}'.format(unconfirmed_user._id, self.public_project._id) + ) + class TestNodeContributorCreateValidation(NodeCRUDTestCase): From 372621ce78a017dd0738da8a4ddbfa5e0f7c1306 Mon Sep 17 00:00:00 2001 From: Alex Schiller Date: Thu, 1 Jun 2017 10:43:10 -0400 Subject: [PATCH 037/163] Fix merge conflict; flake --- admin/preprints/serializers.py | 1 - admin_tests/nodes/test_views.py | 49 +++++++++++++---------------- admin_tests/preprints/test_views.py | 2 +- admin_tests/users/test_views.py | 1 - 4 files changed, 23 insertions(+), 30 deletions(-) diff --git a/admin/preprints/serializers.py b/admin/preprints/serializers.py index 4004dfc1bde..bfde3db9835 100644 --- a/admin/preprints/serializers.py +++ b/admin/preprints/serializers.py @@ -1,4 +1,3 @@ -from website.project.taxonomies import Subject from admin.nodes.serializers import serialize_node diff --git a/admin_tests/nodes/test_views.py b/admin_tests/nodes/test_views.py index 47e34b2b0aa..9118d7211d2 100644 --- a/admin_tests/nodes/test_views.py +++ b/admin_tests/nodes/test_views.py @@ -10,8 +10,6 @@ ) from admin_tests.utilities import setup_log_view, setup_view -from framework.auth import User - from nose import tools as nt from django.test import RequestFactory from django.core.urlresolvers import reverse @@ -22,8 +20,6 @@ from osf_tests.factories import AuthUserFactory, ProjectFactory, RegistrationFactory - - class TestNodeView(AdminTestCase): def test_no_guid(self): @@ -202,7 +198,28 @@ def test_no_log(self): view.delete(self.request) nt.assert_not_equal(self.node.logs.latest().action, NodeLog.CONTRIB_REMOVED) -<<<<<<< HEAD + def test_no_user_permissions_raises_error(self): + guid = self.node._id + request = RequestFactory().get(self.url) + request.user = self.user + + with nt.assert_raises(PermissionDenied): + self.view.as_view()(request, node_id=guid, user_id=self.user) + + def test_correct_view_permissions(self): + change_permission = Permission.objects.get(codename='change_node') + view_permission = Permission.objects.get(codename='view_node') + self.user.user_permissions.add(change_permission) + self.user.user_permissions.add(view_permission) + self.user.save() + + request = RequestFactory().get(self.url) + request.user = self.user + + response = self.view.as_view()(request, node_id=self.node._id, user_id=self.user._id) + nt.assert_equal(response.status_code, 200) + + class TestNodeReindex(AdminTestCase): def setUp(self): super(TestNodeReindex, self).setUp() @@ -268,25 +285,3 @@ def test_reindex_registration_elastic(self): nt.assert_true(self.mock_reindex_elastic.called) nt.assert_equal(AdminLogEntry.objects.count(), count + 1) -======= - def test_no_user_permissions_raises_error(self): - guid = self.node._id - request = RequestFactory().get(self.url) - request.user = self.user - - with nt.assert_raises(PermissionDenied): - self.view.as_view()(request, node_id=guid, user_id=self.user) - - def test_correct_view_permissions(self): - change_permission = Permission.objects.get(codename='change_node') - view_permission = Permission.objects.get(codename='view_node') - self.user.user_permissions.add(change_permission) - self.user.user_permissions.add(view_permission) - self.user.save() - - request = RequestFactory().get(self.url) - request.user = self.user - - response = self.view.as_view()(request, node_id=self.node._id, user_id=self.user._id) - nt.assert_equal(response.status_code, 200) ->>>>>>> b7b2315b6887f23b5d94ce9814fd4965cd66cfb0 diff --git a/admin_tests/preprints/test_views.py b/admin_tests/preprints/test_views.py index 81008c106e6..7c985cb5ec0 100644 --- a/admin_tests/preprints/test_views.py +++ b/admin_tests/preprints/test_views.py @@ -10,7 +10,7 @@ from osf_tests.factories import AuthUserFactory, PreprintFactory, PreprintProviderFactory from osf.models.admin_log_entry import AdminLogEntry -from admin_tests.utilities import setup_view +from admin_tests.utilities import setup_view, setup_log_view from admin.preprints import views from admin.preprints.forms import ChangeProviderForm diff --git a/admin_tests/users/test_views.py b/admin_tests/users/test_views.py index 58fca694b4e..f6e1c2b8f48 100644 --- a/admin_tests/users/test_views.py +++ b/admin_tests/users/test_views.py @@ -719,4 +719,3 @@ def test_reindex_user_elastic(self, mock_reindex_elastic): nt.assert_true(mock_reindex_elastic.called) nt.assert_equal(AdminLogEntry.objects.count(), count + 1) - From 90a4a4d5ea027b0c66c73362b322f45e5551c5f7 Mon Sep 17 00:00:00 2001 From: Fabrice Mizero Date: Thu, 1 Jun 2017 12:20:10 -0400 Subject: [PATCH 038/163] Add error message on submit untouched recaptcha --- website/static/js/passwordForms.js | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/website/static/js/passwordForms.js b/website/static/js/passwordForms.js index b260c174089..934d5db27db 100644 --- a/website/static/js/passwordForms.js +++ b/website/static/js/passwordForms.js @@ -295,6 +295,11 @@ var SignUpViewModel = oop.extend(BaseViewModel, { if ($('.g-recaptcha').length !== 0) { var captchaResponse = $('#g-recaptcha-response').val(); if (captchaResponse.length === 0) { + $osf.growl('Error','Please complete reCAPTCHA.'); + // self.changeMessage( + // 'Please complete reCAPTCHA', + // 'text-danger p-xs' + // ); return false; } $.extend(payload, {'g-recaptcha-response': captchaResponse}); From 56ece003530bbee0f35d8b6de9dc75fe2db72eda Mon Sep 17 00:00:00 2001 From: Casey Rollins Date: Thu, 1 Jun 2017 12:14:59 -0400 Subject: [PATCH 039/163] Find user by username or email in emails list. - Allows unregistered contributors to be found by email. - Display username in user view template. --- admin/templates/users/user.html | 6 +++++- admin/users/views.py | 3 ++- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/admin/templates/users/user.html b/admin/templates/users/user.html index 53a392f0500..40528e494e6 100644 --- a/admin/templates/users/user.html +++ b/admin/templates/users/user.html @@ -137,7 +137,11 @@

User details

- Email + Username + {{ user.username }} + + + Emails {% for email in user.emails %}
  • diff --git a/admin/users/views.py b/admin/users/views.py index 0d2dde44752..0cee964692e 100644 --- a/admin/users/views.py +++ b/admin/users/views.py @@ -4,6 +4,7 @@ import pytz from furl import furl from datetime import datetime, timedelta +from django.db.models import Q from django.views.defaults import page_not_found from django.views.generic import FormView, DeleteView, ListView, TemplateView from django.contrib.auth.mixins import PermissionRequiredMixin @@ -278,7 +279,7 @@ def form_valid(self, form): if guid or email: if email: try: - user = OSFUser.objects.get(emails__contains=[email]) + user = OSFUser.objects.filter(Q(username=email) | Q(emails__contains=[email])).get() guid = user.guids.first()._id except OSFUser.DoesNotExist: return page_not_found(self.request, AttributeError('User with email address {} not found.'.format(email))) From f00b5ee85a89a8c333dd3ba94bad597e960654ce Mon Sep 17 00:00:00 2001 From: Jerry Sun Date: Thu, 1 Jun 2017 16:33:44 -0400 Subject: [PATCH 040/163] Fix some styling issue --- .../files/serializers/test_file_serializer.py | 26 ++------- api_tests/files/views/test_file_detail.py | 32 +++++------ api_tests/files/views/test_file_list.py | 55 +++++++++---------- 3 files changed, 49 insertions(+), 64 deletions(-) diff --git a/api_tests/files/serializers/test_file_serializer.py b/api_tests/files/serializers/test_file_serializer.py index 7ce7537a467..a30aaeb7700 100644 --- a/api_tests/files/serializers/test_file_serializer.py +++ b/api_tests/files/serializers/test_file_serializer.py @@ -24,27 +24,13 @@ def node(self, user): def file(self, node, user): return utils.create_test_file(node, user) - @pytest.fixture() - def date_created(self, file): - return file.versions.first().date_created - - @pytest.fixture() - def date_modified(self, file): - return file.versions.last().date_created - - @pytest.fixture() - def date_created_tz_aware(self, date_created): - return date_created.replace(tzinfo=utc) - - @pytest.fixture() - def date_modified_tz_aware(self, date_modified): - return date_modified.replace(tzinfo=utc) - - @pytest.fixture() - def new_format(self): - return '%Y-%m-%dT%H:%M:%S.%fZ' + def test_file_serializer(self, file): + date_created = file.versions.first().date_created + date_modified = file.versions.last().date_created + date_created_tz_aware = date_created.replace(tzinfo=utc) + date_modified_tz_aware = date_modified.replace(tzinfo=utc) + new_format = '%Y-%m-%dT%H:%M:%S.%fZ' - def test_file_serializer(self, file, date_modified_tz_aware, date_modified, date_created, date_created_tz_aware, new_format): # test_date_modified_formats_to_old_format req = make_drf_request_with_version(version='2.0') data = FileSerializer(file, context={'request': req}).data['data'] diff --git a/api_tests/files/views/test_file_detail.py b/api_tests/files/views/test_file_detail.py index ed5cb642945..17d5e58f39e 100644 --- a/api_tests/files/views/test_file_detail.py +++ b/api_tests/files/views/test_file_detail.py @@ -51,8 +51,8 @@ def test_must_have_auth_and_be_contributor(self, app, file_url): assert res.status_code == 401 # test_must_be_contributor(self, app, file_url): - user = AuthUserFactory() - res = app.get(file_url, auth=user.auth, expect_errors=True) + non_contributor = AuthUserFactory() + res = app.get(file_url, auth=non_contributor.auth, expect_errors=True) assert res.status_code == 403 def test_file_guid_guid_status(self, app, user, file, file_url): @@ -191,9 +191,9 @@ def test_checkout(self, app, user, file, file_url, node): file_url, auth=user.auth ) - assert node.logs.count(),2 - assert node.logs.latest().action, NodeLog.CHECKED_OUT - assert node.logs.latest().user, user + assert node.logs.count() == 2 + assert node.logs.latest().action == NodeLog.CHECKED_OUT + assert node.logs.latest().user == user assert user._id == res.json['data']['relationships']['checkout']['links']['related']['meta']['id'] assert '/{}users/{}/'.format(API_BASE, user._id) in res.json['data']['relationships']['checkout']['links']['related']['href'] @@ -540,27 +540,27 @@ def node(self, user): return ProjectFactory(creator=user) @pytest.fixture() - def file1(self, user, node): + def file_one(self, user, node): return api_utils.create_test_file( - node, user, filename='file1') + node, user, filename='file_one') @pytest.fixture() - def payload(self, file1): + def payload(self, file_one): payload = { - "data": { - "type": "files", - "id": file1._id, - "attributes": { - "checkout": None, - "tags": ["goofy"] + 'data': { + 'type': 'files', + 'id': file_one._id, + 'attributes': { + 'checkout': None, + 'tags': ['goofy'] } } } return payload @pytest.fixture() - def url(self, file1): - return '/{}files/{}/'.format(API_BASE, file1._id) + def url(self, file_one): + return '/{}files/{}/'.format(API_BASE, file_one._id) def test_tags_add_and_update_properly(self, app, user, url, payload): # test_tags_add_properly diff --git a/api_tests/files/views/test_file_list.py b/api_tests/files/views/test_file_list.py index 5275546f87e..4e15558d2c0 100644 --- a/api_tests/files/views/test_file_list.py +++ b/api_tests/files/views/test_file_list.py @@ -1,7 +1,6 @@ -from framework.auth.core import Auth - import pytest +from framework.auth.core import Auth from api.base.settings.defaults import API_BASE from api_tests import utils as api_utils from tests.base import ApiTestCase @@ -25,12 +24,12 @@ def node(self, user): @pytest.fixture() def file(self, user, node): return api_utils.create_test_file( - node, user, filename='file1') + node, user, filename='file_one') @pytest.fixture() def deleted_file(self, user, node): deleted_file = api_utils.create_test_file( - node, user, filename='file2') + node, user, filename='file_two') deleted_file.delete(user=user, save=True) return deleted_file @@ -50,26 +49,26 @@ def node(self, user): return ProjectFactory(creator=user) @pytest.fixture() - def file1(self, user, node): + def file_one(self, user, node): return api_utils.create_test_file( - node, user, filename='file1') + node, user, filename='file_one') @pytest.fixture() - def file2(self, user, node): + def file_two(self, user, node): return api_utils.create_test_file( - node, user, filename='file2') + node, user, filename='file_two') @pytest.fixture() - def file3(self, user, node): + def file_three(self, user, node): return api_utils.create_test_file( - node, user, filename='file3') + node, user, filename='file_three') @pytest.fixture() - def file4(self, user, node): + def file_four(self, user, node): return api_utils.create_test_file( - node, user, filename='file4') + node, user, filename='file_four') - def test_get_all_files(self, app, user, node, file1, file2, file3, file4): + def test_get_all_files(self, app, user, node, file_one, file_two, file_three, file_four): res = app.get( '/{}nodes/{}/files/osfstorage/'.format(API_BASE, node._id), auth=user.auth @@ -77,10 +76,10 @@ def test_get_all_files(self, app, user, node, file1, file2, file3, file4): data = res.json.get('data') assert len(data) == 4 - def test_filter_on_single_tag(self, app, user, node, file1, file2, file3, file4): - file1.add_tag('new', Auth(user)) - file2.add_tag('new', Auth(user)) - file3.add_tag('news', Auth(user)) + def test_filter_on_single_tag(self, app, user, node, file_one, file_two, file_three, file_four): + file_one.add_tag('new', Auth(user)) + file_two.add_tag('new', Auth(user)) + file_three.add_tag('news', Auth(user)) # test_filter_on_tag res = app.get( @@ -92,8 +91,8 @@ def test_filter_on_single_tag(self, app, user, node, file1, file2, file3, file4) data = res.json.get('data') assert len(data) == 2 names = [f['attributes']['name'] for f in data] - assert 'file1' in names - assert 'file2' in names + assert 'file_one' in names + assert 'file_two' in names # test_filtering_tags_exact res = app.get( @@ -114,7 +113,7 @@ def test_filter_on_single_tag(self, app, user, node, file1, file2, file3, file4) assert len(res.json.get('data')) == 1 # test_filtering_tags_capitalized_tag - file4.add_tag('CAT', Auth(user)) + file_four.add_tag('CAT', Auth(user)) res = app.get( '/{}nodes/{}/files/osfstorage/?filter[tags]=cat'.format( API_BASE, node._id @@ -123,9 +122,9 @@ def test_filter_on_single_tag(self, app, user, node, file1, file2, file3, file4) ) assert len(res.json.get('data')) == 1 - def test_filtering_on_multiple_tags(self, app, user, node, file1, file2, file3, file4): + def test_filtering_on_multiple_tags(self, app, user, node, file_one, file_two, file_three, file_four): # test_filtering_on_multiple_tags_one_match - file1.add_tag('cat', Auth(user)) + file_one.add_tag('cat', Auth(user)) res = app.get( '/{}nodes/{}/files/osfstorage/?filter[tags]=cat&filter[tags]=sand'.format( @@ -136,7 +135,7 @@ def test_filtering_on_multiple_tags(self, app, user, node, file1, file2, file3, assert len(res.json.get('data')) == 0 # test_filtering_on_multiple_tags_both_match - file1.add_tag('sand', Auth(user)) + file_one.add_tag('sand', Auth(user)) res = app.get( '/{}nodes/{}/files/osfstorage/?filter[tags]=cat&filter[tags]=sand'.format( API_BASE, node._id @@ -145,12 +144,12 @@ def test_filtering_on_multiple_tags(self, app, user, node, file1, file2, file3, ) assert len(res.json.get('data')) == 1 - def test_filtering_by_tags_returns_distinct(self, app, user, node, file1, file2, file3, file4): + def test_filtering_by_tags_returns_distinct(self, app, user, node, file_one, file_two, file_three, file_four): # regression test for returning multiple of the same file - file1.add_tag('cat', Auth(user)) - file1.add_tag('cAt', Auth(user)) - file1.add_tag('caT', Auth(user)) - file1.add_tag('CAT', Auth(user)) + file_one.add_tag('cat', Auth(user)) + file_one.add_tag('cAt', Auth(user)) + file_one.add_tag('caT', Auth(user)) + file_one.add_tag('CAT', Auth(user)) res = app.get( '/{}nodes/{}/files/osfstorage/?filter[tags]=cat'.format( API_BASE, node._id From 636a11b683aacc1b400718c855d4f585c0f3ab8d Mon Sep 17 00:00:00 2001 From: Fabrice Mizero Date: Mon, 5 Jun 2017 07:06:46 -0400 Subject: [PATCH 041/163] Group mithril mounts in same block, remove obsolete isretract checks --- .../static/js/pages/project-dashboard-page.js | 31 ++++++++----------- 1 file changed, 13 insertions(+), 18 deletions(-) diff --git a/website/static/js/pages/project-dashboard-page.js b/website/static/js/pages/project-dashboard-page.js index 3dae288a37b..b429205ba20 100644 --- a/website/static/js/pages/project-dashboard-page.js +++ b/website/static/js/pages/project-dashboard-page.js @@ -121,16 +121,15 @@ $(document).ready(function () { contributors: window.contextVars.node.contributors, currentUserCanEdit: window.contextVars.currentUser.canEdit }); - var newComponentElem = document.getElementById('newComponent'); - m.startComputation(); + if (!ctx.node.isRetracted) { + m.startComputation(); - if (ctx.node.institutions.length && !ctx.node.anonymous && !ctx.node.isRetracted) { - m.mount(document.getElementById('instLogo'), m.component(institutionLogos, {institutions: window.contextVars.node.institutions})); - } - $('#contributorsList').osfToggleHeight(); + if (ctx.node.institutions.length && !ctx.node.anonymous) { + m.mount(document.getElementById('instLogo'), m.component(institutionLogos, {institutions: window.contextVars.node.institutions})); + } + $('#contributorsList').osfToggleHeight(); - if (!ctx.node.isRetracted) { // Recent Activity widget m.mount(document.getElementById('logFeed'), m.component(LogFeed.LogFeed, {node: node})); @@ -200,16 +199,18 @@ $(document).ready(function () { } }; var filebrowser = new Fangorn(fangornOpts); + var newComponentElem = document.getElementById('newComponent'); + if (window.contextVars.node.isPublic) { + m.mount(document.getElementById('shareButtonsPopover'), + m.component(SocialShare.ShareButtonsPopover, + {title: window.contextVars.node.title, url: window.location.href})); + } if (newComponentElem) { m.mount(newComponentElem, AddComponentButton); }; m.endComputation(); }); - } else { - if (newComponentElem) { - m.mount(newComponentElem, AddComponentButton); - }; - m.endComputation(); + } // Tooltips @@ -296,10 +297,4 @@ $(document).ready(function () { $(elm).text($(elm).text().replace(/\s*$/, '')); }); } - - if (window.contextVars.node.isPublic && !window.contextVars.node.isRetracted) { - m.mount(document.getElementById('shareButtonsPopover'), - m.component(SocialShare.ShareButtonsPopover, - {title: window.contextVars.node.title, url: window.location.href})); - } }); From fbb0b36df64cbcccefc89af4cfecd3e69708cce2 Mon Sep 17 00:00:00 2001 From: Rheisen Dennis Date: Mon, 5 Jun 2017 09:50:13 -0400 Subject: [PATCH 042/163] pytest conversion of ~12 api_tests/nodes files - assert_latest_log added to tests/utils.py --- .../nodes/serializers/test_serializers.py | 26 +- api_tests/nodes/views/test_node_citations.py | 90 +- api_tests/nodes/views/test_node_embeds.py | 110 +- api_tests/nodes/views/test_node_exceptions.py | 73 +- .../views/test_node_institutions_list.py | 44 +- .../nodes/views/test_node_links_detail.py | 247 ++-- api_tests/nodes/views/test_node_links_list.py | 1088 +++++++++-------- api_tests/nodes/views/test_node_logs.py | 196 +-- .../views/test_node_registrations_list.py | 54 +- .../nodes/views/test_node_sparse_fieldsets.py | 258 ++-- .../views/test_node_view_only_links_detail.py | 166 ++- .../views/test_node_view_only_links_list.py | 141 ++- .../views/test_view_only_query_parameter.py | 291 +++-- tests/utils.py | 15 +- 14 files changed, 1559 insertions(+), 1240 deletions(-) diff --git a/api_tests/nodes/serializers/test_serializers.py b/api_tests/nodes/serializers/test_serializers.py index 7e7f5089171..5e558feccb2 100644 --- a/api_tests/nodes/serializers/test_serializers.py +++ b/api_tests/nodes/serializers/test_serializers.py @@ -1,5 +1,4 @@ import pytest - from urlparse import urlparse from dateutil.parser import parse as parse_date @@ -11,16 +10,18 @@ from api.registrations.serializers import RegistrationSerializer from api.base.settings.defaults import API_BASE +@pytest.fixture() +def user(): + return UserFactory() + @pytest.mark.django_db class TestNodeSerializer: - @pytest.fixture(autouse=True) - def setUp(self): - self.user = UserFactory() + def test_node_serializer(self, user): - def test_node_serialization(self): - parent = ProjectFactory(creator=self.user) - node = NodeFactory(creator=self.user, parent=parent) + # test_node_serialization + parent = ProjectFactory(creator=user) + node = NodeFactory(creator=user, parent=parent) req = make_drf_request_with_version(version='2.0') result = NodeSerializer(node, context={'request': req}).data data = result['data'] @@ -54,8 +55,8 @@ def test_node_serialization(self): # Not a fork, so forked_from is removed entirely assert 'forked_from' not in relationships - def test_fork_serialization(self): - node = NodeFactory(creator=self.user) + # test_fork_serialization + node = NodeFactory(creator=user) fork = node.fork_node(auth=Auth(user=node.creator)) req = make_drf_request_with_version(version='2.0') result = NodeSerializer(fork, context={'request': req}).data @@ -68,8 +69,8 @@ def test_fork_serialization(self): urlparse(forked_from).path == '/{}nodes/{}/'.format(API_BASE, node._id)) - def test_template_serialization(self): - node = NodeFactory(creator=self.user) + # test_template_serialization + node = NodeFactory(creator=user) fork = node.use_as_template(auth=Auth(user=node.creator)) req = make_drf_request_with_version(version='2.0') result = NodeSerializer(fork, context={'request': req}).data @@ -82,7 +83,8 @@ def test_template_serialization(self): urlparse(templated_from).path == '/{}nodes/{}/'.format(API_BASE, node._id)) -class TestNodeRegistrationSerializer(DbTestCase): +@pytest.mark.django_db +class TestNodeRegistrationSerializer: def test_serialization(self): user = UserFactory() diff --git a/api_tests/nodes/views/test_node_citations.py b/api_tests/nodes/views/test_node_citations.py index 38635ac8ecd..8c120f4950d 100644 --- a/api_tests/nodes/views/test_node_citations.py +++ b/api_tests/nodes/views/test_node_citations.py @@ -2,80 +2,94 @@ from framework.auth.core import Auth from api.base.settings.defaults import API_BASE -from tests.json_api_test_app import JSONAPITestApp from tests.base import ApiTestCase from tests.factories import ( ProjectFactory, AuthUserFactory, ) -@pytest.mark.django_db -class NodeCitationsMixin: +@pytest.fixture() +def admin_contributor(): + return AuthUserFactory() + +@pytest.fixture() +def rw_contributor(): + return AuthUserFactory() + +@pytest.fixture() +def read_contributor(): + return AuthUserFactory() - def setUp(self): - self.app = JSONAPITestApp() - self.admin_contributor = AuthUserFactory() - self.rw_contributor = AuthUserFactory() - self.read_contributor = AuthUserFactory() - self.non_contributor = AuthUserFactory() +@pytest.fixture() +def non_contributor(): + return AuthUserFactory() - self.public_project = ProjectFactory(creator=self.admin_contributor, is_public=True) +@pytest.fixture() +def public_project(admin_contributor): + return ProjectFactory(creator=admin_contributor, is_public=True) - self.private_project = ProjectFactory(creator=self.admin_contributor) - self.private_project.add_contributor(self.rw_contributor, auth=Auth(self.admin_contributor)) - self.private_project.add_contributor(self.read_contributor, permissions=['read'], auth=Auth(self.admin_contributor)) - self.private_project.save() +@pytest.fixture() +def private_project(admin_contributor, rw_contributor, read_contributor): + private_project = ProjectFactory(creator=admin_contributor) + private_project.add_contributor(rw_contributor, auth=Auth(admin_contributor)) + private_project.add_contributor(read_contributor, permissions=['read'], auth=Auth(admin_contributor)) + private_project.save() + return private_project - def test_node_citations(self): +@pytest.mark.django_db +class NodeCitationsMixin: - # test_admin_can_view_private_project_citations - res = self.app.get(self.private_url, auth=self.admin_contributor.auth) + def test_node_citations(self, app, admin_contributor, rw_contributor, read_contributor, non_contributor, private_url, public_url): + + # test_admin_can_view_private_project_citations + res = app.get(private_url, auth=admin_contributor.auth) assert res.status_code == 200 - # test_rw_contributor_can_view_private_project_citations - res = self.app.get(self.private_url, auth=self.rw_contributor.auth) + # test_rw_contributor_can_view_private_project_citations + res = app.get(private_url, auth=rw_contributor.auth) assert res.status_code == 200 - # test_read_contributor_can_view_private_project_citations - res = self.app.get(self.private_url, auth=self.read_contributor.auth) + # test_read_contributor_can_view_private_project_citations + res = app.get(private_url, auth=read_contributor.auth) assert res.status_code == 200 # test_non_contributor_cannot_view_private_project_citations - res = self.app.get(self.private_url, auth=self.non_contributor.auth, expect_errors=True) + res = app.get(private_url, auth=non_contributor.auth, expect_errors=True) assert res.status_code == 403 assert res.json['errors'][0]['detail'] == 'You do not have permission to perform this action.' # test_unauthenticated_cannot_view_private_project_citations - res = self.app.get(self.private_url, expect_errors=True) + res = app.get(private_url, expect_errors=True) assert res.status_code == 401 assert res.json['errors'][0]['detail'] == 'Authentication credentials were not provided.' # test_unauthenticated_can_view_public_project_citations - res = self.app.get(self.public_url) + res = app.get(public_url) assert res.status_code == 200 # test_citations_are_read_only - post_res = self.app.post_json_api(self.public_url, {}, auth=self.admin_contributor.auth, expect_errors=True) + post_res = app.post_json_api(public_url, {}, auth=admin_contributor.auth, expect_errors=True) assert post_res.status_code == 405 - put_res = self.app.put_json_api(self.public_url, {}, auth=self.admin_contributor.auth, expect_errors=True) + put_res = app.put_json_api(public_url, {}, auth=admin_contributor.auth, expect_errors=True) assert put_res.status_code == 405 - delete_res = self.app.delete_json_api(self.public_url, auth=self.admin_contributor.auth, expect_errors=True) + delete_res = app.delete_json_api(public_url, auth=admin_contributor.auth, expect_errors=True) assert delete_res.status_code == 405 - class TestNodeCitations(NodeCitationsMixin): + @pytest.fixture() + def public_url(self, public_project): + return '/{}nodes/{}/citation/'.format(API_BASE, public_project._id) - @pytest.fixture(autouse=True) - def setUp(self): - super(TestNodeCitations, self).setUp() - self.public_url = '/{}nodes/{}/citation/'.format(API_BASE, self.public_project._id) - self.private_url = '/{}nodes/{}/citation/'.format(API_BASE, self.private_project._id) + @pytest.fixture() + def private_url(self, private_project): + return '/{}nodes/{}/citation/'.format(API_BASE, private_project._id) class TestNodeCitationsStyle(NodeCitationsMixin): + @pytest.fixture() + def public_url(self, public_project): + return '/{}nodes/{}/citation/apa/'.format(API_BASE, public_project._id) - @pytest.fixture(autouse=True) - def setUp(self): - super(TestNodeCitationsStyle, self).setUp() - self.public_url = '/{}nodes/{}/citation/apa/'.format(API_BASE, self.public_project._id) - self.private_url = '/{}nodes/{}/citation/apa/'.format(API_BASE, self.private_project._id) + @pytest.fixture() + def private_url(self, private_project): + return '/{}nodes/{}/citation/apa/'.format(API_BASE, private_project._id) diff --git a/api_tests/nodes/views/test_node_embeds.py b/api_tests/nodes/views/test_node_embeds.py index eb4784c2afb..265cda57d70 100644 --- a/api_tests/nodes/views/test_node_embeds.py +++ b/api_tests/nodes/views/test_node_embeds.py @@ -2,7 +2,6 @@ import functools from framework.auth.core import Auth -from tests.json_api_test_app import JSONAPITestApp from api.base.settings.defaults import API_BASE from tests.base import ApiTestCase from osf_tests.factories import ( @@ -10,94 +9,121 @@ AuthUserFactory ) +@pytest.fixture() +def user(): + return AuthUserFactory() + @pytest.mark.django_db class TestNodeEmbeds: - @pytest.fixture(autouse=True) - def setUp(self): - self.app = JSONAPITestApp() - self.user = AuthUserFactory() - self.auth = Auth(self.user) - make_public_node = functools.partial(ProjectFactory, is_public=False, creator=self.user) - self.root_node = make_public_node() - self.child1 = make_public_node(parent=self.root_node) - self.child2 = make_public_node(parent=self.root_node) + @pytest.fixture() + def contrib_one(self): + return AuthUserFactory() + + @pytest.fixture() + def contrib_two(self): + return AuthUserFactory() + + @pytest.fixture() + def contribs(self, contrib_one, contrib_two): + return [contrib_one, contrib_two] + + @pytest.fixture() + def auth(self, user): + return Auth(user) + + @pytest.fixture() + def make_public_node(self, user): + return functools.partial(ProjectFactory, is_public=False, creator=user) + + @pytest.fixture() + def root_node(self, auth, contrib_one, contrib_two, make_public_node): + root_node = make_public_node() + root_node.add_contributor(contrib_one, ['read', 'write'], auth=auth, save=True) + root_node.add_contributor(contrib_two, ['read', 'write'], auth=auth, save=True) + return root_node + + @pytest.fixture() + def child_one(self, auth, contrib_one, contrib_two, make_public_node, root_node): + child_one = make_public_node(parent=root_node) + child_one.add_contributor(contrib_one, ['read', 'write'], auth=auth, save=True) + child_one.add_contributor(contrib_two, ['read', 'write'], auth=auth, save=True) + return child_one - self.contribs = [AuthUserFactory() for i in range(2)] - for contrib in self.contribs: - self.root_node.add_contributor(contrib, ['read', 'write'], auth=self.auth, save=True) - self.child1.add_contributor(contrib, ['read', 'write'], auth=self.auth, save=True) + @pytest.fixture() + def child_two(self, make_public_node, root_node): + return make_public_node(parent=root_node) - self.contrib1 = self.contribs[0] - self.contrib2 = self.contribs[1] - self.subchild = ProjectFactory(parent=self.child2, creator=self.contrib1) + @pytest.fixture() + def subchild(self, child_two, contrib_one): + return ProjectFactory(parent=child_two, creator=contrib_one) - def test_node_embeds(self): + def test_node_embeds(self, app, user, contrib_one, contribs, subchild, root_node, child_one, child_two): # test_embed_children - url = '/{0}nodes/{1}/?embed=children'.format(API_BASE, self.root_node._id) + url = '/{0}nodes/{1}/?embed=children'.format(API_BASE, root_node._id) - res = self.app.get(url, auth=self.user.auth) + res = app.get(url, auth=user.auth) embeds = res.json['data']['embeds'] - ids = [self.child1._id, self.child2._id] + ids = [child_one._id, child_two._id] for child in embeds['children']['data']: assert child['id'] in ids # test_embed_parent - url = '/{0}nodes/{1}/?embed=parent'.format(API_BASE, self.child1._id) + url = '/{0}nodes/{1}/?embed=parent'.format(API_BASE, child_one._id) - res = self.app.get(url, auth=self.user.auth) + res = app.get(url, auth=user.auth) embeds = res.json['data']['embeds'] - assert embeds['parent']['data']['id'] == self.root_node._id + assert embeds['parent']['data']['id'] == root_node._id # test_embed_no_parent - url = '/{0}nodes/{1}/?embed=parent'.format(API_BASE, self.root_node._id) + url = '/{0}nodes/{1}/?embed=parent'.format(API_BASE, root_node._id) - res = self.app.get(url, auth=self.user.auth) + res = app.get(url, auth=user.auth) data = res.json['data'] assert 'embeds' not in data # test_embed_contributors - url = '/{0}nodes/{1}/?embed=contributors'.format(API_BASE, self.child1._id) + url = '/{0}nodes/{1}/?embed=contributors'.format(API_BASE, child_one._id) - res = self.app.get(url, auth=self.user.auth) + res = app.get(url, auth=user.auth) embeds = res.json['data']['embeds'] - ids = [c._id for c in self.contribs] + [self.user._id] - ids = ['{}-{}'.format(self.child1._id, id_) for id_ in ids] + ids = [c._id for c in contribs] + [user._id] + ids = ['{}-{}'.format(child_one._id, id_) for id_ in ids] for contrib in embeds['contributors']['data']: assert contrib['id'] in ids # test_embed_children_filters_unauthorized - url = '/{0}nodes/{1}/?embed=children'.format(API_BASE, self.root_node._id) + url = '/{0}nodes/{1}/?embed=children'.format(API_BASE, root_node._id) - res = self.app.get(url, auth=self.contrib1.auth) + res = app.get(url, auth=contrib_one.auth) embeds = res.json['data']['embeds'] ids = [c['id'] for c in embeds['children']['data']] - assert self.child2._id not in ids - assert self.child1._id in ids + assert child_two._id not in ids + assert child_one._id in ids # test_embed_parent_unauthorized - url = '/{0}nodes/{1}/?embed=parent'.format(API_BASE, self.subchild._id) + url = '/{0}nodes/{1}/?embed=parent'.format(API_BASE, subchild._id) - res = self.app.get(url, auth=self.contrib1.auth) + res = app.get(url, auth=contrib_one.auth) assert 'errors' in res.json['data']['embeds']['parent'] assert res.json['data']['embeds']['parent']['errors'][0]['detail'] == 'You do not have permission to perform this action.' # test_embed_attributes_not_relationships - url = '/{}nodes/{}/?embed=title'.format(API_BASE, self.root_node._id) + url = '/{}nodes/{}/?embed=title'.format(API_BASE, root_node._id) - res = self.app.get(url, auth=self.contrib1.auth, expect_errors=True) + res = app.get(url, auth=contrib_one.auth, expect_errors=True) assert res.status_code == 400 assert res.json['errors'][0]['detail'] == 'The following fields are not embeddable: title' # test_embed_contributors_pagination - url = '/{}nodes/{}/?embed=contributors'.format(API_BASE, self.root_node._id) - res = self.app.get(url, auth=self.contrib1.auth) + url = '/{}nodes/{}/?embed=contributors'.format(API_BASE, root_node._id) + res = app.get(url, auth=contrib_one.auth) assert res.status_code == 200 assert res.json['data']['embeds']['contributors']['links']['meta']['total_bibliographic'] == 3 # test_embed_contributors_updated_pagination - url = '/{}nodes/{}/?version=2.1&embed=contributors'.format(API_BASE, self.root_node._id) - res = self.app.get(url, auth=self.contrib1.auth) + url = '/{}nodes/{}/?version=2.1&embed=contributors'.format(API_BASE, root_node._id) + res = app.get(url, auth=contrib_one.auth) assert res.status_code == 200 assert res.json['data']['embeds']['contributors']['meta']['total_bibliographic'] == 3 diff --git a/api_tests/nodes/views/test_node_exceptions.py b/api_tests/nodes/views/test_node_exceptions.py index 80710971486..6010892db19 100644 --- a/api_tests/nodes/views/test_node_exceptions.py +++ b/api_tests/nodes/views/test_node_exceptions.py @@ -1,45 +1,52 @@ import pytest from api.base.settings.defaults import API_BASE -from tests.json_api_test_app import JSONAPITestApp from tests.base import ApiTestCase from osf_tests.factories import ( ProjectFactory, AuthUserFactory ) +@pytest.fixture() +def user(): + return AuthUserFactory() + @pytest.mark.django_db class TestExceptionFormatting: - @pytest.fixture(autouse=True) - def setUp(self): - self.app = JSONAPITestApp() - self.user = AuthUserFactory() - self.non_contrib = AuthUserFactory() - - self.title = 'Cool Project' - self.description = 'A Properly Cool Project' - self.category = 'data' + @pytest.fixture() + def non_contrib(self): + return AuthUserFactory() - self.project_no_title = { + @pytest.fixture() + def project_no_title(self): + return { 'data': { 'attributes': { - 'description': self.description, - 'category': self.category, + 'description': 'A Monument to Reason', + 'category': 'data', 'type': 'nodes', } } } - self.private_project = ProjectFactory(is_public=False, creator=self.user) - self.public_project = ProjectFactory(is_public=True, creator=self.user) - self.private_url = '/{}nodes/{}/'.format(API_BASE, self.private_project._id) + @pytest.fixture() + def private_project(self, user): + return ProjectFactory(is_public=False, creator=user) + + @pytest.fixture() + def public_project(self, user): + return ProjectFactory(is_public=True, creator=user) + + @pytest.fixture() + def private_url(self, private_project): + return '/{}nodes/{}/'.format(API_BASE, private_project._id) - def test_exception_formatting(self): + def test_exception_formatting(self, app, user, non_contrib, public_project, private_project, private_url, project_no_title): # test_creates_project_with_no_title_formatting url = '/{}nodes/'.format(API_BASE) - res = self.app.post_json_api(url, self.project_no_title, auth=self.user.auth, expect_errors=True) + res = app.post_json_api(url, project_no_title, auth=user.auth, expect_errors=True) errors = res.json['errors'] assert(isinstance(errors, list)) assert res.json['errors'][0]['source'] == {'pointer': '/data/attributes/title'} @@ -47,25 +54,25 @@ def test_exception_formatting(self): # test_node_does_not_exist_formatting url = '/{}nodes/{}/'.format(API_BASE, '12345') - res = self.app.get(url, auth=self.user.auth, expect_errors=True) + res = app.get(url, auth=user.auth, expect_errors=True) errors = res.json['errors'] assert(isinstance(errors, list)) assert errors[0] == {'detail': 'Not found.'} # test_forbidden_formatting - res = self.app.get(self.private_url, auth=self.non_contrib.auth, expect_errors=True) + res = app.get(private_url, auth=non_contrib.auth, expect_errors=True) errors = res.json['errors'] assert(isinstance(errors, list)) assert errors[0] == {'detail': 'You do not have permission to perform this action.'} # test_not_authorized_formatting - res = self.app.get(self.private_url, expect_errors=True) + res = app.get(private_url, expect_errors=True) errors = res.json['errors'] assert(isinstance(errors, list)) assert errors[0] == {'detail': 'Authentication credentials were not provided.'} # test_update_project_with_no_title_or_category_formatting - res = self.app.put_json_api(self.private_url, {'data': {'type': 'nodes', 'id': self.private_project._id, 'attributes': {'description': 'New description'}}}, auth=self.user.auth, expect_errors=True) + res = app.put_json_api(private_url, {'data': {'type': 'nodes', 'id': private_project._id, 'attributes': {'description': 'New description'}}}, auth=user.auth, expect_errors=True) errors = res.json['errors'] assert(isinstance(errors, list)) assert len(errors) == 2 @@ -77,8 +84,8 @@ def test_exception_formatting(self): assert errors[1]['detail'] == 'This field is required.' # test_create_node_link_no_target_formatting - url = self.private_url + 'node_links/' - res = self.app.post_json_api(url, { + url = private_url + 'node_links/' + res = app.post_json_api(url, { 'data': { 'type': 'node_links', 'relationships': { @@ -90,7 +97,7 @@ def test_exception_formatting(self): } } } - }, auth=self.user.auth, expect_errors=True) + }, auth=user.auth, expect_errors=True) errors = res.json['errors'] assert(isinstance(errors, list)) assert res.status_code == 400 @@ -98,34 +105,34 @@ def test_exception_formatting(self): assert res.json['errors'][0]['detail'] == 'This field may not be blank.' # test_node_link_already_exists - url = self.private_url + 'node_links/' - res = self.app.post_json_api(url, { + url = private_url + 'node_links/' + res = app.post_json_api(url, { 'data': { 'type': 'node_links', 'relationships': { 'nodes': { 'data': { - 'id': self.public_project._id, + 'id': public_project._id, 'type': 'nodes', } } } } - }, auth=self.user.auth) + }, auth=user.auth) assert res.status_code == 201 - res = self.app.post_json_api(url, {'data': { + res = app.post_json_api(url, {'data': { 'type': 'node_links', 'relationships': { 'nodes': { 'data': { - 'id': self.public_project._id, + 'id': public_project._id, 'type': 'nodes' } } } - }}, auth=self.user.auth, expect_errors=True) + }}, auth=user.auth, expect_errors=True) errors = res.json['errors'] assert(isinstance(errors, list)) assert res.status_code == 400 - assert(self.public_project._id in res.json['errors'][0]['detail']) + assert(public_project._id in res.json['errors'][0]['detail']) diff --git a/api_tests/nodes/views/test_node_institutions_list.py b/api_tests/nodes/views/test_node_institutions_list.py index aff0fcd71ce..d7a62e4dd90 100644 --- a/api_tests/nodes/views/test_node_institutions_list.py +++ b/api_tests/nodes/views/test_node_institutions_list.py @@ -1,37 +1,45 @@ import pytest from tests.base import ApiTestCase -from tests.json_api_test_app import JSONAPITestApp from osf_tests.factories import InstitutionFactory, NodeFactory, AuthUserFactory from api.base.settings.defaults import API_BASE +@pytest.fixture() +def user(): + return AuthUserFactory() + @pytest.mark.django_db class TestNodeInstitutionDetail: - @pytest.fixture(autouse=True) - def setUp(self): - self.app = JSONAPITestApp() - self.institution = InstitutionFactory() - self.node = NodeFactory(is_public=True) - self.node.affiliated_institutions.add(self.institution) - self.node.save() - self.user = AuthUserFactory() - self.node2 = NodeFactory(creator=self.user) + @pytest.fixture() + def institution(self): + return InstitutionFactory() + + @pytest.fixture() + def node_one(self, institution): + node_one = NodeFactory(is_public=True) + node_one.affiliated_institutions.add(institution) + node_one.save() + return node_one + + @pytest.fixture() + def node_two(self, user): + return NodeFactory(creator=user) - def test_node_institution_detail(self): + def test_node_institution_detail(self, app, user, institution, node_one, node_two,): # test_return_institution - url = '/{0}nodes/{1}/institutions/'.format(API_BASE, self.node._id) - res = self.app.get(url) + url = '/{0}nodes/{1}/institutions/'.format(API_BASE, node_one._id) + res = app.get(url) assert res.status_code == 200 - assert res.json['data'][0]['attributes']['name'] == self.institution.name - assert res.json['data'][0]['id'] == self.institution._id + assert res.json['data'][0]['attributes']['name'] == institution.name + assert res.json['data'][0]['id'] == institution._id # test_return_no_institution - url = '/{0}nodes/{1}/institution/'.format(API_BASE, self.node2._id) - res = self.app.get( - url, auth=self.user.auth, + url = '/{0}nodes/{1}/institution/'.format(API_BASE, node_two._id) + res = app.get( + url, auth=user.auth, expect_errors=True ) diff --git a/api_tests/nodes/views/test_node_links_detail.py b/api_tests/nodes/views/test_node_links_detail.py index f02dc2aebef..72192caeeb5 100644 --- a/api_tests/nodes/views/test_node_links_detail.py +++ b/api_tests/nodes/views/test_node_links_detail.py @@ -1,13 +1,11 @@ import pytest - from urlparse import urlparse from framework.auth.core import Auth from website.models import NodeLog from api.base.settings.defaults import API_BASE -from tests.json_api_test_app import JSONAPITestApp from tests.base import ApiTestCase -from tests.utils import assert_logs +from tests.utils import assert_latest_log from osf_tests.factories import ( ProjectFactory, RegistrationFactory, @@ -16,119 +14,159 @@ node_url_for = lambda n_id: '/{}nodes/{}/'.format(API_BASE, n_id) +@pytest.fixture() +def user(): + return AuthUserFactory() + @pytest.mark.django_db class TestNodeLinkDetail: - @pytest.fixture(autouse=True) - def setUp(self): - self.app = JSONAPITestApp() - self.user = AuthUserFactory() - self.private_project = ProjectFactory(creator=self.user, is_public=False) - self.pointer_project = ProjectFactory(creator=self.user, is_public=False) - self.pointer = self.private_project.add_pointer(self.pointer_project, auth=Auth(self.user), save=True) - self.private_url = '/{}nodes/{}/node_links/{}/'.format(API_BASE, self.private_project._id, self.pointer._id) + @pytest.fixture() + def non_contributor(self): + return AuthUserFactory() + + @pytest.fixture() + def private_project(self, user): + return ProjectFactory(creator=user, is_public=False) + + @pytest.fixture() + def private_pointer_project(self, user): + return ProjectFactory(creator=user, is_public=False) + + @pytest.fixture() + def private_pointer(self, user, private_project, private_pointer_project): + return private_project.add_pointer(private_pointer_project, auth=Auth(user), save=True) + + @pytest.fixture() + def private_url(self, private_project, private_pointer): + return '/{}nodes/{}/node_links/{}/'.format(API_BASE, private_project._id, private_pointer._id) - self.user_two = AuthUserFactory() + @pytest.fixture() + def public_project(self, user): + return ProjectFactory(creator=user, is_public=True) - self.public_project = ProjectFactory(creator=self.user, is_public=True) - self.public_pointer_project = ProjectFactory(is_public=True) - self.public_pointer = self.public_project.add_pointer(self.public_pointer_project, - auth=Auth(self.user), - save=True) - self.public_url = '/{}nodes/{}/node_links/{}/'.format(API_BASE, self.public_project._id, self.public_pointer._id) + @pytest.fixture() + def public_pointer_project(self): + return ProjectFactory(is_public=True) - def test_node_link_detail(self): + @pytest.fixture() + def public_pointer(self, user, public_project, public_pointer_project): + return public_project.add_pointer(public_pointer_project, auth=Auth(user), save=True) + + @pytest.fixture() + def public_url(self, public_project, public_pointer): + return '/{}nodes/{}/node_links/{}/'.format(API_BASE, public_project._id, public_pointer._id) + + def test_node_link_detail(self, app, user, non_contributor, private_pointer_project, public_pointer_project, public_url, private_url): # test_returns_embedded_public_node_pointer_detail_logged_out - res = self.app.get(self.public_url) + res = app.get(public_url) assert res.status_code == 200 assert res.content_type == 'application/vnd.api+json' res_json = res.json['data'] embedded = res_json['embeds']['target_node']['data']['id'] - assert embedded == self.public_pointer_project._id + assert embedded == public_pointer_project._id # test_returns_public_node_pointer_detail_logged_in - res = self.app.get(self.public_url, auth=self.user.auth) + res = app.get(public_url, auth=user.auth) res_json = res.json['data'] assert res.status_code == 200 assert res.content_type == 'application/vnd.api+json' embedded = res_json['embeds']['target_node']['data']['id'] - assert embedded == self.public_pointer_project._id + assert embedded == public_pointer_project._id # test_returns_private_node_pointer_detail_logged_out - res = self.app.get(self.private_url, expect_errors=True) + res = app.get(private_url, expect_errors=True) assert res.status_code == 200 target_node = res.json['data']['embeds']['target_node'] assert 'errors' in target_node assert target_node['errors'][0]['detail'] == 'You do not have permission to perform this action.' # test_returns_private_node_pointer_detail_logged_in_contributor - res = self.app.get(self.private_url, auth=self.user.auth) + res = app.get(private_url, auth=user.auth) res_json = res.json['data'] assert res.status_code == 200 assert res.content_type == 'application/vnd.api+json' embedded = res_json['embeds']['target_node']['data']['id'] - assert embedded == self.pointer_project._id + assert embedded == private_pointer_project._id # test_returns_private_node_pointer_detail_logged_in_non_contributor - res = self.app.get(self.private_url, auth=self.user_two.auth, expect_errors=True) + res = app.get(private_url, auth=non_contributor.auth, expect_errors=True) assert res.status_code == 200 target_node = res.json['data']['embeds']['target_node'] assert 'errors' in target_node assert target_node['errors'][0]['detail'] == 'You do not have permission to perform this action.' # test_self_link_points_to_node_link_detail_url - res = self.app.get(self.public_url, auth=self.user.auth) + res = app.get(public_url, auth=user.auth) assert res.status_code == 200 url = res.json['data']['links']['self'] - assert self.public_url in url + assert public_url in url # test_node_links_bad_version - url = '{}?version=2.1'.format(self.public_url) - res = self.app.get(url, auth=self.user.auth, expect_errors=True) + url = '{}?version=2.1'.format(public_url) + res = app.get(url, auth=user.auth, expect_errors=True) assert res.status_code == 404 assert res.json['errors'][0]['detail'] == 'This feature is deprecated as of version 2.1' @pytest.mark.django_db class TestDeleteNodeLink: - @pytest.fixture(autouse=True) - def setUp(self): - self.app = JSONAPITestApp() - self.user = AuthUserFactory() - self.project = ProjectFactory(creator=self.user, is_public=False) - self.pointer_project = ProjectFactory(creator=self.user, is_public=True) - self.pointer = self.project.add_pointer(self.pointer_project, auth=Auth(self.user), save=True) - self.private_url = '/{}nodes/{}/node_links/{}/'.format(API_BASE, self.project._id, self.pointer._id) - - self.user_two = AuthUserFactory() - - self.public_project = ProjectFactory(is_public=True, creator=self.user) - self.public_pointer_project = ProjectFactory(is_public=True, creator=self.user) - self.public_pointer = self.public_project.add_pointer(self.public_pointer_project, - auth=Auth(self.user), - save=True) - self.public_url = '/{}nodes/{}/node_links/{}/'.format(API_BASE, self.public_project._id, self.public_pointer._id) - - def test_delete_node_link_no_permissions_for_target_node(self): - pointer_project = ProjectFactory(creator=self.user_two, is_public=False) - pointer = self.public_project.add_pointer(pointer_project, auth=Auth(self.user), save=True) - assert pointer.child in self.public_project.nodes - url = '/{}nodes/{}/node_links/{}/'.format(API_BASE, self.public_project._id, pointer._id) - res = self.app.delete_json_api(url, auth=self.user.auth, expect_errors=True) + @pytest.fixture() + def user_two(self): + return AuthUserFactory() + + @pytest.fixture() + def private_project(self, user): + return ProjectFactory(creator=user, is_public=False) + + @pytest.fixture() + def private_pointer_project(self, user): + return ProjectFactory(creator=user, is_public=True) + + @pytest.fixture() + def private_pointer(self, user, private_project, private_pointer_project): + return private_project.add_pointer(private_pointer_project, auth=Auth(user), save=True) + + @pytest.fixture() + def private_url(self, private_project, private_pointer): + return '/{}nodes/{}/node_links/{}/'.format(API_BASE, private_project._id, private_pointer._id) + + @pytest.fixture() + def public_project(self, user): + return ProjectFactory(is_public=True, creator=user) + + @pytest.fixture() + def public_pointer_project(self, user): + return ProjectFactory(is_public=True, creator=user) + + @pytest.fixture() + def public_pointer(self, user, public_project, public_pointer_project): + return public_project.add_pointer(public_pointer_project, auth=Auth(user), save=True) + + @pytest.fixture() + def public_url(self, public_project, public_pointer): + return '/{}nodes/{}/node_links/{}/'.format(API_BASE, public_project._id, public_pointer._id) + + def test_delete_node_link_no_permissions_for_target_node(self, app, user, user_two, public_project): + pointer_project = ProjectFactory(creator=user_two, is_public=False) + pointer = public_project.add_pointer(pointer_project, auth=Auth(user), save=True) + assert pointer.child in public_project.nodes + url = '/{}nodes/{}/node_links/{}/'.format(API_BASE, public_project._id, pointer._id) + res = app.delete_json_api(url, auth=user.auth, expect_errors=True) assert res.status_code == 204 - self.public_project.reload() - assert pointer not in self.public_project.nodes + public_project.reload() + assert pointer not in public_project.nodes - def test_cannot_delete_if_registration(self): - registration = RegistrationFactory(project=self.public_project) + def test_cannot_delete_if_registration(self, app, user, public_project, public_pointer): + registration = RegistrationFactory(project=public_project) url = '/{}registrations/{}/node_links/'.format( API_BASE, registration._id, ) - res = self.app.get(url, auth=self.user.auth) + res = app.get(url, auth=user.auth) assert res.status_code == 200 pointer_id = res.json['data'][0]['id'] @@ -137,79 +175,78 @@ def test_cannot_delete_if_registration(self): registration._id, pointer_id, ) - res = self.app.delete(url, auth=self.user.auth, expect_errors=True) + res = app.delete(url, auth=user.auth, expect_errors=True) assert res.status_code == 405 - def test_deletes_public_node_pointer_logged_out(self): - res = self.app.delete(self.public_url, expect_errors=True) + def test_deletes_public_node_pointer_logged_out(self, app, public_url): + res = app.delete(public_url, expect_errors=True) assert res.status_code == 401 assert 'detail' in res.json['errors'][0].keys() - def test_deletes_public_node_pointer_fails_if_bad_auth(self): - node_count_before = len(self.public_project.nodes_pointer) - res = self.app.delete(self.public_url, auth=self.user_two.auth, expect_errors=True) + def test_deletes_public_node_pointer_fails_if_bad_auth(self, app, user_two, public_project, public_url): + node_count_before = len(public_project.nodes_pointer) + res = app.delete(public_url, auth=user_two.auth, expect_errors=True) # This is could arguably be a 405, but we don't need to go crazy with status codes assert res.status_code == 403 assert 'detail' in res.json['errors'][0] - self.public_project.reload() - assert node_count_before == len(self.public_project.nodes_pointer) - - @assert_logs(NodeLog.POINTER_REMOVED, 'public_project') - def test_deletes_public_node_pointer_succeeds_as_owner(self): - node_count_before = len(self.public_project.nodes_pointer) - res = self.app.delete(self.public_url, auth=self.user.auth) - self.public_project.reload() - assert res.status_code == 204 - assert node_count_before - 1 == len(self.public_project.nodes_pointer) - - def test_deletes_private_node_pointer_logged_out(self): - res = self.app.delete(self.private_url, expect_errors=True) + public_project.reload() + assert node_count_before == len(public_project.nodes_pointer) + + def test_deletes_public_node_pointer_succeeds_as_owner(self, app, user, public_project, public_pointer, public_url): + with assert_latest_log(NodeLog.POINTER_REMOVED, public_project): + node_count_before = len(public_project.nodes_pointer) + res = app.delete(public_url, auth=user.auth) + public_project.reload() + assert res.status_code == 204 + assert node_count_before - 1 == len(public_project.nodes_pointer) + + def test_deletes_private_node_pointer_logged_out(self, app, private_url): + res = app.delete(private_url, expect_errors=True) assert res.status_code == 401 assert 'detail' in res.json['errors'][0] - @assert_logs(NodeLog.POINTER_REMOVED, 'project') - def test_deletes_private_node_pointer_logged_in_contributor(self): - res = self.app.delete(self.private_url, auth=self.user.auth) - self.project.reload() # Update the model to reflect changes made by post request - assert res.status_code == 204 - assert len(self.project.nodes_pointer) == 0 + def test_deletes_private_node_pointer_logged_in_contributor(self, app, user, private_project, private_url): + with assert_latest_log(NodeLog.POINTER_REMOVED, private_project): + res = app.delete(private_url, auth=user.auth) + private_project.reload() # Update the model to reflect changes made by post request + assert res.status_code == 204 + assert len(private_project.nodes_pointer) == 0 - def test_deletes_private_node_pointer_logged_in_non_contributor(self): - res = self.app.delete(self.private_url, auth=self.user_two.auth, expect_errors=True) + def test_deletes_private_node_pointer_logged_in_non_contributor(self, app, user_two, private_url): + res = app.delete(private_url, auth=user_two.auth, expect_errors=True) assert res.status_code == 403 assert 'detail' in res.json['errors'][0] - @assert_logs(NodeLog.POINTER_REMOVED, 'public_project') - def test_return_deleted_public_node_pointer(self): - res = self.app.delete(self.public_url, auth=self.user.auth) - self.public_project.reload() # Update the model to reflect changes made by post request - assert res.status_code == 204 + def test_return_deleted_public_node_pointer(self, app, user, public_project, public_url): + with assert_latest_log(NodeLog.POINTER_REMOVED, public_project): + res = app.delete(public_url, auth=user.auth) + public_project.reload() # Update the model to reflect changes made by post request + assert res.status_code == 204 #check that deleted pointer can not be returned - res = self.app.get(self.public_url, auth=self.user.auth, expect_errors=True) + res = app.get(public_url, auth=user.auth, expect_errors=True) assert res.status_code == 404 - @assert_logs(NodeLog.POINTER_REMOVED, 'project') - def test_return_deleted_private_node_pointer(self): - res = self.app.delete(self.private_url, auth=self.user.auth) - self.project.reload() # Update the model to reflect changes made by post request - assert res.status_code == 204 + def test_return_deleted_private_node_pointer(self, app, user, private_project, private_url): + with assert_latest_log(NodeLog.POINTER_REMOVED, private_project): + res = app.delete(private_url, auth=user.auth) + private_project.reload() # Update the model to reflect changes made by post request + assert res.status_code == 204 #check that deleted pointer can not be returned - res = self.app.get(self.private_url, auth=self.user.auth, expect_errors=True) + res = app.get(private_url, auth=user.auth, expect_errors=True) assert res.status_code == 404 # Regression test for https://openscience.atlassian.net/browse/OSF-4322 - def test_delete_link_that_is_not_linked_to_correct_node(self): - project = ProjectFactory(creator=self.user) + def test_delete_link_that_is_not_linked_to_correct_node(self, app, user, public_pointer): + project = ProjectFactory(creator=user) # The node link belongs to a different project - res = self.app.delete( - '/{}nodes/{}/node_links/{}/'.format(API_BASE, project._id, self.public_pointer._id), - auth=self.user.auth, + res = app.delete( + '/{}nodes/{}/node_links/{}/'.format(API_BASE, project._id, public_pointer._id), + auth=user.auth, expect_errors=True ) assert res.status_code == 404 errors = res.json['errors'] assert len(errors) == 1 assert errors[0]['detail'] == 'Not found.' - diff --git a/api_tests/nodes/views/test_node_links_list.py b/api_tests/nodes/views/test_node_links_list.py index 83ef447eca1..3ec265f9406 100644 --- a/api_tests/nodes/views/test_node_links_list.py +++ b/api_tests/nodes/views/test_node_links_list.py @@ -1,5 +1,4 @@ import pytest - from urlparse import urlparse from framework.auth.core import Auth @@ -7,7 +6,7 @@ from api.base.settings.defaults import API_BASE from tests.json_api_test_app import JSONAPITestApp from tests.base import ApiTestCase -from tests.utils import assert_logs +from tests.utils import assert_latest_log from osf_tests.factories import ( ProjectFactory, RegistrationFactory, @@ -16,260 +15,254 @@ node_url_for = lambda n_id: '/{}nodes/{}/'.format(API_BASE, n_id) +@pytest.fixture() +def user(): + return AuthUserFactory() + @pytest.mark.django_db class TestNodeLinksList: - @pytest.fixture(autouse=True) - def setUp(self): - self.app = JSONAPITestApp() - self.user = AuthUserFactory() - self.project = ProjectFactory(is_public=False, creator=self.user) - self.pointer_project = ProjectFactory(is_public=False, creator=self.user) - self.project.add_pointer(self.pointer_project, auth=Auth(self.user)) - self.private_url = '/{}nodes/{}/node_links/'.format(API_BASE, self.project._id) + @pytest.fixture() + def public_non_contrib(self): + return AuthUserFactory() + + @pytest.fixture() + def private_pointer_project(self, user): + return ProjectFactory(is_public=False, creator=user) + + @pytest.fixture() + def private_project(self, user, private_pointer_project): + private_project = ProjectFactory(is_public=False, creator=user) + private_project.add_pointer(private_pointer_project, auth=Auth(user)) + return private_project - self.public_project = ProjectFactory(is_public=True, creator=self.user) - self.public_pointer_project = ProjectFactory(is_public=True, creator=self.user) - self.public_project.add_pointer(self.public_pointer_project, auth=Auth(self.user)) - self.public_url = '/{}nodes/{}/node_links/'.format(API_BASE, self.public_project._id) + @pytest.fixture() + def private_url(self, private_project): + return '/{}nodes/{}/node_links/'.format(API_BASE, private_project._id) - self.user_two = AuthUserFactory() + @pytest.fixture() + def public_pointer_project(self, user): + return ProjectFactory(is_public=True, creator=user) - def test_non_mutational_node_links_list_tests(self): + @pytest.fixture() + def public_project(self, user, public_pointer_project): + public_project = ProjectFactory(is_public=True, creator=user) + public_project.add_pointer(public_pointer_project, auth=Auth(user)) + return public_project + + @pytest.fixture() + def public_url(self, public_project): + return '/{}nodes/{}/node_links/'.format(API_BASE, public_project._id) + + def test_non_mutational_node_links_list_tests(self, app, user, public_non_contrib, public_pointer_project, private_pointer_project, public_url, private_url): # test_return_embedded_public_node_pointers_logged_out - res = self.app.get(self.public_url) + res = app.get(public_url) res_json = res.json['data'] assert len(res_json) == 1 assert res.status_code == 200 assert res.content_type == 'application/vnd.api+json' embedded = res_json[0]['embeds']['target_node']['data']['id'] - assert embedded == self.public_pointer_project._id + assert embedded == public_pointer_project._id # test_return_embedded_public_node_pointers_logged_in - res = self.app.get(self.public_url, auth=self.user_two.auth) + res = app.get(public_url, auth=public_non_contrib.auth) res_json = res.json['data'] assert len(res_json) == 1 assert res.status_code == 200 assert res.content_type == 'application/vnd.api+json' embedded = res_json[0]['embeds']['target_node']['data']['id'] - assert embedded == self.public_pointer_project._id + assert embedded == public_pointer_project._id # test_return_private_node_pointers_logged_out - res = self.app.get(self.private_url, expect_errors=True) + res = app.get(private_url, expect_errors=True) assert res.status_code == 401 assert 'detail' in res.json['errors'][0] # test_return_private_node_pointers_logged_in_contributor - res = self.app.get(self.private_url, auth=self.user.auth) + res = app.get(private_url, auth=user.auth) res_json = res.json['data'] assert res.status_code == 200 assert res.content_type == 'application/vnd.api+json' assert len(res_json) == 1 embedded = res_json[0]['embeds']['target_node']['data']['id'] - assert embedded == self.pointer_project._id + assert embedded == private_pointer_project._id # test_return_private_node_pointers_logged_in_non_contributor - res = self.app.get(self.private_url, auth=self.user_two.auth, expect_errors=True) + res = app.get(private_url, auth=public_non_contrib.auth, expect_errors=True) assert res.status_code == 403 assert 'detail' in res.json['errors'][0] # test_node_links_bad_version - url = '{}?version=2.1'.format(self.public_url) - res = self.app.get(url, auth=self.user.auth, expect_errors=True) + url = '{}?version=2.1'.format(public_url) + res = app.get(url, auth=user.auth, expect_errors=True) assert res.status_code == 404 assert res.json['errors'][0]['detail'] == 'This feature is deprecated as of version 2.1' - def test_deleted_links_not_returned(self): - res = self.app.get(self.public_url, expect_errors=True) + def test_deleted_links_not_returned(self, app, public_url, public_pointer_project): + res = app.get(public_url, expect_errors=True) res_json = res.json['data'] original_length = len(res_json) - self.public_pointer_project.is_deleted = True - self.public_pointer_project.save() + public_pointer_project.is_deleted = True + public_pointer_project.save() - res = self.app.get(self.public_url) + res = app.get(public_url) res_json = res.json['data'] assert len(res_json) == original_length - 1 @pytest.mark.django_db class TestNodeLinkCreate: - @pytest.fixture(autouse=True) - def setUp(self): - self.app = JSONAPITestApp() - self.user = AuthUserFactory() - self.project = ProjectFactory(is_public=False, creator=self.user) - self.pointer_project = ProjectFactory(is_public=False, creator=self.user) - self.private_url = '/{}nodes/{}/node_links/'.format(API_BASE, self.project._id) - - self.private_payload = { - 'data': { - 'type': 'node_links', - 'relationships': { - 'nodes': { - 'data': { - 'id': self.pointer_project._id, - 'type': 'nodes' + @pytest.fixture() + def private_project(self, user): + return ProjectFactory(is_public=False, creator=user) + + @pytest.fixture() + def private_pointer_project(self, user): + return ProjectFactory(is_public=False, creator=user) + + @pytest.fixture() + def private_url(self, user, private_project): + return '/{}nodes/{}/node_links/'.format(API_BASE, private_project._id) + + @pytest.fixture() + def public_project(self, user): + return ProjectFactory(is_public=True, creator=user) + + @pytest.fixture() + def public_pointer_project(self, user): + return ProjectFactory(is_public=True, creator=user) + + @pytest.fixture() + def public_url(self, public_project): + return '/{}nodes/{}/node_links/'.format(API_BASE, public_project._id) + + @pytest.fixture() + def fake_url(self): + return '/{}nodes/{}/node_links/'.format(API_BASE, 'rheis') + + @pytest.fixture() + def user_two(self): + return AuthUserFactory() + + @pytest.fixture() + def user_two_project(self, user_two): + return ProjectFactory(is_public=True, creator=user_two) + + @pytest.fixture() + def user_two_url(self, user_two_project): + return '/{}nodes/{}/node_links/'.format(API_BASE, user_two_project._id) + + @pytest.fixture() + def make_payload(self): + + # creates a fake payload by default + + def payload(id='rheis'): + return { + 'data': { + 'type': 'node_links', + 'relationships': { + 'nodes': { + 'data': { + 'id': id, + 'type': 'nodes' + } } } } } - } - self.public_project = ProjectFactory(is_public=True, creator=self.user) - self.public_pointer_project = ProjectFactory(is_public=True, creator=self.user) - self.public_url = '/{}nodes/{}/node_links/'.format(API_BASE, self.public_project._id) - self.public_payload = { - 'data': { - 'type': 'node_links', - 'relationships': { - 'nodes': { - 'data': { - 'id': self.public_pointer_project._id, - 'type': 'nodes' - } - } - } - } - } - self.fake_url = '/{}nodes/{}/node_links/'.format(API_BASE, 'fdxlq') - self.fake_payload = { - 'data': { - 'type': 'node_links', - 'relationships': { - 'nodes': { - 'data': { - 'id': 'fdxlq', - 'type': 'nodes' - } - } - } - } - } - self.point_to_itself_payload = { - 'data': { - 'type': 'node_links', - 'relationships': { - 'nodes': { - 'data': { - 'id': self.public_project._id, - 'type': 'nodes' - } - } - } - } - } + return payload - self.user_two = AuthUserFactory() - self.user_two_project = ProjectFactory(is_public=True, creator=self.user_two) - self.user_two_url = '/{}nodes/{}/node_links/'.format(API_BASE, self.user_two_project._id) - self.user_two_payload = { - 'data': { - 'type': 'node_links', - 'relationships': { - 'nodes': { - 'data': { - 'id': self.user_two_project._id, - 'type': 'nodes' - } - } - } - } - } + def test_add_node_link(self, app, user, public_pointer_project, public_url): - def test_add_node_link_relationships_is_a_list(self): + # test_add_node_link_relationships_is_a_list data = { 'data': { 'type': 'node_links', - 'relationships': [{'target_node_id': self.public_pointer_project._id}] + 'relationships': [{'target_node_id': public_pointer_project._id}] } } - res = self.app.post_json_api(self.public_url, data, auth=self.user.auth, expect_errors=True) + res = app.post_json_api(public_url, data, auth=user.auth, expect_errors=True) assert res.status_code == 400 assert res.json['errors'][0]['detail'] == 'Malformed request.' - def test_create_node_link_invalid_data(self): - res = self.app.post_json_api(self.public_url, 'Incorrect data', auth=self.user.auth, expect_errors=True) - assert res.status_code == 400 - assert res.json['errors'][0]['detail'] == 'Malformed request.' - - - def test_add_node_link_no_relationships(self): + # test_add_node_link_no_relationships data = { 'data': { 'type': 'node_links', 'attributes': { - 'id': self.public_pointer_project._id + 'id': public_pointer_project._id } } } - res = self.app.post_json_api(self.public_url, data, auth=self.user.auth, expect_errors=True) + res = app.post_json_api(public_url, data, auth=user.auth, expect_errors=True) assert res.status_code == 400 assert res.json['errors'][0]['source']['pointer'] == '/data/relationships' - def test_add_node_links_empty_relationships(self): + # test_add_node_links_empty_relationships data = { 'data': { 'type': 'node_links', 'relationships': {} } } - res = self.app.post_json_api(self.public_url, data, auth=self.user.auth, expect_errors=True) + res = app.post_json_api(public_url, data, auth=user.auth, expect_errors=True) assert res.json['errors'][0]['source']['pointer'] == '/data/relationships' - def test_add_node_links_no_nodes_key_in_relationships(self): + # test_add_node_links_no_nodes_key_in_relationships data = { 'data': { 'type': 'node_links', 'relationships': { 'data': { - 'id': self.public_pointer_project._id, + 'id': public_pointer_project._id, 'type': 'nodes' } } } } - res = self.app.post_json_api(self.public_url, data, auth=self.user.auth, expect_errors=True) + res = app.post_json_api(public_url, data, auth=user.auth, expect_errors=True) assert res.status_code == 400 assert res.json['errors'][0]['detail'] == 'Malformed request.' - def test_add_node_links_no_data_in_relationships(self): + # test_add_node_links_no_data_in_relationships data = { 'data': { 'type': 'node_links', 'relationships': { 'nodes': { - 'id': self.public_pointer_project._id, + 'id': public_pointer_project._id, 'type': 'nodes' } } } } - res = self.app.post_json_api(self.public_url, data, auth=self.user.auth, expect_errors=True) + res = app.post_json_api(public_url, data, auth=user.auth, expect_errors=True) assert res.status_code == 400 assert res.json['errors'][0]['detail'] == 'Request must include /data.' - def test_add_node_links_no_target_type_in_relationships(self): + # test_add_node_links_no_target_type_in_relationships data = { 'data': { 'type': 'node_links', 'relationships': { 'nodes': { 'data': { - 'id': self.public_pointer_project._id + 'id': public_pointer_project._id } } } } } - res = self.app.post_json_api(self.public_url, data, auth=self.user.auth, expect_errors=True) + res = app.post_json_api(public_url, data, auth=user.auth, expect_errors=True) assert res.status_code == 400 assert res.json['errors'][0]['detail'] == 'Request must include /type.' - - def test_add_node_links_no_target_id_in_relationships(self): + # test_add_node_links_no_target_id_in_relationships data = { 'data': { 'type': 'node_links', @@ -282,11 +275,11 @@ def test_add_node_links_no_target_id_in_relationships(self): } } } - res = self.app.post_json_api(self.public_url, data, auth=self.user.auth, expect_errors=True) + res = app.post_json_api(public_url, data, auth=user.auth, expect_errors=True) assert res.status_code == 400 assert res.json['errors'][0]['source']['pointer'] == '/data/id' - def test_add_node_links_incorrect_target_id_in_relationships(self): + # test_add_node_links_incorrect_target_id_in_relationships data = { 'data': { 'type': 'node_links', @@ -300,10 +293,10 @@ def test_add_node_links_incorrect_target_id_in_relationships(self): } } } - res = self.app.post_json_api(self.public_url, data, auth=self.user.auth, expect_errors=True) + res = app.post_json_api(public_url, data, auth=user.auth, expect_errors=True) assert res.status_code == 400 - def test_add_node_links_incorrect_target_type_in_relationships(self): + # test_add_node_links_incorrect_target_type_in_relationships data = { 'data': { 'type': 'nodes', @@ -311,204 +304,246 @@ def test_add_node_links_incorrect_target_type_in_relationships(self): 'nodes': { 'data': { 'type': 'Incorrect!', - 'id': self.public_pointer_project._id + 'id': public_pointer_project._id } } } } } - res = self.app.post_json_api(self.public_url, data, auth=self.user.auth, expect_errors=True) + res = app.post_json_api(public_url, data, auth=user.auth, expect_errors=True) assert res.status_code == 409 - def test_creates_node_link_target_not_nested(self): + def test_create_node_link_invalid_data(self, app, user, public_url): + res = app.post_json_api(public_url, 'Incorrect data', auth=user.auth, expect_errors=True) + assert res.status_code == 400 + assert res.json['errors'][0]['detail'] == 'Malformed request.' + + def test_creates_node_link_target_not_nested(self, app, user_two, private_pointer_project, public_url): payload = { 'data': { 'type': 'node_links', - 'id': self.pointer_project._id + 'id': private_pointer_project._id } } - res = self.app.post_json_api(self.public_url, payload, auth=self.user_two.auth, expect_errors=True) + res = app.post_json_api(public_url, payload, auth=user_two.auth, expect_errors=True) assert res.status_code == 400 assert res.json['errors'][0]['source']['pointer'] == '/data/relationships' assert res.json['errors'][0]['detail'] == 'Request must include /data/relationships.' - def test_creates_public_node_pointer_logged_out(self): - res = self.app.post_json_api(self.public_url, self.public_payload, expect_errors=True) + def test_creates_public_node_pointer_logged_out(self, app, public_url, public_pointer_project, make_payload): + public_payload = make_payload(id=public_pointer_project._id) + res = app.post_json_api(public_url, public_payload, expect_errors=True) assert res.status_code == 401 assert 'detail' in res.json['errors'][0] - @assert_logs(NodeLog.POINTER_CREATED, 'public_project') - def test_creates_public_node_pointer_logged_in(self): - res = self.app.post_json_api(self.public_url, self.public_payload, auth=self.user_two.auth, expect_errors=True) - assert res.status_code == 403 - assert 'detail' in res.json['errors'][0] - - res = self.app.post_json_api(self.public_url, self.public_payload, auth=self.user.auth) - assert res.status_code == 201 - assert res.content_type == 'application/vnd.api+json' - res_json = res.json['data'] - embedded = res_json['embeds']['target_node']['data']['id'] - assert embedded == self.public_pointer_project._id - - def test_creates_private_node_pointer_logged_out(self): - res = self.app.post_json_api(self.private_url, self.private_payload, expect_errors=True) + def test_creates_public_node_pointer_logged_in(self, app, user, user_two, public_project, public_pointer_project, public_url, make_payload): + public_payload = make_payload(id=public_pointer_project._id) + with assert_latest_log(NodeLog.POINTER_CREATED, public_project): + res = app.post_json_api(public_url, public_payload, auth=user_two.auth, expect_errors=True) + assert res.status_code == 403 + assert 'detail' in res.json['errors'][0] + + res = app.post_json_api(public_url, public_payload, auth=user.auth) + assert res.status_code == 201 + assert res.content_type == 'application/vnd.api+json' + res_json = res.json['data'] + embedded = res_json['embeds']['target_node']['data']['id'] + assert embedded == public_pointer_project._id + + def test_creates_private_node_pointer_logged_out(self, app, private_pointer_project, private_url, make_payload): + private_payload = make_payload(id=private_pointer_project._id) + res = app.post_json_api(private_url, private_payload, expect_errors=True) assert res.status_code == 401 assert 'detail' in res.json['errors'][0] - def test_creates_private_node_pointer_logged_in_contributor(self): - res = self.app.post_json_api(self.private_url, self.private_payload, auth=self.user.auth) + def test_creates_private_node_pointer_logged_in_contributor(self, app, user, private_pointer_project, private_url, make_payload): + private_payload = make_payload(id=private_pointer_project._id) + res = app.post_json_api(private_url, private_payload, auth=user.auth) assert res.status_code == 201 res_json = res.json['data'] embedded = res_json['embeds']['target_node']['data']['id'] - assert embedded == self.pointer_project._id + assert embedded == private_pointer_project._id assert res.content_type == 'application/vnd.api+json' - def test_creates_private_node_pointer_logged_in_non_contributor(self): - res = self.app.post_json_api(self.private_url, self.private_payload, auth=self.user_two.auth, expect_errors=True) + def test_creates_private_node_pointer_logged_in_non_contributor(self, app, user_two, private_pointer_project, private_url, make_payload): + private_payload = make_payload(id=private_pointer_project._id) + res = app.post_json_api(private_url, private_payload, auth=user_two.auth, expect_errors=True) assert res.status_code == 403 assert 'detail' in res.json['errors'][0] - def test_create_node_pointer_non_contributing_node_to_contributing_node(self): - res = self.app.post_json_api(self.private_url, self.user_two_payload, auth=self.user_two.auth, expect_errors=True) + def test_create_node_pointer_non_contributing_node_to_contributing_node(self, app, user_two, user_two_project, private_url, make_payload): + user_two_payload = make_payload(id=user_two_project._id) + res = app.post_json_api(private_url, user_two_payload, auth=user_two.auth, expect_errors=True) assert res.status_code == 403 assert 'detail' in res.json['errors'][0] - @assert_logs(NodeLog.POINTER_CREATED, 'project') - def test_create_node_pointer_contributing_node_to_non_contributing_node(self): - res = self.app.post_json_api(self.private_url, self.user_two_payload, auth=self.user.auth) - assert res.status_code == 201 - assert res.content_type == 'application/vnd.api+json' - res_json = res.json['data'] - embedded = res_json['embeds']['target_node']['data']['id'] - assert embedded == self.user_two_project._id - - def test_create_pointer_non_contributing_node_to_fake_node(self): - res = self.app.post_json_api(self.private_url, self.fake_payload, auth=self.user_two.auth, expect_errors=True) + def test_create_node_pointer_contributing_node_to_non_contributing_node(self, app, user, user_two, user_two_project, private_project, private_url, make_payload): + with assert_latest_log(NodeLog.POINTER_CREATED, private_project): + user_two_payload = make_payload(id=user_two_project._id) + res = app.post_json_api(private_url, user_two_payload, auth=user.auth) + assert res.status_code == 201 + assert res.content_type == 'application/vnd.api+json' + res_json = res.json['data'] + embedded = res_json['embeds']['target_node']['data']['id'] + assert embedded == user_two_project._id + + def test_create_pointer_non_contributing_node_to_fake_node(self, app, user_two, private_url, make_payload): + fake_payload = make_payload() + res = app.post_json_api(private_url, fake_payload, auth=user_two.auth, expect_errors=True) assert res.status_code == 403 assert 'detail' in res.json['errors'][0] - def test_create_pointer_contributing_node_to_fake_node(self): - res = self.app.post_json_api(self.private_url, self.fake_payload, auth=self.user.auth, expect_errors=True) + def test_create_pointer_contributing_node_to_fake_node(self, app, user, private_url, make_payload): + fake_payload = make_payload() + res = app.post_json_api(private_url, fake_payload, auth=user.auth, expect_errors=True) assert res.status_code == 400 assert 'detail' in res.json['errors'][0] - def test_create_fake_node_pointing_to_contributing_node(self): - res = self.app.post_json_api(self.fake_url, self.private_payload, auth=self.user.auth, expect_errors=True) + def test_create_fake_node_pointing_to_contributing_node(self, app, user, user_two, private_pointer_project, fake_url, make_payload): + private_payload = make_payload(id=private_pointer_project._id) + res = app.post_json_api(fake_url, private_payload, auth=user.auth, expect_errors=True) assert res.status_code == 404 assert 'detail' in res.json['errors'][0] - res = self.app.post_json_api(self.fake_url, self.private_payload, auth=self.user_two.auth, expect_errors=True) + res = app.post_json_api(fake_url, private_payload, auth=user_two.auth, expect_errors=True) assert res.status_code == 404 assert 'detail' in res.json['errors'][0] - @assert_logs(NodeLog.POINTER_CREATED, 'public_project') - def test_create_node_pointer_to_itself(self): - res = self.app.post_json_api(self.public_url, self.point_to_itself_payload, auth=self.user.auth) - res_json = res.json['data'] - assert res.status_code == 201 - assert res.content_type == 'application/vnd.api+json' - embedded = res_json['embeds']['target_node']['data']['id'] - assert embedded == self.public_project._id - - def test_create_node_pointer_to_itself_unauthorized(self): - res = self.app.post_json_api(self.public_url, self.point_to_itself_payload, auth=self.user_two.auth, expect_errors=True) + def test_create_node_pointer_to_itself(self, app, user, public_project, public_url, make_payload): + with assert_latest_log(NodeLog.POINTER_CREATED, public_project): + point_to_itself_payload = make_payload(id=public_project._id) + res = app.post_json_api(public_url, point_to_itself_payload, auth=user.auth) + res_json = res.json['data'] + assert res.status_code == 201 + assert res.content_type == 'application/vnd.api+json' + embedded = res_json['embeds']['target_node']['data']['id'] + assert embedded == public_project._id + + def test_create_node_pointer_errors(self, app, user, user_two, public_project, user_two_project, public_pointer_project, public_url, private_url, make_payload): + + # test_create_node_pointer_to_itself_unauthorized + point_to_itself_payload = make_payload(id=public_project._id) + res = app.post_json_api(public_url, point_to_itself_payload, auth=user_two.auth, expect_errors=True) assert res.status_code == 403 assert 'detail' in res.json['errors'][0] - @assert_logs(NodeLog.POINTER_CREATED, 'public_project') - def test_create_node_pointer_already_connected(self): - res = self.app.post_json_api(self.public_url, self.public_payload, auth=self.user.auth) - assert res.status_code == 201 - assert res.content_type == 'application/vnd.api+json' - res_json = res.json['data'] - embedded = res_json['embeds']['target_node']['data']['id'] - assert embedded == self.public_pointer_project._id - - res = self.app.post_json_api(self.public_url, self.public_payload, auth=self.user.auth, expect_errors=True) - assert res.status_code == 400 - assert 'detail' in res.json['errors'][0] - - def test_cannot_add_link_to_registration(self): - registration = RegistrationFactory(creator=self.user) - - url = '/{}nodes/{}/node_links/'.format(API_BASE, registration._id) - payload = { - 'data': { - 'type': 'node_links', - 'relationships': { - 'nodes': { - 'data': { - 'id': self.public_pointer_project._id, - 'type': 'nodes' - } - } - } - } - } - res = self.app.post_json_api(url, payload, auth=self.user.auth, expect_errors=True) - assert res.status_code == 404 - - def test_create_node_pointer_no_type(self): + # test_create_node_pointer_already_connected + with assert_latest_log(NodeLog.POINTER_CREATED, public_project): + public_payload = make_payload(id=public_pointer_project._id) + res = app.post_json_api(public_url, public_payload, auth=user.auth) + assert res.status_code == 201 + assert res.content_type == 'application/vnd.api+json' + res_json = res.json['data'] + embedded = res_json['embeds']['target_node']['data']['id'] + assert embedded == public_pointer_project._id + + res = app.post_json_api(public_url, public_payload, auth=user.auth, expect_errors=True) + assert res.status_code == 400 + assert 'detail' in res.json['errors'][0] + + # test_create_node_pointer_no_type payload = { 'data': { 'relationships': { 'nodes': { 'data': { - 'id': self.user_two_project._id, + 'id': user_two_project._id, 'type': 'nodes' } } } } } - res = self.app.post_json_api(self.private_url, payload, auth=self.user.auth, expect_errors=True) + res = app.post_json_api(private_url, payload, auth=user.auth, expect_errors=True) assert res.status_code == 400 assert res.json['errors'][0]['detail'] == 'This field may not be null.' assert res.json['errors'][0]['source']['pointer'] == '/data/type' - def test_create_node_pointer_incorrect_type(self): + # test_create_node_pointer_incorrect_type payload = { 'data': { 'type': 'Wrong type.', 'relationships': { 'nodes': { 'data': { - 'id': self.user_two_project._id, + 'id': user_two_project._id, 'type': 'nodes' } } } } } - res = self.app.post_json_api(self.private_url, payload, auth=self.user.auth, expect_errors=True) + res = app.post_json_api(private_url, payload, auth=user.auth, expect_errors=True) assert res.status_code == 409 assert res.json['errors'][0]['detail'] == 'This resource has a type of "node_links", but you set the json body\'s type field to "Wrong type.". You probably need to change the type field to match the resource\'s type.' + def test_cannot_add_link_to_registration(self, app, user, public_pointer_project, make_payload): + registration = RegistrationFactory(creator=user) + url = '/{}nodes/{}/node_links/'.format(API_BASE, registration._id) + payload = make_payload(id=public_pointer_project._id) + + res = app.post_json_api(url, payload, auth=user.auth, expect_errors=True) + assert res.status_code == 404 + @pytest.mark.django_db class TestNodeLinksBulkCreate: - @pytest.fixture(autouse=True) - def setUp(self): - self.app = JSONAPITestApp() - self.user = AuthUserFactory() + @pytest.fixture() + def user_two(self): + return AuthUserFactory() + + @pytest.fixture() + def private_project(self, user): + return ProjectFactory(is_public=False, creator=user) + + @pytest.fixture() + def private_pointer_project_one(self, user): + return ProjectFactory(is_public=False, creator=user) + + @pytest.fixture() + def private_pointer_project_two(self, user): + return ProjectFactory(is_public=False, creator=user) + + @pytest.fixture() + def private_url(self, private_project): + return '/{}nodes/{}/node_links/'.format(API_BASE, private_project._id) - self.private_project = ProjectFactory(is_public=False, creator=self.user) - self.private_pointer_project = ProjectFactory(is_public=False, creator=self.user) - self.private_pointer_project_two = ProjectFactory(is_public=False, creator=self.user) + @pytest.fixture() + def public_project(self, user): + return ProjectFactory(is_public=True, creator=user) - self.private_url = '/{}nodes/{}/node_links/'.format(API_BASE, self.private_project._id) + @pytest.fixture() + def public_pointer_project_one(self, user): + return ProjectFactory(is_public=True, creator=user) - self.private_payload = { + @pytest.fixture() + def public_pointer_project_two(self, user): + return ProjectFactory(is_public=True, creator=user) + + @pytest.fixture() + def public_url(self, public_project): + return '/{}nodes/{}/node_links/'.format(API_BASE, public_project._id) + + @pytest.fixture() + def user_two_project(self, user_two): + return ProjectFactory(is_public=True, creator=user_two) + + @pytest.fixture() + def user_two_url(self, user_two_project): + return '/{}nodes/{}/node_links/'.format(API_BASE, user_two_project._id) + + @pytest.fixture() + def private_payload(self, private_pointer_project_one, private_pointer_project_two): + return { 'data': [{ 'type': 'node_links', 'relationships': { 'nodes': { 'data': { - 'id': self.private_pointer_project._id, + 'id': private_pointer_project_one._id, 'type': 'nodes' } } - } }, { @@ -516,31 +551,26 @@ def setUp(self): 'relationships': { 'nodes': { 'data': { - 'id': self.private_pointer_project_two._id, + 'id': private_pointer_project_two._id, 'type': 'nodes' } } - } }] } - self.public_project = ProjectFactory(is_public=True, creator=self.user) - self.public_pointer_project = ProjectFactory(is_public=True, creator=self.user) - self.public_pointer_project_two = ProjectFactory(is_public=True, creator=self.user) - - self.public_url = '/{}nodes/{}/node_links/'.format(API_BASE, self.public_project._id) - self.public_payload = { + @pytest.fixture() + def public_payload(self, public_pointer_project_one, public_pointer_project_two): + return { 'data': [{ 'type': 'node_links', 'relationships': { 'nodes': { 'data': { - 'id': self.public_pointer_project._id, + 'id': public_pointer_project_one._id, 'type': 'nodes' } } - } }, { @@ -548,396 +578,420 @@ def setUp(self): 'relationships': { 'nodes': { 'data': { - 'id': self.public_pointer_project_two._id, + 'id': public_pointer_project_two._id, 'type': 'nodes' } } - } }] } - self.user_two = AuthUserFactory() - self.user_two_project = ProjectFactory(is_public=True, creator=self.user_two) - self.user_two_url = '/{}nodes/{}/node_links/'.format(API_BASE, self.user_two_project._id) - self.user_two_payload = {'data': [{ - 'type': 'node_links', - 'relationships': { - 'nodes': { - 'data': { - 'id': self.user_two_project._id, - 'type': 'nodes' - } + @pytest.fixture() + def user_two_payload(self, user_two_project): + return { + 'data': [{ + 'type': 'node_links', + 'relationships': { + 'nodes': { + 'data': { + 'id': user_two_project._id, + 'type': 'nodes' + } + } } - } + }] } - ]} - def test_bulk_create_node_links_blank_request(self): - res = self.app.post_json_api(self.public_url, auth=self.user.auth, expect_errors=True, bulk=True) + def test_bulk_create_errors(self, app, user, user_two, public_project, user_two_project, public_pointer_project_one, public_pointer_project_two, private_pointer_project_one, public_url, private_url, public_payload, private_payload, user_two_payload): + + # test_bulk_create_node_links_blank_request + res = app.post_json_api(public_url, auth=user.auth, expect_errors=True, bulk=True) assert res.status_code == 400 - def test_bulk_creates_pointers_limits(self): - payload = {'data': [self.public_payload['data'][0]] * 101} - res = self.app.post_json_api(self.public_url, payload, auth=self.user.auth, expect_errors=True, bulk=True) + # test_bulk_creates_pointers_limits + payload = {'data': [public_payload['data'][0]] * 101} + res = app.post_json_api(public_url, payload, auth=user.auth, expect_errors=True, bulk=True) assert res.status_code == 400 assert res.json['errors'][0]['detail'] == 'Bulk operation limit is 100, got 101.' assert res.json['errors'][0]['source']['pointer'] == '/data' - res = self.app.get(self.public_url) + res = app.get(public_url) assert res.json['data'] == [] - def test_bulk_creates_project_target_not_nested(self): - payload = {'data': [{'type': 'node_links', 'target_node_id': self.private_pointer_project._id}]} - res = self.app.post_json_api(self.public_url, payload, auth=self.user_two.auth, expect_errors=True, bulk=True) + # test_bulk_creates_project_target_not_nested + payload = {'data': [{'type': 'node_links', 'target_node_id': private_pointer_project_one._id}]} + res = app.post_json_api(public_url, payload, auth=user_two.auth, expect_errors=True, bulk=True) assert res.status_code == 400 assert res.json['errors'][0]['source']['pointer'] == '/data/relationships' assert res.json['errors'][0]['detail'] == 'Request must include /data/relationships.' - def test_bulk_creates_public_node_pointers_logged_out(self): - res = self.app.post_json_api(self.public_url, self.public_payload, expect_errors=True, bulk=True) + # test_bulk_creates_public_node_pointers_logged_out + res = app.post_json_api(public_url, public_payload, expect_errors=True, bulk=True) assert res.status_code == 401 assert 'detail' in res.json['errors'][0] - res = self.app.get(self.public_url) + res = app.get(public_url) assert res.json['data'] == [] - def test_bulk_creates_public_node_pointer_logged_in_non_contrib(self): - res = self.app.post_json_api(self.public_url, self.public_payload, - auth=self.user_two.auth, expect_errors=True, bulk=True) + # test_bulk_creates_public_node_pointer_logged_in_non_contrib + res = app.post_json_api(public_url, public_payload, + auth=user_two.auth, expect_errors=True, bulk=True) assert res.status_code == 403 - @assert_logs(NodeLog.POINTER_CREATED, 'public_project') - def test_bulk_creates_public_node_pointer_logged_in_contrib(self): - res = self.app.post_json_api(self.public_url, self.public_payload, auth=self.user.auth, bulk=True) - assert res.status_code == 201 - assert res.content_type == 'application/vnd.api+json' - res_json = res.json['data'] - embedded = res_json[0]['embeds']['target_node']['data']['id'] - assert embedded == self.public_pointer_project._id - - embedded = res_json[1]['embeds']['target_node']['data']['id'] - assert embedded == self.public_pointer_project_two._id - - - def test_bulk_creates_private_node_pointers_logged_out(self): - res = self.app.post_json_api(self.private_url, self.private_payload, expect_errors=True, bulk=True) + # test_bulk_creates_private_node_pointers_logged_out + res = app.post_json_api(private_url, private_payload, expect_errors=True, bulk=True) assert res.status_code == 401 assert 'detail' in res.json['errors'][0] - res = self.app.get(self.private_url, auth=self.user.auth) + res = app.get(private_url, auth=user.auth) assert res.json['data'] == [] - @assert_logs(NodeLog.POINTER_CREATED, 'private_project', index=-1) - @assert_logs(NodeLog.POINTER_CREATED, 'private_project') - def test_bulk_creates_private_node_pointer_logged_in_contributor(self): - res = self.app.post_json_api(self.private_url, self.private_payload, auth=self.user.auth, bulk=True) - assert res.status_code == 201 - res_json = res.json['data'] - embedded = res_json[0]['embeds']['target_node']['data']['id'] - assert embedded == self.private_pointer_project._id - - embedded = res_json[1]['embeds']['target_node']['data']['id'] - assert embedded == self.private_pointer_project_two._id - assert res.content_type == 'application/vnd.api+json' - - def test_bulk_creates_private_node_pointers_logged_in_non_contributor(self): - res = self.app.post_json_api(self.private_url, self.private_payload, - auth=self.user_two.auth, expect_errors=True, bulk=True) + # test_bulk_creates_private_node_pointers_logged_in_non_contributor + res = app.post_json_api(private_url, private_payload, + auth=user_two.auth, expect_errors=True, bulk=True) assert res.status_code == 403 assert 'detail' in res.json['errors'][0] - res = self.app.get(self.private_url, auth=self.user.auth) + res = app.get(private_url, auth=user.auth) assert res.json['data'] == [] - def test_bulk_creates_node_pointers_non_contributing_node_to_contributing_node(self): - res = self.app.post_json_api(self.private_url, self.user_two_payload, - auth=self.user_two.auth, expect_errors=True, bulk=True) + # test_bulk_creates_node_pointers_non_contributing_node_to_contributing_node + res = app.post_json_api(private_url, user_two_payload, + auth=user_two.auth, expect_errors=True, bulk=True) assert res.status_code == 403 assert 'detail' in res.json['errors'][0] - @assert_logs(NodeLog.POINTER_CREATED, 'private_project') - def test_bulk_creates_node_pointers_contributing_node_to_non_contributing_node(self): - res = self.app.post_json_api(self.private_url, self.user_two_payload, auth=self.user.auth, bulk=True) - assert res.status_code == 201 - assert res.content_type == 'application/vnd.api+json' - res_json = res.json['data'] - embedded = res_json[0]['embeds']['target_node']['data']['id'] - assert embedded == self.user_two_project._id + # test_bulk_creates_pointers_non_contributing_node_to_fake_node + fake_payload = {'data': [{'type': 'node_links', 'relationships': {'nodes': {'data': {'id': 'rheis', 'type': 'nodes'}}}}]} - res = self.app.get(self.private_url, auth=self.user.auth) - res_json = res.json['data'] - embedded = res_json[0]['embeds']['target_node']['data']['id'] - assert embedded == self.user_two_project._id - - def test_bulk_creates_pointers_non_contributing_node_to_fake_node(self): - fake_payload = {'data': [{'type': 'node_links', 'relationships': {'nodes': {'data': {'id': 'fdxlq', 'type': 'nodes'}}}}]} - - res = self.app.post_json_api(self.private_url, fake_payload, - auth=self.user_two.auth, expect_errors=True, bulk=True) + res = app.post_json_api(private_url, fake_payload, + auth=user_two.auth, expect_errors=True, bulk=True) assert res.status_code == 403 assert 'detail' in res.json['errors'][0] - def test_bulk_creates_pointers_contributing_node_to_fake_node(self): - fake_payload = {'data': [{'type': 'node_links', 'relationships': {'nodes': {'data': {'id': 'fdxlq', 'type': 'nodes'}}}}]} + # test_bulk_creates_pointers_contributing_node_to_fake_node + fake_payload = {'data': [{'type': 'node_links', 'relationships': {'nodes': {'data': {'id': 'rheis', 'type': 'nodes'}}}}]} - res = self.app.post_json_api(self.private_url, fake_payload, - auth=self.user.auth, expect_errors=True, bulk=True) + res = app.post_json_api(private_url, fake_payload, + auth=user.auth, expect_errors=True, bulk=True) assert res.status_code == 400 assert 'detail' in res.json['errors'][0] - def test_bulk_creates_fake_nodes_pointing_to_contributing_node(self): - fake_url = '/{}nodes/{}/node_links/'.format(API_BASE, 'fdxlq') + # test_bulk_creates_fake_nodes_pointing_to_contributing_node + fake_url = '/{}nodes/{}/node_links/'.format(API_BASE, 'rheis') - res = self.app.post_json_api(fake_url, self.private_payload, auth=self.user.auth, expect_errors=True, bulk=True) + res = app.post_json_api(fake_url, private_payload, auth=user.auth, expect_errors=True, bulk=True) assert res.status_code == 404 assert 'detail' in res.json['errors'][0] - res = self.app.post_json_api(fake_url, self.private_payload, auth=self.user_two.auth, expect_errors=True, bulk=True) + res = app.post_json_api(fake_url, private_payload, auth=user_two.auth, expect_errors=True, bulk=True) assert res.status_code == 404 assert 'detail' in res.json['errors'][0] - @assert_logs(NodeLog.POINTER_CREATED, 'public_project') - def test_bulk_creates_node_pointer_to_itself(self): - point_to_itself_payload = {'data': [{'type': 'node_links', 'relationships': {'nodes': {'data': {'type': 'nodes', 'id': self.public_project._id}}}}]} - - res = self.app.post_json_api(self.public_url, point_to_itself_payload, auth=self.user.auth, bulk=True) - assert res.status_code == 201 - assert res.content_type == 'application/vnd.api+json' - res_json = res.json['data'] - embedded = res_json[0]['embeds']['target_node']['data']['id'] - assert embedded == self.public_project._id + # test_bulk_creates_node_pointer_to_itself_unauthorized + point_to_itself_payload = {'data': [{'type': 'node_links', 'relationships': {'nodes': {'data': {'type': 'nodes', 'id': public_project._id}}}}]} - def test_bulk_creates_node_pointer_to_itself_unauthorized(self): - point_to_itself_payload = {'data': [{'type': 'node_links', 'relationships': {'nodes': {'data': {'type': 'nodes', 'id': self.public_project._id}}}}]} - - res = self.app.post_json_api(self.public_url, point_to_itself_payload, bulk=True, auth=self.user_two.auth, + res = app.post_json_api(public_url, point_to_itself_payload, bulk=True, auth=user_two.auth, expect_errors=True) assert res.status_code == 403 assert 'detail' in res.json['errors'][0] - @assert_logs(NodeLog.POINTER_CREATED, 'public_project') - @assert_logs(NodeLog.POINTER_CREATED, 'public_project', index=-1) - def test_bulk_creates_node_pointer_already_connected(self): - res = self.app.post_json_api(self.public_url, self.public_payload, auth=self.user.auth, bulk=True) - assert res.status_code == 201 - assert res.content_type == 'application/vnd.api+json' - res_json = res.json['data'] - embedded = res_json[0]['embeds']['target_node']['data']['id'] - assert embedded == self.public_pointer_project._id - - embedded_two = res_json[1]['embeds']['target_node']['data']['id'] - assert embedded_two == self.public_pointer_project_two._id - - res = self.app.post_json_api(self.public_url, self.public_payload, auth=self.user.auth, expect_errors=True, bulk=True) - assert res.status_code == 400 - assert 'Target Node \'{}\' already pointed to by \'{}\'.'.format(self.public_pointer_project._id, self.public_project._id) in res.json['errors'][0]['detail'] - - def test_bulk_cannot_add_link_to_registration(self): - registration = RegistrationFactory(creator=self.user) - - url = '/{}nodes/{}/node_links/'.format(API_BASE, registration._id) - payload = {'data': [{'type': 'node_links', 'relationships': {'nodes': {'data': {'type': 'nodes', 'id': self.public_pointer_project._id}}}}]} - res = self.app.post_json_api(url, payload, auth=self.user.auth, expect_errors=True, bulk=True) - assert res.status_code == 404 - - def test_bulk_creates_node_pointer_no_type(self): - payload = {'data': [{'relationships': {'nodes': {'data': {'type': 'nodes', 'id': self.user_two_project._id}}}}]} - res = self.app.post_json_api(self.private_url, payload, auth=self.user.auth, expect_errors=True, bulk=True) + # test_bulk_creates_node_pointer_no_type + payload = {'data': [{'relationships': {'nodes': {'data': {'type': 'nodes', 'id': user_two_project._id}}}}]} + res = app.post_json_api(private_url, payload, auth=user.auth, expect_errors=True, bulk=True) assert res.status_code == 400 assert res.json['errors'][0]['detail'] == 'This field may not be null.' assert res.json['errors'][0]['source']['pointer'] == '/data/0/type' - def test_bulk_creates_node_pointer_incorrect_type(self): - payload = {'data': [{'type': 'Wrong type.', 'relationships': {'nodes': {'data': {'type': 'nodes', 'id': self.user_two_project._id}}}}]} - res = self.app.post_json_api(self.private_url, payload, auth=self.user.auth, expect_errors=True, bulk=True) + # test_bulk_creates_node_pointer_incorrect_type + payload = {'data': [{'type': 'Wrong type.', 'relationships': {'nodes': {'data': {'type': 'nodes', 'id': user_two_project._id}}}}]} + res = app.post_json_api(private_url, payload, auth=user.auth, expect_errors=True, bulk=True) assert res.status_code == 409 assert res.json['errors'][0]['detail'] == 'This resource has a type of "node_links", but you set the json body\'s type field to "Wrong type.". You probably need to change the type field to match the resource\'s type.' -@pytest.mark.django_db -class TestBulkDeleteNodeLinks: - - @pytest.fixture(autouse=True) - def setUp(self): - self.app = JSONAPITestApp() - self.user = AuthUserFactory() - self.project = ProjectFactory(creator=self.user, is_public=False) - self.pointer_project = ProjectFactory(creator=self.user, is_public=True) - self.pointer_project_two = ProjectFactory(creator=self.user, is_public=True) - - self.pointer = self.project.add_pointer(self.pointer_project, auth=Auth(self.user), save=True) - self.pointer_two = self.project.add_pointer(self.pointer_project_two, auth=Auth(self.user), save=True) - - self.private_payload = { - 'data': [ - {'type': 'node_links', 'id': self.pointer._id}, - {'type': 'node_links', 'id': self.pointer_two._id} - ] - } + def test_bulk_creates_public_node_pointer_logged_in_contrib(self, app, user, public_project, public_pointer_project_one, public_pointer_project_two, public_url, public_payload): + with assert_latest_log(NodeLog.POINTER_CREATED, public_project): + res = app.post_json_api(public_url, public_payload, auth=user.auth, bulk=True) + assert res.status_code == 201 + assert res.content_type == 'application/vnd.api+json' + res_json = res.json['data'] + embedded = res_json[0]['embeds']['target_node']['data']['id'] + assert embedded == public_pointer_project_one._id + + embedded = res_json[1]['embeds']['target_node']['data']['id'] + assert embedded == public_pointer_project_two._id + + def test_bulk_creates_private_node_pointer_logged_in_contributor(self, app, user, private_project, private_payload, private_pointer_project_one, private_pointer_project_two, private_url): + with assert_latest_log(NodeLog.POINTER_CREATED, private_project): + res = app.post_json_api(private_url, private_payload, auth=user.auth, bulk=True) + assert res.status_code == 201 + res_json = res.json['data'] + embedded = res_json[0]['embeds']['target_node']['data']['id'] + assert embedded == private_pointer_project_one._id + + embedded = res_json[1]['embeds']['target_node']['data']['id'] + assert embedded == private_pointer_project_two._id + assert res.content_type == 'application/vnd.api+json' + + def test_bulk_creates_node_pointers_contributing_node_to_non_contributing_node(self, app, user, user_two, private_project, user_two_project, user_two_payload, private_url): + with assert_latest_log(NodeLog.POINTER_CREATED, private_project): + res = app.post_json_api(private_url, user_two_payload, auth=user.auth, bulk=True) + assert res.status_code == 201 + assert res.content_type == 'application/vnd.api+json' + res_json = res.json['data'] + embedded = res_json[0]['embeds']['target_node']['data']['id'] + assert embedded == user_two_project._id + + res = app.get(private_url, auth=user.auth) + res_json = res.json['data'] + embedded = res_json[0]['embeds']['target_node']['data']['id'] + assert embedded == user_two_project._id + + def test_bulk_creates_node_pointer_to_itself(self, app, user, public_project, public_url): + with assert_latest_log(NodeLog.POINTER_CREATED, public_project): + point_to_itself_payload = {'data': [{'type': 'node_links', 'relationships': {'nodes': {'data': {'type': 'nodes', 'id': public_project._id}}}}]} + + res = app.post_json_api(public_url, point_to_itself_payload, auth=user.auth, bulk=True) + assert res.status_code == 201 + assert res.content_type == 'application/vnd.api+json' + res_json = res.json['data'] + embedded = res_json[0]['embeds']['target_node']['data']['id'] + assert embedded == public_project._id + + def test_bulk_creates_node_pointer_already_connected(self, app, user, public_project, public_pointer_project_one, public_pointer_project_two, public_url, public_payload): + with assert_latest_log(NodeLog.POINTER_CREATED, public_project): + res = app.post_json_api(public_url, public_payload, auth=user.auth, bulk=True) + assert res.status_code == 201 + assert res.content_type == 'application/vnd.api+json' + res_json = res.json['data'] + embedded = res_json[0]['embeds']['target_node']['data']['id'] + assert embedded == public_pointer_project_one._id + + embedded_two = res_json[1]['embeds']['target_node']['data']['id'] + assert embedded_two == public_pointer_project_two._id + + res = app.post_json_api(public_url, public_payload, auth=user.auth, expect_errors=True, bulk=True) + assert res.status_code == 400 + assert 'Target Node \'{}\' already pointed to by \'{}\'.'.format(public_pointer_project_one._id, public_project._id) in res.json['errors'][0]['detail'] + + def test_bulk_cannot_add_link_to_registration(self, app, user, public_pointer_project_one): + registration = RegistrationFactory(creator=user) - self.private_url = '/{}nodes/{}/node_links/'.format(API_BASE, self.project._id) + url = '/{}nodes/{}/node_links/'.format(API_BASE, registration._id) + payload = {'data': [{'type': 'node_links', 'relationships': {'nodes': {'data': {'type': 'nodes', 'id': public_pointer_project_one._id}}}}]} + res = app.post_json_api(url, payload, auth=user.auth, expect_errors=True, bulk=True) + assert res.status_code == 404 - self.user_two = AuthUserFactory() +@pytest.mark.django_db +class TestBulkDeleteNodeLinks: - self.public_project = ProjectFactory(is_public=True, creator=self.user) - self.public_pointer_project = ProjectFactory(is_public=True, creator=self.user) - self.public_pointer_project_two = ProjectFactory(is_public=True, creator=self.user) + @pytest.fixture() + def non_contrib(self): + return AuthUserFactory() + + @pytest.fixture() + def private_project(self, user): + return ProjectFactory(creator=user, is_public=False) + + @pytest.fixture() + def private_project_pointer_project_one(self, user): + return ProjectFactory(creator=user, is_public=True) + + @pytest.fixture() + def private_project_pointer_project_two(self, user): + return ProjectFactory(creator=user, is_public=True) + + @pytest.fixture() + def private_pointer_one(self, user, private_project, private_project_pointer_project_one): + return private_project.add_pointer(private_project_pointer_project_one, auth=Auth(user), save=True) + + @pytest.fixture() + def private_pointer_two(self, user, private_project, private_project_pointer_project_two): + return private_project.add_pointer(private_project_pointer_project_two, auth=Auth(user), save=True) + + @pytest.fixture() + def private_payload(self, private_pointer_one, private_pointer_two): + return { + 'data': [ + {'type': 'node_links', 'id': private_pointer_one._id}, + {'type': 'node_links', 'id': private_pointer_two._id} + ] + } - self.public_pointer = self.public_project.add_pointer(self.public_pointer_project, - auth=Auth(self.user), - save=True) - self.public_pointer_two = self.public_project.add_pointer(self.public_pointer_project_two, - auth=Auth(self.user), - save=True) + @pytest.fixture() + def private_url(self, private_project): + return '/{}nodes/{}/node_links/'.format(API_BASE, private_project._id) + + @pytest.fixture() + def public_project(self, user): + return ProjectFactory(is_public=True, creator=user) + + @pytest.fixture() + def public_project_pointer_project_one(self, user): + return ProjectFactory(is_public=True, creator=user) + + @pytest.fixture() + def public_project_pointer_project_two(self, user): + return ProjectFactory(is_public=True, creator=user) + + @pytest.fixture() + def public_pointer_one(self, user, public_project, public_project_pointer_project_one): + return public_project.add_pointer(public_project_pointer_project_one, auth=Auth(user), save=True) + + @pytest.fixture() + def public_pointer_two(self, user, public_project, public_project_pointer_project_two): + return public_project.add_pointer(public_project_pointer_project_two, auth=Auth(user), save=True) + + @pytest.fixture() + def public_payload(self, public_pointer_one, public_pointer_two): + return { + 'data': [ + {'type': 'node_links', 'id': public_pointer_one._id}, + {'type': 'node_links', 'id': public_pointer_two._id} + ] + } - self.public_payload = { - 'data': [ - {'type': 'node_links', 'id': self.public_pointer._id}, - {'type': 'node_links', 'id': self.public_pointer_two._id} - ] - } + @pytest.fixture() + def public_url(self, public_project): + return '/{}nodes/{}/node_links/'.format(API_BASE, public_project._id) - self.public_url = '/{}nodes/{}/node_links/'.format(API_BASE, self.public_project._id) + def test_bulk_delete_errors(self, app, user, non_contrib, public_project, public_pointer_one, public_pointer_two, public_project_pointer_project_one, public_project_pointer_project_two, public_url, private_url, public_payload, private_payload): - def test_bulk_delete_node_links_blank_request(self): - res = self.app.delete_json_api(self.public_url, auth=self.user.auth, expect_errors=True, bulk=True) + # test_bulk_delete_node_links_blank_request + res = app.delete_json_api(public_url, auth=user.auth, expect_errors=True, bulk=True) assert res.status_code == 400 - def test_bulk_delete_pointer_limits(self): - res = self.app.delete_json_api(self.public_url, {'data': [self.public_payload['data'][0]] * 101}, - auth=self.user.auth, expect_errors=True, bulk=True) + # test_bulk_delete_pointer_limits + res = app.delete_json_api(public_url, {'data': [public_payload['data'][0]] * 101}, + auth=user.auth, expect_errors=True, bulk=True) assert res.status_code == 400 assert res.json['errors'][0]['detail'] == 'Bulk operation limit is 100, got 101.' assert res.json['errors'][0]['source']['pointer'] == '/data' - def test_bulk_delete_dict_inside_data(self): - res = self.app.delete_json_api(self.public_url, {'data': {'id': self.public_project._id, 'type': 'node_links'}}, - auth=self.user.auth, expect_errors=True, bulk=True) + # test_bulk_delete_dict_inside_data + res = app.delete_json_api(public_url, {'data': {'id': public_project._id, 'type': 'node_links'}}, + auth=user.auth, expect_errors=True, bulk=True) assert res.status_code == 400 assert res.json['errors'][0]['detail'] == 'Expected a list of items but got type "dict".' - def test_bulk_delete_pointers_no_type(self): + # test_bulk_delete_pointers_no_type payload = {'data': [ - {'id': self.public_pointer._id}, - {'id': self.public_pointer_two._id} + {'id': public_project_pointer_project_one._id}, + {'id': public_project_pointer_project_two._id} ]} - res = self.app.delete_json_api(self.public_url, payload, auth=self.user.auth, expect_errors=True, bulk=True) + res = app.delete_json_api(public_url, payload, auth=user.auth, expect_errors=True, bulk=True) assert res.status_code == 400 assert res.json['errors'][0]['source']['pointer'] == '/data/type' - def test_bulk_delete_pointers_incorrect_type(self): + # test_bulk_delete_pointers_incorrect_type payload = {'data': [ - {'id': self.public_pointer._id, 'type': 'Incorrect type.'}, - {'id': self.public_pointer_two._id, 'type': 'Incorrect type.'} + {'id': public_pointer_one._id, 'type': 'Incorrect type.'}, + {'id': public_pointer_two._id, 'type': 'Incorrect type.'} ]} - res = self.app.delete_json_api(self.public_url, payload, auth=self.user.auth, expect_errors=True, bulk=True) + res = app.delete_json_api(public_url, payload, auth=user.auth, expect_errors=True, bulk=True) assert res.status_code == 409 - def test_bulk_delete_pointers_no_id(self): + # test_bulk_delete_pointers_no_id payload = {'data': [ {'type': 'node_links'}, {'type': 'node_links'} ]} - res = self.app.delete_json_api(self.public_url, payload, auth=self.user.auth, expect_errors=True, bulk=True) + res = app.delete_json_api(public_url, payload, auth=user.auth, expect_errors=True, bulk=True) assert res.status_code == 400 assert res.json['errors'][0]['source']['pointer'] == '/data/id' - def test_bulk_delete_pointers_no_data(self): - res = self.app.delete_json_api(self.public_url, auth=self.user.auth, expect_errors=True, bulk=True) + # test_bulk_delete_pointers_no_data + res = app.delete_json_api(public_url, auth=user.auth, expect_errors=True, bulk=True) assert res.status_code == 400 assert res.json['errors'][0]['detail'] == 'Request must contain array of resource identifier objects.' - def test_bulk_delete_pointers_payload_is_empty_dict(self): - res = self.app.delete_json_api(self.public_url, {}, auth=self.user.auth, expect_errors=True, bulk=True) + # test_bulk_delete_pointers_payload_is_empty_dict + res = app.delete_json_api(public_url, {}, auth=user.auth, expect_errors=True, bulk=True) assert res.status_code == 400 assert res.json['errors'][0]['detail'] == 'Request must include /data.' - def test_cannot_delete_if_registration(self): - registration = RegistrationFactory(project=self.public_project) - - url = '/{}registrations/{}/node_links/'.format(API_BASE, registration._id) - - res = self.app.delete_json_api(url, self.public_payload, auth=self.user.auth, expect_errors=True, bulk=True) - assert res.status_code == 405 - - def test_bulk_deletes_public_node_pointers_logged_out(self): - res = self.app.delete_json_api(self.public_url, self.public_payload, expect_errors=True, bulk=True) + # test_bulk_deletes_public_node_pointers_logged_out + res = app.delete_json_api(public_url, public_payload, expect_errors=True, bulk=True) assert res.status_code == 401 assert 'detail' in res.json['errors'][0] - def test_bulk_deletes_public_node_pointers_fails_if_bad_auth(self): - node_count_before = len(self.public_project.nodes_pointer) - res = self.app.delete_json_api(self.public_url, self.public_payload, - auth=self.user_two.auth, expect_errors=True, bulk=True) + # test_bulk_deletes_public_node_pointers_fails_if_bad_auth + node_count_before = len(public_project.nodes_pointer) + res = app.delete_json_api(public_url, public_payload, + auth=non_contrib.auth, expect_errors=True, bulk=True) # This is could arguably be a 405, but we don't need to go crazy with status codes assert res.status_code == 403 assert 'detail' in res.json['errors'][0] - self.public_project.reload() - assert node_count_before == len(self.public_project.nodes_pointer) - - @assert_logs(NodeLog.POINTER_REMOVED, 'public_project') - @assert_logs(NodeLog.POINTER_REMOVED, 'public_project', index=-1) - def test_bulk_deletes_public_node_pointers_succeeds_as_owner(self): - node_count_before = len(self.public_project.nodes_pointer) - res = self.app.delete_json_api(self.public_url, self.public_payload, auth=self.user.auth, bulk=True) - self.public_project.reload() - assert res.status_code == 204 - assert node_count_before - 2 == len(self.public_project.nodes_pointer) - - self.public_project.reload() - - def test_bulk_deletes_private_node_pointers_logged_out(self): - res = self.app.delete_json_api(self.private_url, self.private_payload, expect_errors=True, bulk=True) - assert res.status_code == 401 - assert 'detail' in res.json['errors'][0] + public_project.reload() + assert node_count_before == len(public_project.nodes_pointer) - @assert_logs(NodeLog.POINTER_REMOVED, 'project', index=-1) - @assert_logs(NodeLog.POINTER_REMOVED, 'project') - def test_bulk_deletes_private_node_pointers_logged_in_contributor(self): - res = self.app.delete_json_api(self.private_url, self.private_payload, auth=self.user.auth, bulk=True) - self.project.reload() # Update the model to reflect changes made by post request - assert res.status_code == 204 - assert len(self.project.nodes_pointer) == 0 - - def test_bulk_deletes_private_node_pointers_logged_in_non_contributor(self): - res = self.app.delete_json_api(self.private_url, self.private_payload, - auth=self.user_two.auth, expect_errors=True, bulk=True) + # test_bulk_deletes_private_node_pointers_logged_in_non_contributor + res = app.delete_json_api(private_url, private_payload, + auth=non_contrib.auth, expect_errors=True, bulk=True) assert res.status_code == 403 assert 'detail' in res.json['errors'][0] - @assert_logs(NodeLog.POINTER_REMOVED, 'public_project', index=-1) - @assert_logs(NodeLog.POINTER_REMOVED, 'public_project') - def test_return_bulk_deleted_public_node_pointer(self): - res = self.app.delete_json_api(self.public_url, self.public_payload, auth=self.user.auth, bulk=True) - self.public_project.reload() # Update the model to reflect changes made by post request - assert res.status_code == 204 + # test_bulk_deletes_private_node_pointers_logged_out + res = app.delete_json_api(private_url, private_payload, expect_errors=True, bulk=True) + assert res.status_code == 401 + assert 'detail' in res.json['errors'][0] - pointer_url = '/{}nodes/{}/node_links/{}/'.format(API_BASE, self.public_project._id, self.public_pointer._id) + def test_cannot_delete_if_registration(self, app, user, public_project, public_payload): + registration = RegistrationFactory(project=public_project) - #check that deleted pointer can not be returned - res = self.app.get(pointer_url, auth=self.user.auth, expect_errors=True) - assert res.status_code == 404 + url = '/{}registrations/{}/node_links/'.format(API_BASE, registration._id) - @assert_logs(NodeLog.POINTER_REMOVED, 'project', index=-1) - @assert_logs(NodeLog.POINTER_REMOVED, 'project') - def test_return_bulk_deleted_private_node_pointer(self): - res = self.app.delete_json_api(self.private_url, self.private_payload, auth=self.user.auth, bulk=True) - self.project.reload() # Update the model to reflect changes made by post request - assert res.status_code == 204 + res = app.delete_json_api(url, public_payload, auth=user.auth, expect_errors=True, bulk=True) + assert res.status_code == 405 - pointer_url = '/{}nodes/{}/node_links/{}/'.format(API_BASE, self.project._id, self.pointer._id) + def test_bulk_deletes_public_node_pointers_succeeds_as_owner(self, app, user, public_project, public_url, public_payload): + with assert_latest_log(NodeLog.POINTER_REMOVED, public_project): + node_count_before = len(public_project.nodes_pointer) + res = app.delete_json_api(public_url, public_payload, auth=user.auth, bulk=True) + public_project.reload() + assert res.status_code == 204 + assert node_count_before - 2 == len(public_project.nodes_pointer) - #check that deleted pointer can not be returned - res = self.app.get(pointer_url, auth=self.user.auth, expect_errors=True) - assert res.status_code == 404 + public_project.reload() + + def test_bulk_deletes_private_node_pointers_logged_in_contributor(self, app, user, private_project, private_url, private_payload): + with assert_latest_log(NodeLog.POINTER_REMOVED, private_project): + res = app.delete_json_api(private_url, private_payload, auth=user.auth, bulk=True) + private_project.reload() # Update the model to reflect changes made by post request + assert res.status_code == 204 + assert len(private_project.nodes_pointer) == 0 + + def test_return_bulk_deleted_public_node_pointer(self, app, user, public_project, public_pointer_one, public_url, public_payload): + with assert_latest_log(NodeLog.POINTER_REMOVED, public_project): + res = app.delete_json_api(public_url, public_payload, auth=user.auth, bulk=True) + public_project.reload() # Update the model to reflect changes made by post request + assert res.status_code == 204 + + pointer_url = '/{}nodes/{}/node_links/{}/'.format(API_BASE, public_project._id, public_pointer_one._id) + + #check that deleted pointer can not be returned + res = app.get(pointer_url, auth=user.auth, expect_errors=True) + assert res.status_code == 404 + + def test_return_bulk_deleted_private_node_pointer(self, app, user, private_project, private_pointer_one, private_url, private_payload): + with assert_latest_log(NodeLog.POINTER_REMOVED, private_project): + res = app.delete_json_api(private_url, private_payload, auth=user.auth, bulk=True) + private_project.reload() # Update the model to reflect changes made by post request + assert res.status_code == 204 + + pointer_url = '/{}nodes/{}/node_links/{}/'.format(API_BASE, private_project._id, private_pointer_one._id) + + #check that deleted pointer can not be returned + res = app.get(pointer_url, auth=user.auth, expect_errors=True) + assert res.status_code == 404 # Regression test for https://openscience.atlassian.net/browse/OSF-4322 - def test_bulk_delete_link_that_is_not_linked_to_correct_node(self): - project = ProjectFactory(creator=self.user) + def test_bulk_delete_link_that_is_not_linked_to_correct_node(self, app, user, private_url, public_payload): + project = ProjectFactory(creator=user) # The node link belongs to a different project - res = self.app.delete_json_api( - self.private_url, self.public_payload, - auth=self.user.auth, + res = app.delete_json_api( + private_url, public_payload, + auth=user.auth, expect_errors=True, bulk=True ) diff --git a/api_tests/nodes/views/test_node_logs.py b/api_tests/nodes/views/test_node_logs.py index 2fb28c70e9a..48a667cade2 100644 --- a/api_tests/nodes/views/test_node_logs.py +++ b/api_tests/nodes/views/test_node_logs.py @@ -20,133 +20,157 @@ API_LATEST = 0 API_FIRST = -1 +@pytest.fixture() +def user(): + return AuthUserFactory() + @pytest.mark.django_db class TestNodeLogList: - @pytest.fixture(autouse=True) - def setUp(self): - self.app = JSONAPITestApp() - self.user = AuthUserFactory() - self.contrib = AuthUserFactory() - self.creator = AuthUserFactory() - self.user_auth = Auth(self.user) - self.NodeLogFactory = ProjectFactory() - self.pointer = ProjectFactory() - - self.private_project = ProjectFactory(is_public=False, creator=self.user) - self.private_url = '/{}nodes/{}/logs/?version=2.2'.format(API_BASE, self.private_project._id) - - self.public_project = ProjectFactory(is_public=True, creator=self.user) - self.public_url = '/{}nodes/{}/logs/?version=2.2'.format(API_BASE, self.public_project._id) - - def test_add_tag(self): - user_auth = Auth(self.user) - self.public_project.add_tag('Jeff Spies', auth=user_auth) - assert 'tag_added' == self.public_project.logs.latest().action - res = self.app.get(self.public_url, auth=self.user.auth) + @pytest.fixture() + def contrib(self): + return AuthUserFactory() + + @pytest.fixture() + def creator(self): + return AuthUserFactory() + + @pytest.fixture() + def user_auth(self, user): + return Auth(user) + + @pytest.fixture() + def NodeLogFactory(self): + return ProjectFactory() + + @pytest.fixture() + def pointer(self): + return ProjectFactory() + + @pytest.fixture() + def private_project(self, user): + return ProjectFactory(is_public=False, creator=user) + + @pytest.fixture() + def private_url(self, private_project): + return '/{}nodes/{}/logs/?version=2.2'.format(API_BASE, private_project._id) + + @pytest.fixture() + def public_project(self, user): + return ProjectFactory(is_public=True, creator=user) + + @pytest.fixture() + def public_url(self, public_project): + return '/{}nodes/{}/logs/?version=2.2'.format(API_BASE, public_project._id) + + def test_add_tag(self, app, user, user_auth, public_project, public_url): + public_project.add_tag('Rheisen', auth=user_auth) + assert 'tag_added' == public_project.logs.latest().action + res = app.get(public_url, auth=user.auth) assert res.status_code == 200 - assert len(res.json['data']) == self.public_project.logs.count() + assert len(res.json['data']) == public_project.logs.count() assert res.json['data'][API_LATEST]['attributes']['action'] == 'tag_added' - assert 'Jeff Spies' == self.public_project.logs.latest().params['tag'] - - def test_remove_tag(self): - user_auth = Auth(self.user) - self.public_project.add_tag('Jeff Spies', auth=user_auth) - assert 'tag_added' == self.public_project.logs.latest().action - self.public_project.remove_tag('Jeff Spies', auth=self.user_auth) - assert 'tag_removed' == self.public_project.logs.latest().action - res = self.app.get(self.public_url, auth=self.user) + assert 'Rheisen' == public_project.logs.latest().params['tag'] + + def test_remove_tag(self, app, user, user_auth, public_project, public_url): + public_project.add_tag('Rheisen', auth=user_auth) + assert 'tag_added' == public_project.logs.latest().action + public_project.remove_tag('Rheisen', auth=user_auth) + assert 'tag_removed' == public_project.logs.latest().action + res = app.get(public_url, auth=user) assert res.status_code == 200 - assert len(res.json['data']) == self.public_project.logs.count() + assert len(res.json['data']) == public_project.logs.count() assert res.json['data'][API_LATEST]['attributes']['action'] == 'tag_removed' - assert 'Jeff Spies' == self.public_project.logs.latest().params['tag'] + assert 'Rheisen' == public_project.logs.latest().params['tag'] + + def test_project_creation(self, app, user, public_project, private_project, public_url, private_url): - def test_project_created(self): - res = self.app.get(self.public_url) + # test_project_created + res = app.get(public_url) assert res.status_code == 200 - assert len(res.json['data']) == self.public_project.logs.count() - assert self.public_project.logs.first().action == 'project_created' - assert self.public_project.logs.first().action == res.json['data'][API_LATEST]['attributes']['action'] + assert len(res.json['data']) == public_project.logs.count() + assert public_project.logs.first().action == 'project_created' + assert public_project.logs.first().action == res.json['data'][API_LATEST]['attributes']['action'] - def test_log_create_on_public_project(self): - res = self.app.get(self.public_url) + # test_log_create_on_public_project + res = app.get(public_url) assert res.status_code == 200 - assert len(res.json['data']) == self.public_project.logs.count() + assert len(res.json['data']) == public_project.logs.count() assert_datetime_equal(parse_date(res.json['data'][API_FIRST]['attributes']['date']), - self.public_project.logs.first().date) - assert res.json['data'][API_FIRST]['attributes']['action'] == self.public_project.logs.first().action + public_project.logs.first().date) + assert res.json['data'][API_FIRST]['attributes']['action'] == public_project.logs.first().action - def test_log_create_on_private_project(self): - res = self.app.get(self.private_url, auth=self.user.auth) + # test_log_create_on_private_project + res = app.get(private_url, auth=user.auth) assert res.status_code == 200 - assert len(res.json['data']) == self.public_project.logs.count() + assert len(res.json['data']) == public_project.logs.count() assert_datetime_equal(parse_date(res.json['data'][API_FIRST]['attributes']['date']), - self.private_project.logs.first().date) - assert res.json['data'][API_FIRST]['attributes']['action'] == self.private_project.logs.first().action + private_project.logs.first().date) + assert res.json['data'][API_FIRST]['attributes']['action'] == private_project.logs.first().action - def test_add_addon(self): - self.public_project.add_addon('github', auth=self.user_auth) - assert 'addon_added' == self.public_project.logs.latest().action - res = self.app.get(self.public_url, auth=self.user.auth) + def test_add_addon(self, app, user, user_auth, public_project, public_url): + public_project.add_addon('github', auth=user_auth) + assert 'addon_added' == public_project.logs.latest().action + res = app.get(public_url, auth=user.auth) assert res.status_code == 200 - assert len(res.json['data']) == self.public_project.logs.count() + assert len(res.json['data']) == public_project.logs.count() assert res.json['data'][API_LATEST]['attributes']['action'] == 'addon_added' - def test_project_add_remove_contributor(self): - self.public_project.add_contributor(self.contrib, auth=self.user_auth) - assert 'contributor_added' == self.public_project.logs.latest().action + def test_project_add_remove_contributor(self, app, user, contrib, user_auth, public_project, public_url): + public_project.add_contributor(contrib, auth=user_auth) + assert 'contributor_added' == public_project.logs.latest().action # Disconnect contributor_removed so that we don't check in files # We can remove this when StoredFileNode is implemented in osf-models with disconnected_from_listeners(contributor_removed): - self.public_project.remove_contributor(self.contrib, auth=self.user_auth) - assert 'contributor_removed' == self.public_project.logs.latest().action - res = self.app.get(self.public_url, auth=self.user.auth) + public_project.remove_contributor(contrib, auth=user_auth) + assert 'contributor_removed' == public_project.logs.latest().action + res = app.get(public_url, auth=user.auth) assert res.status_code == 200 - assert len(res.json['data']) == self.public_project.logs.count() + assert len(res.json['data']) == public_project.logs.count() assert res.json['data'][API_LATEST]['attributes']['action'] == 'contributor_removed' assert res.json['data'][1]['attributes']['action'] == 'contributor_added' - def test_remove_addon(self): - self.public_project.add_addon('github', auth=self.user_auth) - assert 'addon_added' == self.public_project.logs.latest().action - old_log_length = len(list(self.public_project.logs.all())) - self.public_project.delete_addon('github', auth=self.user_auth) - assert 'addon_removed' == self.public_project.logs.latest().action - assert (self.public_project.logs.count() - 1) == old_log_length - res = self.app.get(self.public_url, auth=self.user.auth) + def test_remove_addon(self, app, user, user_auth, public_project, public_url): + public_project.add_addon('github', auth=user_auth) + assert 'addon_added' == public_project.logs.latest().action + old_log_length = len(list(public_project.logs.all())) + public_project.delete_addon('github', auth=user_auth) + assert 'addon_removed' == public_project.logs.latest().action + assert (public_project.logs.count() - 1) == old_log_length + res = app.get(public_url, auth=user.auth) assert res.status_code == 200 - assert len(res.json['data']) == self.public_project.logs.count() + assert len(res.json['data']) == public_project.logs.count() assert res.json['data'][API_LATEST]['attributes']['action'] == 'addon_removed' - def test_add_pointer(self): - self.public_project.add_pointer(self.pointer, auth=Auth(self.user), save=True) - assert 'pointer_created' == self.public_project.logs.latest().action - res = self.app.get(self.public_url, auth=self.user.auth) + def test_add_pointer(self, app, user_auth, public_project, pointer, public_url): + public_project.add_pointer(pointer, auth=user_auth, save=True) + assert 'pointer_created' == public_project.logs.latest().action + res = app.get(public_url, auth=user_auth) assert res.status_code == 200 - assert len(res.json['data']) == self.public_project.logs.count() + assert len(res.json['data']) == public_project.logs.count() assert res.json['data'][API_LATEST]['attributes']['action'] == 'pointer_created' @pytest.mark.django_db class TestNodeLogFiltering(TestNodeLogList): - def test_filter_action_not_equal(self): - self.public_project.add_tag('Jeff Spies', auth=self.user_auth) - assert 'tag_added' == self.public_project.logs.latest().action - url = '/{}nodes/{}/logs/?filter[action][ne]=tag_added'.format(API_BASE, self.public_project._id) - res = self.app.get(url, auth=self.user.auth) + def test_filter_action_not_equal(self, app, user, user_auth, public_project): + public_project.add_tag('Rheisen', auth=user_auth) + assert 'tag_added' == public_project.logs.latest().action + url = '/{}nodes/{}/logs/?filter[action][ne]=tag_added'.format(API_BASE, public_project._id) + res = app.get(url, auth=user.auth) assert len(res.json['data']) == 1 assert res.json['data'][0]['attributes']['action'] == 'project_created' - def test_filter_date_not_equal(self): - self.public_project.add_pointer(self.pointer, auth=Auth(self.user), save=True) - assert 'pointer_created' == self.public_project.logs.latest().action - assert self.public_project.logs.count() == 2 + def test_filter_date_not_equal(self, app, user, public_project, pointer): + public_project.add_pointer(pointer, auth=Auth(user), save=True) + assert 'pointer_created' == public_project.logs.latest().action + assert public_project.logs.count() == 2 - pointer_added_log = self.public_project.logs.get(action='pointer_created') + pointer_added_log = public_project.logs.get(action='pointer_created') date_pointer_added = str(pointer_added_log.date).split('+')[0].replace(' ', 'T') - url = '/{}nodes/{}/logs/?filter[date][ne]={}'.format(API_BASE, self.public_project._id, date_pointer_added) - res = self.app.get(url, auth=self.user.auth) + url = '/{}nodes/{}/logs/?filter[date][ne]={}'.format(API_BASE, public_project._id, date_pointer_added) + res = app.get(url, auth=user.auth) assert res.status_code == 200 assert len(res.json['data']) == 1 assert res.json['data'][0]['attributes']['action'] == 'project_created' diff --git a/api_tests/nodes/views/test_node_registrations_list.py b/api_tests/nodes/views/test_node_registrations_list.py index 8c8c251e850..69d25d7842b 100644 --- a/api_tests/nodes/views/test_node_registrations_list.py +++ b/api_tests/nodes/views/test_node_registrations_list.py @@ -2,7 +2,6 @@ from urlparse import urlparse from api.base.settings.defaults import API_BASE -from tests.json_api_test_app import JSONAPITestApp from tests.base import ApiTestCase from osf_tests.factories import ( ProjectFactory, @@ -12,56 +11,67 @@ node_url_for = lambda n_id: '/{}nodes/{}/'.format(API_BASE, n_id) +@pytest.fixture() +def user(): + return AuthUserFactory() + @pytest.mark.django_db class TestNodeRegistrationList: - @pytest.fixture(autouse=True) - def setUp(self): - self.app = JSONAPITestApp() - self.user = AuthUserFactory() + @pytest.fixture() + def private_project(self, user): + return ProjectFactory(is_public=False, creator=user) + + @pytest.fixture() + def private_registration(self, user, private_project): + return RegistrationFactory(creator=user, project=private_project, is_public=True) + + @pytest.fixture() + def private_url(self, private_project): + return '/{}nodes/{}/registrations/'.format(API_BASE, private_project._id) - self.project = ProjectFactory(is_public=False, creator=self.user) - self.registration_project = RegistrationFactory(creator=self.user, project=self.project, is_public=True) - self.project.save() - self.private_url = '/{}nodes/{}/registrations/'.format(API_BASE, self.project._id) + @pytest.fixture() + def public_project(self, user): + return ProjectFactory(is_public=True, creator=user) - self.public_project = ProjectFactory(is_public=True, creator=self.user) - self.public_registration_project = RegistrationFactory(creator=self.user, project=self.public_project, is_public=True) - self.public_project.save() - self.public_url = '/{}nodes/{}/registrations/'.format(API_BASE, self.public_project._id) + @pytest.fixture() + def public_registration(self, user, public_project): + return RegistrationFactory(creator=user, project=public_project, is_public=True) - self.user_two = AuthUserFactory() + @pytest.fixture() + def public_url(self, public_project): + return '/{}nodes/{}/registrations/'.format(API_BASE, public_project._id) - def test_node_registration_list(self): + def test_node_registration_list(self, app, user, public_project, private_project, public_registration, private_registration, public_url, private_url): # test_return_public_registrations_logged_out - res = self.app.get(self.public_url) + res = app.get(public_url) assert res.status_code == 200 assert res.content_type == 'application/vnd.api+json' assert res.json['data'][0]['attributes']['registration'] == True url = res.json['data'][0]['relationships']['registered_from']['links']['related']['href'] - assert urlparse(url).path == '/{}nodes/{}/'.format(API_BASE, self.public_project._id) + assert urlparse(url).path == '/{}nodes/{}/'.format(API_BASE, public_project._id) assert res.json['data'][0]['type'] == 'registrations' # test_return_public_registrations_logged_in - res = self.app.get(self.public_url, auth=self.user.auth) + res = app.get(public_url, auth=user.auth) assert res.status_code == 200 assert res.json['data'][0]['attributes']['registration'] == True url = res.json['data'][0]['relationships']['registered_from']['links']['related']['href'] - assert urlparse(url).path == '/{}nodes/{}/'.format(API_BASE, self.public_project._id) + assert urlparse(url).path == '/{}nodes/{}/'.format(API_BASE, public_project._id) assert res.content_type == 'application/vnd.api+json' assert res.json['data'][0]['type'] == 'registrations' # test_return_private_registrations_logged_out - res = self.app.get(self.private_url, expect_errors=True) + res = app.get(private_url, expect_errors=True) assert res.status_code == 401 assert 'detail' in res.json['errors'][0] # test_return_private_registrations_logged_in_contributor - res = self.app.get(self.private_url, auth=self.user.auth) + res = app.get(private_url, auth=user.auth) assert res.status_code == 200 assert res.json['data'][0]['attributes']['registration'] == True url = res.json['data'][0]['relationships']['registered_from']['links']['related']['href'] - assert urlparse(url).path == '/{}nodes/{}/'.format(API_BASE, self.project._id) + assert urlparse(url).path == '/{}nodes/{}/'.format(API_BASE, private_project._id) assert res.content_type == 'application/vnd.api+json' assert res.json['data'][0]['type'] == 'registrations' diff --git a/api_tests/nodes/views/test_node_sparse_fieldsets.py b/api_tests/nodes/views/test_node_sparse_fieldsets.py index 430a95188af..532121dc557 100644 --- a/api_tests/nodes/views/test_node_sparse_fieldsets.py +++ b/api_tests/nodes/views/test_node_sparse_fieldsets.py @@ -1,4 +1,4 @@ -# -*- coding: utf-8 -*- +import pytest from api.base.settings.defaults import API_BASE from tests.base import ApiTestCase @@ -6,71 +6,81 @@ ProjectFactory, AuthUserFactory, ) -from api_tests.nodes.views.test_view_only_query_parameter import ViewOnlyTestCase +@pytest.fixture() +def user(): + return AuthUserFactory() -class TestNodeSparseFieldsList(ApiTestCase): - def setUp(self): - super(TestNodeSparseFieldsList, self).setUp() - self.user = AuthUserFactory() +@pytest.mark.django_db +class TestNodeSparseFieldsList: - self.non_contrib = AuthUserFactory() + @pytest.fixture() + def deleted_project(self): + return ProjectFactory(is_deleted=True) - self.deleted = ProjectFactory(is_deleted=True) - self.private = ProjectFactory(is_public=False, creator=self.user) - self.public = ProjectFactory(is_public=True, creator=self.user) + @pytest.fixture() + def private_project(self, user): + return ProjectFactory(is_public=False, creator=user) - self.url = '/{}nodes/?fields[nodes]='.format(API_BASE) + @pytest.fixture() + def public_project(self, user): + return ProjectFactory(is_public=True, creator=user) - def test_empty_fields_returns_no_attributes(self): - res = self.app.get(self.url) + @pytest.fixture() + def url(self): + return '/{}nodes/?fields[nodes]='.format(API_BASE) + + def test_node_sparse_fields_list(self, app, user, deleted_project, private_project, public_project, url): + + # def test_empty_fields_returns_no_attributes(self): + res = app.get(url) node_json = res.json['data'][0] assert node_json['attributes'] == {} assert set(node_json.keys()) == set(['links', 'type', 'id', 'attributes']) - def test_sparse_fields_includes_relationships(self): - res = self.app.get(self.url + 'children') + # def test_sparse_fields_includes_relationships(self): + res = app.get(url + 'children') node_json = res.json['data'][0] assert node_json['attributes'] == {} assert set(node_json.keys()) == set(['links', 'type', 'id', 'attributes', 'relationships']) - assert node_json['relationships']['children']['links']['related']['href'].endswith('/{}nodes/{}/children/'.format(API_BASE, self.public._id)) + assert node_json['relationships']['children']['links']['related']['href'].endswith('/{}nodes/{}/children/'.format(API_BASE, public_project._id)) - def test_returns_expected_nodes(self): - res = self.app.get(self.url + 'title') + # def test_returns_expected_nodes(self): + res = app.get(url + 'title') node_json = res.json['data'] ids = [each['id'] for each in node_json] - assert self.public._id in ids - assert self.deleted._id not in ids - assert self.private._id not in ids + assert public_project._id in ids + assert deleted_project._id not in ids + assert private_project._id not in ids assert len(node_json) == 1 node_json = node_json[0] - assert node_json['attributes']['title'] == self.public.title + assert node_json['attributes']['title'] == public_project.title assert len(node_json['attributes']) == 1 assert set(node_json.keys()) == set(['links', 'type', 'id', 'attributes']) - def test_filtering_by_id(self): - url = '/{}nodes/?filter[id]={}&fields[nodes]='.format(API_BASE, self.public._id) - res = self.app.get(url) - assert [each['id'] for each in res.json['data']] == [self.public._id] + # def test_filtering_by_id(self): + url = '/{}nodes/?filter[id]={}&fields[nodes]='.format(API_BASE, public_project._id) + res = app.get(url) + assert [each['id'] for each in res.json['data']] == [public_project._id] node_json = res.json['data'][0] assert set(node_json.keys()) == set(['links', 'type', 'id', 'attributes']) assert node_json['attributes'] == {} - def test_filtering_by_excluded_field(self): - url = '/{}nodes/?filter[title]={}&fields[nodes]='.format(API_BASE, self.public.title) - res = self.app.get(url) - assert [each['id'] for each in res.json['data']] == [self.public._id] + # def test_filtering_by_excluded_field(self): + url = '/{}nodes/?filter[title]={}&fields[nodes]='.format(API_BASE, public_project.title) + res = app.get(url) + assert [each['id'] for each in res.json['data']] == [public_project._id] node_json = res.json['data'][0] assert set(node_json.keys()) == set(['links', 'type', 'id', 'attributes']) assert node_json['attributes'] == {} - def test_create_with_sparse_fields(self): + # def test_create_with_sparse_fields(self): payload = { 'data': { 'type': 'nodes', @@ -83,100 +93,100 @@ def test_create_with_sparse_fields(self): } } } - res = self.app.post_json_api(self.url, payload, auth=self.user.auth) + res = app.post_json_api(url, payload, auth=user.auth) assert res.status_code == 201 assert set(res.json['data'].keys()) == set(['links', 'type', 'id', 'attributes']) assert res.json['data']['attributes'] == {} -class TestNodeSparseFieldsDetail(ApiTestCase): - - def setUp(self): - super(TestNodeSparseFieldsDetail, self).setUp() - self.user = AuthUserFactory() - self.node = ProjectFactory(is_public=True, creator=self.user) - self.url = '/{}nodes/{}/'.format(API_BASE, self.node._id) - - def test_empty_fields_returns_no_attributes(self): - res = self.app.get(self.url + '?fields[nodes]=') - node_json = res.json['data'] - - assert node_json['attributes'] == {} - assert set(node_json.keys()) == set(['links', 'type', 'id', 'attributes']) - - def test_embed_sparse_same_type(self): - child = ProjectFactory(parent=self.node, is_public=True, creator=self.user) - url = '{}?embed=children&fields[nodes]=title,children'.format(self.url) - res = self.app.get(url) - node_json = res.json['data'] - - assert set(node_json.keys()) == set(['links', 'type', 'id', 'attributes', 'relationships', 'embeds']) - assert node_json['attributes'].keys() == ['title'] - assert set(node_json['embeds']['children']['data'][0].keys()) == set(['links', 'type', 'id', 'attributes', 'relationships']) - assert node_json['embeds']['children']['data'][0]['attributes'].keys() == ['title'] - assert node_json['embeds']['children']['data'][0]['attributes']['title'] == child.title - - def test_embed_sparse_different_types(self): - url = '{}?embed=contributors&fields[nodes]=title,contributors'.format(self.url) - res = self.app.get(url) - node_json = res.json['data'] - - assert set(node_json.keys()) == set(['links', 'type', 'id', 'attributes', 'embeds', 'relationships']) - assert node_json['attributes'].keys() == ['title'] - assert len(node_json['embeds']['contributors']['data']) == 1 - assert node_json['embeds']['contributors']['data'][0]['id'] == '{}-{}'.format(self.node._id, self.user._id) - assert len(node_json['embeds']['contributors']['data'][0]['attributes']) > 1 - - def test_sparse_embedded_type(self): - url = '{}?embed=contributors&fields[contributors]='.format(self.url) - res = self.app.get(url) - node_json = res.json['data'] - - assert set(node_json.keys()) == set(['links', 'type', 'id', 'attributes', 'embeds', 'relationships']) - assert len(node_json['attributes'].keys()) > 1 - assert len(node_json['embeds']['contributors']['data']) == 1 - assert node_json['embeds']['contributors']['data'][0]['id'] == '{}-{}'.format(self.node._id, self.user._id) - assert len(node_json['embeds']['contributors']['data'][0]['attributes']) == 0 - - def test_multiple_sparse_types(self): - url = '{}?fields[nodes]=contributors,title&embed=contributors&fields[contributors]=bibliographic'.format(self.url) - res = self.app.get(url) - node_json = res.json['data'] - - assert set(node_json.keys()) == set(['links', 'type', 'id', 'attributes', 'embeds', 'relationships']) - assert node_json['attributes'].keys() == ['title'] - assert len(node_json['embeds']['contributors']['data']) == 1 - assert node_json['embeds']['contributors']['data'][0]['id'] == '{}-{}'.format(self.node._id, self.user._id) - assert node_json['embeds']['contributors']['data'][0]['attributes'].keys() == ['bibliographic'] - - def test_update_with_sparse_fields(self): - url = '{}?fields[nodes]='.format(self.url) - old_title = self.node.title - payload = {'data': { - 'id': self.node._id, - 'type': 'nodes', - 'attributes': { - 'title': 'new title' - } - }} - res = self.app.patch_json_api(url, payload, auth=self.user.auth) - assert res.status_code == 200 - assert res.json['data']['attributes'] == {} - self.node.reload() - assert self.node.title != old_title - - -class TestSparseViewOnlyLinks(ViewOnlyTestCase): - - def test_sparse_fields_with_anonymous_link(self): - res = self.app.get(self.private_node_one_url, { - 'view_only': self.private_node_one_anonymous_link.key, - 'fields[nodes]': 'title,current_user_can_comment,contributors', - 'fields[contributors]': 'id', - 'embed': 'contributors' - }) # current_user_can_comment is an anonymized field, should be removed - assert res.status_code == 200 - assert res.json['data']['attributes'].keys() == ['title'] - - for contrib in res.json['data']['embeds']['contributors']['data']: - assert contrib['id'] == '' - assert contrib['attributes'] == {} +# class TestNodeSparseFieldsDetail(ApiTestCase): + +# def setUp(self): +# super(TestNodeSparseFieldsDetail, self).setUp() +# self.user = AuthUserFactory() +# self.node = ProjectFactory(is_public=True, creator=self.user) +# self.url = '/{}nodes/{}/'.format(API_BASE, self.node._id) + +# def test_empty_fields_returns_no_attributes(self): +# res = self.app.get(self.url + '?fields[nodes]=') +# node_json = res.json['data'] + +# assert node_json['attributes'] == {} +# assert set(node_json.keys()) == set(['links', 'type', 'id', 'attributes']) + +# def test_embed_sparse_same_type(self): +# child = ProjectFactory(parent=self.node, is_public=True, creator=self.user) +# url = '{}?embed=children&fields[nodes]=title,children'.format(self.url) +# res = self.app.get(url) +# node_json = res.json['data'] + +# assert set(node_json.keys()) == set(['links', 'type', 'id', 'attributes', 'relationships', 'embeds']) +# assert node_json['attributes'].keys() == ['title'] +# assert set(node_json['embeds']['children']['data'][0].keys()) == set(['links', 'type', 'id', 'attributes', 'relationships']) +# assert node_json['embeds']['children']['data'][0]['attributes'].keys() == ['title'] +# assert node_json['embeds']['children']['data'][0]['attributes']['title'] == child.title + +# def test_embed_sparse_different_types(self): +# url = '{}?embed=contributors&fields[nodes]=title,contributors'.format(self.url) +# res = self.app.get(url) +# node_json = res.json['data'] + +# assert set(node_json.keys()) == set(['links', 'type', 'id', 'attributes', 'embeds', 'relationships']) +# assert node_json['attributes'].keys() == ['title'] +# assert len(node_json['embeds']['contributors']['data']) == 1 +# assert node_json['embeds']['contributors']['data'][0]['id'] == '{}-{}'.format(self.node._id, self.user._id) +# assert len(node_json['embeds']['contributors']['data'][0]['attributes']) > 1 + +# def test_sparse_embedded_type(self): +# url = '{}?embed=contributors&fields[contributors]='.format(self.url) +# res = self.app.get(url) +# node_json = res.json['data'] + +# assert set(node_json.keys()) == set(['links', 'type', 'id', 'attributes', 'embeds', 'relationships']) +# assert len(node_json['attributes'].keys()) > 1 +# assert len(node_json['embeds']['contributors']['data']) == 1 +# assert node_json['embeds']['contributors']['data'][0]['id'] == '{}-{}'.format(self.node._id, self.user._id) +# assert len(node_json['embeds']['contributors']['data'][0]['attributes']) == 0 + +# def test_multiple_sparse_types(self): +# url = '{}?fields[nodes]=contributors,title&embed=contributors&fields[contributors]=bibliographic'.format(self.url) +# res = self.app.get(url) +# node_json = res.json['data'] + +# assert set(node_json.keys()) == set(['links', 'type', 'id', 'attributes', 'embeds', 'relationships']) +# assert node_json['attributes'].keys() == ['title'] +# assert len(node_json['embeds']['contributors']['data']) == 1 +# assert node_json['embeds']['contributors']['data'][0]['id'] == '{}-{}'.format(self.node._id, self.user._id) +# assert node_json['embeds']['contributors']['data'][0]['attributes'].keys() == ['bibliographic'] + +# def test_update_with_sparse_fields(self): +# url = '{}?fields[nodes]='.format(self.url) +# old_title = self.node.title +# payload = {'data': { +# 'id': self.node._id, +# 'type': 'nodes', +# 'attributes': { +# 'title': 'new title' +# } +# }} +# res = self.app.patch_json_api(url, payload, auth=self.user.auth) +# assert res.status_code == 200 +# assert res.json['data']['attributes'] == {} +# self.node.reload() +# assert self.node.title != old_title + + +# class TestSparseViewOnlyLinks(ViewOnlyTestCase): + +# def test_sparse_fields_with_anonymous_link(self): +# res = self.app.get(self.private_node_one_url, { +# 'view_only': self.private_node_one_anonymous_link.key, +# 'fields[nodes]': 'title,current_user_can_comment,contributors', +# 'fields[contributors]': 'id', +# 'embed': 'contributors' +# }) # current_user_can_comment is an anonymized field, should be removed +# assert res.status_code == 200 +# assert res.json['data']['attributes'].keys() == ['title'] + +# for contrib in res.json['data']['embeds']['contributors']['data']: +# assert contrib['id'] == '' +# assert contrib['attributes'] == {} diff --git a/api_tests/nodes/views/test_node_view_only_links_detail.py b/api_tests/nodes/views/test_node_view_only_links_detail.py index e40b08b8fc3..e583bb8ccf5 100644 --- a/api_tests/nodes/views/test_node_view_only_links_detail.py +++ b/api_tests/nodes/views/test_node_view_only_links_detail.py @@ -1,162 +1,208 @@ import pytest from api.base.settings.defaults import API_BASE +from tests.base import ApiTestCase from website.util import permissions -from test_node_view_only_links_list import ViewOnlyLinkTestCase -from osf_tests.factories import NodeFactory, AuthUserFactory +from osf_tests.factories import ( + ProjectFactory, + AuthUserFactory, + PrivateLinkFactory +) + +@pytest.fixture(scope='function') +def user(): + return AuthUserFactory() + +@pytest.fixture(scope='function') +def read_only_user(): + return AuthUserFactory() + +@pytest.fixture(scope='function') +def read_write_user(): + return AuthUserFactory() + +@pytest.fixture(scope='function') +def non_contributor(): + return AuthUserFactory() + +@pytest.fixture(scope='function') +def public_project(user, read_only_user, read_write_user): + public_project = ProjectFactory(is_public=True, creator=user) + public_project.add_contributor(read_only_user, permissions=[permissions.READ]) + public_project.add_contributor(read_write_user, permissions=[permissions.WRITE]) + public_project.save() + return public_project + +@pytest.fixture(scope='function') +def view_only_link(public_project): + view_only_link = PrivateLinkFactory(name='testlink') + view_only_link.nodes.add(public_project) + view_only_link.save() + return view_only_link @pytest.mark.django_db -class TestViewOnlyLinksDetail(ViewOnlyLinkTestCase): +@pytest.mark.usefixtures('user', 'read_only_user', 'read_write_user', 'non_contributor', 'public_project', 'view_only_link') +class TestViewOnlyLinksDetail: - @pytest.fixture(autouse=True) - def setUp(self): - super(TestViewOnlyLinksDetail, self).setUp() - self.url = '/{}nodes/{}/view_only_links/{}/'.format(API_BASE, self.public_project._id, self.view_only_link._id) + @pytest.fixture() + def url(self, public_project, view_only_link): + return '/{}nodes/{}/view_only_links/{}/'.format(API_BASE, public_project._id, view_only_link._id) - def test_non_mutating_view_only_links_detail_tests(self): + def test_non_mutating_view_only_links_detail_tests(self, app, user, read_write_user, read_only_user, non_contributor, url, public_project, view_only_link): # test_admin_can_view_vol_detail - res = self.app.get(self.url, auth=self.user.auth) + res = app.get(url, auth=user.auth) assert res.status_code == 200 assert res.json['data']['attributes']['name'] == 'testlink' # test_read_write_cannot_view_vol_detail - res = self.app.get(self.url, auth=self.read_write_user.auth, expect_errors=True) + res = app.get(url, auth=read_write_user.auth, expect_errors=True) assert res.status_code == 403 # test_read_only_cannot_view_vol_detail - res = self.app.get(self.url, auth=self.read_only_user.auth, expect_errors=True) + res = app.get(url, auth=read_only_user.auth, expect_errors=True) assert res.status_code == 403 # test_logged_in_user_cannot_view_vol_detail - res = self.app.get(self.url, auth=self.non_contributor.auth, expect_errors=True) + res = app.get(url, auth=non_contributor.auth, expect_errors=True) assert res.status_code == 403 # test_unauthenticated_user_cannot_view_vol_detail - res = self.app.get(self.url, expect_errors=True) + res = app.get(url, expect_errors=True) assert res.status_code == 401 - def test_deleted_vol_not_returned(self): - res = self.app.get(self.url, auth=self.user.auth) + def test_deleted_vol_not_returned(self, app, user, public_project, view_only_link, url): + res = app.get(url, auth=user.auth) assert res.status_code == 200 assert res.json['data']['attributes']['name'] == 'testlink' - self.view_only_link.nodes.remove(self.public_project) - self.view_only_link.save() + view_only_link.nodes.remove(public_project) + view_only_link.save() - res = self.app.get(self.url, auth=self.user.auth, expect_errors=True) + res = app.get(url, auth=user.auth, expect_errors=True) assert res.status_code == 404 @pytest.mark.django_db -class TestViewOnlyLinksUpdate(ViewOnlyLinkTestCase): +@pytest.mark.usefixtures('user', 'read_only_user', 'read_write_user', 'non_contributor', 'public_project', 'view_only_link') +class TestViewOnlyLinksUpdate: - @pytest.fixture(autouse=True) - def setUp(self): - super(TestViewOnlyLinksUpdate, self).setUp() - self.url = '/{}nodes/{}/view_only_links/{}/'.format(API_BASE, self.public_project._id, self.view_only_link._id) + @pytest.fixture() + def url(self, public_project, view_only_link): + return '/{}nodes/{}/view_only_links/{}/'.format(API_BASE, public_project._id, view_only_link._id) - self.user_two = AuthUserFactory() - self.public_project.add_contributor(self.user_two, permissions=[permissions.ADMIN]) + @pytest.fixture() + def public_project_admin(self, public_project): + return AuthUserFactory() - self.public_project_component = NodeFactory(is_public=True, creator=self.user, parent=self.public_project) - self.public_project_component.save() + @pytest.fixture() + def public_project(self, public_project_admin, public_project): + public_project.add_contributor(public_project_admin, permissions=[permissions.ADMIN]) + return public_project - def test_admin_can_update_vol_name(self): - assert self.view_only_link.name == 'testlink' - assert self.view_only_link.anonymous == False + @pytest.fixture() + def public_project_component(self, user, public_project): + return NodeFactory(is_public=True, creator=user, parent=public_project) + + def test_admin_can_update_vol_name(self, app, user, view_only_link, url): + assert view_only_link.name == 'testlink' + assert view_only_link.anonymous == False payload = { 'attributes': { 'name': 'updated vol name' } } - res = self.app.put_json_api(self.url, {'data': payload}, auth=self.user.auth) + res = app.put_json_api(url, {'data': payload}, auth=user.auth) assert res.status_code == 200 assert res.json['data']['attributes']['name'] == 'updated vol name' assert res.json['data']['attributes']['anonymous'] == False - def test_admin_can_update_vol_anonymous(self): - assert self.view_only_link.name == 'testlink' - assert self.view_only_link.anonymous == False + def test_admin_can_update_vol_anonymous(self, app, user, view_only_link, url): + assert view_only_link.name == 'testlink' + assert view_only_link.anonymous == False payload = { 'attributes': { 'anonymous': True } } - res = self.app.put_json_api(self.url, {'data': payload}, auth=self.user.auth) + res = app.put_json_api(url, {'data': payload}, auth=user.auth) assert res.status_code == 200 assert res.json['data']['attributes']['name'] == 'testlink' assert res.json['data']['attributes']['anonymous'] == True - def test_read_write_cannot_update_vol(self): + def test_cannot_update_vol(self, app, read_write_user, read_only_user, non_contributor, url): + + # test_read_write_cannot_update_vol payload = { 'attributes': { 'name': 'updated vol name', 'anonymous': True, } } - res = self.app.put_json_api(self.url, {'data': payload}, auth=self.read_write_user.auth, expect_errors=True) + res = app.put_json_api(url, {'data': payload}, auth=read_write_user.auth, expect_errors=True) assert res.status_code == 403 - def test_read_only_cannot_update_vol(self): + # test_read_only_cannot_update_vol payload = { 'attributes': { 'name': 'updated vol name', 'anonymous': True, } } - res = self.app.put_json_api(self.url, {'data': payload}, auth=self.read_only_user.auth, expect_errors=True) + res = app.put_json_api(url, {'data': payload}, auth=read_only_user.auth, expect_errors=True) assert res.status_code == 403 - def test_logged_in_user_cannot_update_vol(self): + # test_logged_in_user_cannot_update_vol payload = { 'attributes': { 'name': 'updated vol name', 'anonymous': True, } } - res = self.app.put_json_api(self.url, {'data': payload}, auth=self.non_contributor.auth, expect_errors=True) + res = app.put_json_api(url, {'data': payload}, auth=non_contributor.auth, expect_errors=True) assert res.status_code == 403 - def test_unauthenticated_user_cannot_update_vol(self): + # test_unauthenticated_user_cannot_update_vol payload = { 'attributes': { 'name': 'updated vol name', 'anonymous': True, } } - res = self.app.put_json_api(self.url, {'data': payload}, expect_errors=True) + res = app.put_json_api(url, {'data': payload}, expect_errors=True) assert res.status_code == 401 @pytest.mark.django_db -class TestViewOnlyLinksDelete(ViewOnlyLinkTestCase): +@pytest.mark.usefixtures('user', 'read_only_user', 'read_write_user', 'non_contributor', 'public_project', 'view_only_link') +class TestViewOnlyLinksDelete: - @pytest.fixture(autouse=True) - def setUp(self): - super(TestViewOnlyLinksDelete, self).setUp() - self.url = '/{}nodes/{}/view_only_links/{}/'.format(API_BASE, self.public_project._id, self.view_only_link._id) + @pytest.fixture() + def url(self, public_project, view_only_link): + return '/{}nodes/{}/view_only_links/{}/'.format(API_BASE, public_project._id, view_only_link._id) - def test_admin_can_delete_vol(self): - res = self.app.delete(self.url, auth=self.user.auth) - self.view_only_link.reload() + def test_admin_can_delete_vol(self, app, user, url, view_only_link): + res = app.delete(url, auth=user.auth) + view_only_link.reload() assert res.status_code == 204 - assert self.view_only_link.is_deleted == True + assert view_only_link.is_deleted == True + + def test_vol_delete(self, app, read_write_user, read_only_user, non_contributor, url): - def test_read_write_cannot_delete_vol(self): - res = self.app.delete(self.url, auth=self.read_write_user.auth, expect_errors=True) + # test_read_write_cannot_delete_vol + res = app.delete(url, auth=read_write_user.auth, expect_errors=True) assert res.status_code == 403 - def test_read_only_cannot_delete_vol(self): - res = self.app.delete(self.url, auth=self.read_only_user.auth, expect_errors=True) + # test_read_only_cannot_delete_vol + res = app.delete(url, auth=read_only_user.auth, expect_errors=True) assert res.status_code == 403 - def test_logged_in_user_cannot_delete_vol(self): - res = self.app.delete(self.url, auth=self.non_contributor.auth, expect_errors=True) + # test_logged_in_user_cannot_delete_vol + res = app.delete(url, auth=non_contributor.auth, expect_errors=True) assert res.status_code == 403 - def test_unauthenticated_user_cannot_delete_vol(self): - res = self.app.delete(self.url, expect_errors=True) + # test_unauthenticated_user_cannot_delete_vol + res = app.delete(url, expect_errors=True) assert res.status_code == 401 diff --git a/api_tests/nodes/views/test_node_view_only_links_list.py b/api_tests/nodes/views/test_node_view_only_links_list.py index ea4642509e1..1166ec7a587 100644 --- a/api_tests/nodes/views/test_node_view_only_links_list.py +++ b/api_tests/nodes/views/test_node_view_only_links_list.py @@ -2,7 +2,6 @@ from website.util import permissions from api.base.settings.defaults import API_BASE -from tests.json_api_test_app import JSONAPITestApp from tests.base import ApiTestCase from osf_tests.factories import ( ProjectFactory, @@ -10,175 +9,191 @@ PrivateLinkFactory ) - -class ViewOnlyLinkTestCase(object): - - def setUp(self): - self.app = JSONAPITestApp() - self.user = AuthUserFactory() - self.read_only_user = AuthUserFactory() - self.read_write_user = AuthUserFactory() - self.non_contributor = AuthUserFactory() - - self.public_project = ProjectFactory(is_public=True, creator=self.user) - self.public_project.add_contributor(self.read_only_user, permissions=[permissions.READ]) - self.public_project.add_contributor(self.read_write_user, permissions=[permissions.WRITE]) - self.public_project.save() - - self.view_only_link = PrivateLinkFactory(name='testlink') - self.view_only_link.nodes.add(self.public_project) - self.view_only_link.save() +@pytest.fixture(scope='function') +def user(): + return AuthUserFactory() + +@pytest.fixture(scope='function') +def read_only_user(): + return AuthUserFactory() + +@pytest.fixture(scope='function') +def read_write_user(): + return AuthUserFactory() + +@pytest.fixture(scope='function') +def non_contributor(): + return AuthUserFactory() + +@pytest.fixture(scope='function') +def public_project(user, read_only_user, read_write_user): + public_project = ProjectFactory(is_public=True, creator=user) + public_project.add_contributor(read_only_user, permissions=[permissions.READ]) + public_project.add_contributor(read_write_user, permissions=[permissions.WRITE]) + public_project.save() + return public_project + +@pytest.fixture(scope='function') +def view_only_link(public_project): + view_only_link = PrivateLinkFactory(name='testlink') + view_only_link.nodes.add(public_project) + view_only_link.save() + return view_only_link @pytest.mark.django_db -class TestViewOnlyLinksList(ViewOnlyLinkTestCase): +@pytest.mark.usefixtures('user', 'read_only_user', 'read_write_user', 'non_contributor', 'public_project', 'view_only_link') +class TestViewOnlyLinksList: - @pytest.fixture(autouse=True) - def setUp(self): - super(TestViewOnlyLinksList, self).setUp() - self.url = '/{}nodes/{}/view_only_links/'.format(API_BASE, self.public_project._id) + @pytest.fixture() + def url(self, public_project): + return '/{}nodes/{}/view_only_links/'.format(API_BASE, public_project._id) - def test_non_mutating_view_only_links_list_tests(self): + def test_non_mutating_view_only_links_list_tests(self, app, user, read_write_user, read_only_user, non_contributor, public_project, url): # test_admin_can_view_vols_list - res = self.app.get(self.url, auth=self.user.auth) + res = app.get(url, auth=user.auth) assert res.status_code == 200 data = res.json['data'] + print data + print url assert len(data) == 1 assert data[0]['attributes']['name'] == 'testlink' # test_read_write_cannot_view_vols_list - res = self.app.get(self.url, auth=self.read_write_user.auth, expect_errors=True) + res = app.get(url, auth=read_write_user.auth, expect_errors=True) assert res.status_code == 403 # test_read_only_cannot_view_vols_list - res = self.app.get(self.url, auth=self.read_only_user.auth, expect_errors=True) + res = app.get(url, auth=read_only_user.auth, expect_errors=True) assert res.status_code == 403 # test_logged_in_user_cannot_view_vols_list - res = self.app.get(self.url, auth=self.non_contributor.auth, expect_errors=True) + res = app.get(url, auth=non_contributor.auth, expect_errors=True) assert res.status_code == 403 # test_unauthenticated_user_cannot_view_vols_list - res = self.app.get(self.url, expect_errors=True) + res = app.get(url, expect_errors=True) assert res.status_code == 401 - def test_deleted_vols_not_returned(self): + def test_deleted_vols_not_returned(self, app, user, url, public_project): view_only_link = PrivateLinkFactory(name='testlink2') - view_only_link.nodes.add(self.public_project) + view_only_link.nodes.add(public_project) view_only_link.save() - res = self.app.get(self.url, auth=self.user.auth) + res = app.get(url, auth=user.auth) data = res.json['data'] assert res.status_code == 200 assert len(data) == 2 - view_only_link.nodes.remove(self.public_project) + view_only_link.nodes.remove(public_project) view_only_link.save() - res = self.app.get(self.url, auth=self.user.auth) + res = app.get(url, auth=user.auth) data = res.json['data'] assert res.status_code == 200 assert len(data) == 1 @pytest.mark.django_db -class TestViewOnlyLinksCreate(ViewOnlyLinkTestCase): +@pytest.mark.usefixtures('user', 'read_only_user', 'read_write_user', 'non_contributor', 'public_project', 'view_only_link') +class TestViewOnlyLinksCreate: - @pytest.fixture(autouse=True) - def setUp(self): - super(TestViewOnlyLinksCreate, self).setUp() - self.url = '/{}nodes/{}/view_only_links/'.format(API_BASE, self.public_project._id) + @pytest.fixture() + def url(self, public_project): + return '/{}nodes/{}/view_only_links/'.format(API_BASE, public_project._id) - def test_invalid_vol_name(self): + def test_invalid_vol_name(self, app, user, url): payload = { 'attributes': { 'name': '
    ', 'anonymous': False, } } - res = self.app.post_json_api(self.url, {'data': payload}, auth=self.user.auth, expect_errors=True) + res = app.post_json_api(url, {'data': payload}, auth=user.auth, expect_errors=True) assert res.status_code == 400 assert res.json['errors'][0]['detail'] == 'Invalid link name.' - def test_default_anonymous_not_in_payload(self): - url = '/{}nodes/{}/view_only_links/?embed=creator'.format(API_BASE, self.public_project._id) + def test_default_anonymous_not_in_payload(self, app, user, public_project): + url = '/{}nodes/{}/view_only_links/?embed=creator'.format(API_BASE, public_project._id) payload = { 'attributes': { 'name': 'testlink', } } - res = self.app.post_json_api(url, {'data': payload}, auth=self.user.auth) + res = app.post_json_api(url, {'data': payload}, auth=user.auth) assert res.status_code == 201 data = res.json['data'] assert data['attributes']['name'] == 'testlink' assert data['attributes']['anonymous'] == False - assert data['embeds']['creator']['data']['id'] == self.user._id + assert data['embeds']['creator']['data']['id'] == user._id - def test_default_name_not_in_payload(self): - url = '/{}nodes/{}/view_only_links/?embed=creator'.format(API_BASE, self.public_project._id) + def test_default_name_not_in_payload(self, app, user, public_project): + url = '/{}nodes/{}/view_only_links/?embed=creator'.format(API_BASE, public_project._id) payload = { 'attributes': { 'anonymous': False, } } - res = self.app.post_json_api(url, {'data': payload}, auth=self.user.auth) + res = app.post_json_api(url, {'data': payload}, auth=user.auth) assert res.status_code == 201 data = res.json['data'] assert data['attributes']['name'] == 'Shared project link' assert data['attributes']['anonymous'] == False - assert data['embeds']['creator']['data']['id'] == self.user._id + assert data['embeds']['creator']['data']['id'] == user._id - def test_admin_can_create_vol(self): - url = '/{}nodes/{}/view_only_links/?embed=creator'.format(API_BASE, self.public_project._id) + def test_admin_can_create_vol(self, app, user, public_project): + url = '/{}nodes/{}/view_only_links/?embed=creator'.format(API_BASE, public_project._id) payload = { 'attributes': { 'name': 'testlink', 'anonymous': True, } } - res = self.app.post_json_api(url, {'data': payload}, auth=self.user.auth) + res = app.post_json_api(url, {'data': payload}, auth=user.auth) assert res.status_code == 201 - assert self.public_project.private_links.count() == 2 + assert public_project.private_links.count() == 2 data = res.json['data'] assert data['attributes']['name'] == 'testlink' assert data['attributes']['anonymous'] == True - assert data['embeds']['creator']['data']['id'] == self.user._id + assert data['embeds']['creator']['data']['id'] == user._id + + def test_cannot_create_vol(self, app, read_write_user, read_only_user, non_contributor, url): - def test_read_write_cannot_create_vol(self): + # test_read_write_cannot_create_vol payload = { 'attributes': { 'name': 'testlink', 'anonymous': True, } } - res = self.app.post_json_api(self.url, {'data': payload}, auth=self.read_write_user.auth, expect_errors=True) + res = app.post_json_api(url, {'data': payload}, auth=read_write_user.auth, expect_errors=True) assert res.status_code == 403 - def test_read_only_cannot_create_vol(self): + # test_read_only_cannot_create_vol payload = { 'attributes': { 'name': 'testlink', 'anonymous': True, } } - res = self.app.post_json_api(self.url, {'data': payload}, auth=self.read_only_user.auth, expect_errors=True) + res = app.post_json_api(url, {'data': payload}, auth=read_only_user.auth, expect_errors=True) assert res.status_code == 403 - def test_logged_in_user_cannot_create_vol(self): + # test_logged_in_user_cannot_create_vol payload = { 'attributes': { 'name': 'testlink', 'anonymous': True, } } - res = self.app.post_json_api(self.url, {'data': payload}, auth=self.non_contributor.auth, expect_errors=True) + res = app.post_json_api(url, {'data': payload}, auth=non_contributor.auth, expect_errors=True) assert res.status_code == 403 - def test_unauthenticated_user_cannot_create_vol(self): + # test_unauthenticated_user_cannot_create_vol payload = { 'attributes': { 'name': 'testlink', 'anonymous': True, } } - res = self.app.post_json_api(self.url, {'data': payload}, expect_errors=True) + res = app.post_json_api(url, {'data': payload}, expect_errors=True) assert res.status_code == 401 diff --git a/api_tests/nodes/views/test_view_only_query_parameter.py b/api_tests/nodes/views/test_view_only_query_parameter.py index 11186c3f4c6..3871ecd64f8 100644 --- a/api_tests/nodes/views/test_view_only_query_parameter.py +++ b/api_tests/nodes/views/test_view_only_query_parameter.py @@ -3,7 +3,6 @@ from website.util import permissions from api.base.settings.defaults import API_BASE from tests.base import ApiTestCase -from tests.json_api_test_app import JSONAPITestApp from website.models import Node from osf_tests.factories import ( ProjectFactory, @@ -11,62 +10,117 @@ PrivateLinkFactory, ) -class ViewOnlyTestCase(object): - - @pytest.fixture(autouse=True) - def setUp(self): - self.app = JSONAPITestApp() - self.creation_user = AuthUserFactory() - self.viewing_user = AuthUserFactory() - self.contributing_read_user = AuthUserFactory() - self.contributing_write_user = AuthUserFactory() - self.valid_contributors = [ - self.creation_user._id, - self.contributing_read_user._id, - self.contributing_write_user._id, - ] - - self.private_node_one = ProjectFactory(is_public=False, creator=self.creation_user, title="Private One") - self.private_node_one.add_contributor(self.contributing_read_user, permissions=[permissions.READ], save=True) - self.private_node_one.add_contributor(self.contributing_write_user, permissions=[permissions.WRITE], save=True) - self.private_node_one_anonymous_link = PrivateLinkFactory(anonymous=True) - self.private_node_one_anonymous_link.nodes.add(self.private_node_one) - self.private_node_one_anonymous_link.save() - self.private_node_one_private_link = PrivateLinkFactory(anonymous=False) - self.private_node_one_private_link.nodes.add(self.private_node_one) - self.private_node_one_private_link.save() - self.private_node_one_url = '/{}nodes/{}/'.format(API_BASE, self.private_node_one._id) - - self.private_node_two = ProjectFactory(is_public=False, creator=self.creation_user, title="Private Two") - self.private_node_two.add_contributor(self.contributing_read_user, permissions=[permissions.READ], save=True) - self.private_node_two.add_contributor(self.contributing_write_user, permissions=[permissions.WRITE], save=True) - self.private_node_two_url = '/{}nodes/{}/'.format(API_BASE, self.private_node_two._id) - - self.public_node_one = ProjectFactory(is_public=True, creator=self.creation_user, title="Public One") - self.public_node_one.add_contributor(self.contributing_read_user, permissions=[permissions.READ], save=True) - self.public_node_one.add_contributor(self.contributing_write_user, permissions=[permissions.WRITE], save=True) - self.public_node_one_anonymous_link = PrivateLinkFactory(anonymous=True) - self.public_node_one_anonymous_link.nodes.add(self.public_node_one) - self.public_node_one_anonymous_link.save() - self.public_node_one_private_link = PrivateLinkFactory(anonymous=False) - self.public_node_one_private_link.nodes.add(self.public_node_one) - self.public_node_one_private_link.save() - self.public_node_one_url = '/{}nodes/{}/'.format(API_BASE, self.public_node_one._id) - - self.public_node_two = ProjectFactory(is_public=True, creator=self.creation_user, title="Public Two") - self.public_node_two.add_contributor(self.contributing_read_user, permissions=[permissions.READ], save=True) - self.public_node_two.add_contributor(self.contributing_write_user, permissions=[permissions.WRITE], save=True) - self.public_node_two_url = '/{}nodes/{}/'.format(API_BASE, self.public_node_two._id) +@pytest.fixture() +def creation_user(): + return AuthUserFactory() + +@pytest.fixture() +def viewing_user(): + return AuthUserFactory() + +@pytest.fixture() +def contributing_read_user(): + return AuthUserFactory() + +@pytest.fixture() +def contributing_write_user(): + return AuthUserFactory() + +@pytest.fixture() +def valid_contributors(creation_user, contributing_read_user, contributing_write_user): + return [ + creation_user._id, + contributing_read_user._id, + contributing_write_user._id, + ] + +@pytest.fixture() +def private_node_one(creation_user, contributing_read_user, contributing_write_user): + private_node_one = ProjectFactory(is_public=False, creator=creation_user, title='Private One') + private_node_one.add_contributor(contributing_read_user, permissions=[permissions.READ], save=True) + private_node_one.add_contributor(contributing_write_user, permissions=[permissions.WRITE], save=True) + return private_node_one + +@pytest.fixture() +def private_node_one_anonymous_link(private_node_one): + private_node_one_anonymous_link = PrivateLinkFactory(anonymous=True) + private_node_one_anonymous_link.nodes.add(private_node_one) + private_node_one_anonymous_link.save() + return private_node_one_anonymous_link + +@pytest.fixture() +def private_node_one_private_link(private_node_one): + private_node_one_private_link = PrivateLinkFactory(anonymous=False) + private_node_one_private_link.nodes.add(private_node_one) + private_node_one_private_link.save() + return private_node_one_private_link + +@pytest.fixture() +def private_node_one_url(private_node_one): + return '/{}nodes/{}/'.format(API_BASE, private_node_one._id) + +@pytest.fixture() +def private_node_two(creation_user, contributing_read_user, contributing_write_user): + private_node_two = ProjectFactory(is_public=False, creator=creation_user, title='Private Two') + private_node_two.add_contributor(contributing_read_user, permissions=[permissions.READ], save=True) + private_node_two.add_contributor(contributing_write_user, permissions=[permissions.WRITE], save=True) + return private_node_two + +@pytest.fixture() +def private_node_two_url(private_node_two): + return '/{}nodes/{}/'.format(API_BASE, private_node_two._id) + +@pytest.fixture() +def public_node_one(creation_user, contributing_read_user, contributing_write_user): + public_node_one = ProjectFactory(is_public=True, creator=creation_user, title='Public One') + public_node_one.add_contributor(contributing_read_user, permissions=[permissions.READ], save=True) + public_node_one.add_contributor(contributing_write_user, permissions=[permissions.WRITE], save=True) + return public_node_one + +@pytest.fixture() +def public_node_one_anonymous_link(public_node_one): + public_node_one_anonymous_link = PrivateLinkFactory(anonymous=True) + public_node_one_anonymous_link.nodes.add(public_node_one) + public_node_one_anonymous_link.save() + return public_node_one_anonymous_link + +@pytest.fixture() +def public_node_one_private_link(public_node_one): + public_node_one_private_link = PrivateLinkFactory(anonymous=False) + public_node_one_private_link.nodes.add(public_node_one) + public_node_one_private_link.save() + return public_node_one_private_link + +@pytest.fixture() +def public_node_one_url(public_node_one): + return '/{}nodes/{}/'.format(API_BASE, public_node_one._id) + +@pytest.fixture() +def public_node_two(creation_user, contributing_read_user, contributing_write_user): + public_node_two = ProjectFactory(is_public=True, creator=creation_user, title='Public Two') + public_node_two.add_contributor(contributing_read_user, permissions=[permissions.READ], save=True) + public_node_two.add_contributor(contributing_write_user, permissions=[permissions.WRITE], save=True) + return public_node_two + +@pytest.fixture() +def public_node_two_url(public_node_two): + return '/{}nodes/{}/'.format(API_BASE, public_node_two._id) @pytest.mark.django_db -class TestNodeDetailViewOnlyLinks(ViewOnlyTestCase): +@pytest.mark.usefixtures('creation_user', 'viewing_user', 'contributing_read_user', 'contributing_write_user', 'valid_contributors', + 'private_node_one', 'private_node_one_anonymous_link', 'private_node_one_private_link', 'private_node_one_url', + 'private_node_two', 'private_node_two_url', 'public_node_one', 'public_node_one_anonymous_link', + 'public_node_one_private_link', 'public_node_one_url', 'public_node_two', 'public_node_two_url') +class TestNodeDetailViewOnlyLinks: - def test_private_node_with_link_works_when_using_link(self): - res_normal = self.app.get(self.private_node_one_url, auth=self.contributing_read_user.auth) + def test_private_node(self, app, creation_user, contributing_read_user, valid_contributors, private_node_one, private_node_one_url, private_node_one_private_link, private_node_one_anonymous_link, public_node_one_url, public_node_one_private_link, public_node_one_anonymous_link): + + # test_private_node_with_link_works_when_using_link + res_normal = app.get(private_node_one_url, auth=contributing_read_user.auth) assert res_normal.status_code == 200 - res_linked = self.app.get(self.private_node_one_url, {'view_only': self.private_node_one_private_link.key}) + res_linked = app.get(private_node_one_url, {'view_only': private_node_one_private_link.key}) assert res_linked.status_code == 200 - assert_items_equal(res_linked.json['data']['attributes']['current_user_permissions'], ['read']) + assert res_linked.json['data']['attributes']['current_user_permissions'] == ['read'] # Remove any keys that will be different for view-only responses res_normal_json = res_normal.json @@ -77,13 +131,13 @@ def test_private_node_with_link_works_when_using_link(self): assert user_can_comment assert not view_only_can_comment - def test_private_node_with_link_unauthorized_when_not_using_link(self): - res = self.app.get(self.private_node_one_url, expect_errors=True) + # test_private_node_with_link_unauthorized_when_not_using_link + res = app.get(private_node_one_url, expect_errors=True) assert res.status_code == 401 - def test_private_node_with_link_anonymous_does_not_expose_contributor_id(self): - res = self.app.get(self.private_node_one_url, { - 'view_only': self.private_node_one_anonymous_link.key, + # test_private_node_with_link_anonymous_does_not_expose_contributor_id + res = app.get(private_node_one_url, { + 'view_only': private_node_one_anonymous_link.key, 'embed': 'contributors', }) assert res.status_code == 200 @@ -91,29 +145,29 @@ def test_private_node_with_link_anonymous_does_not_expose_contributor_id(self): for contributor in contributors: assert contributor['id'] == '' - def test_private_node_with_link_non_anonymous_does_expose_contributor_id(self): - res = self.app.get(self.private_node_one_url, { - 'view_only': self.private_node_one_private_link.key, + # test_private_node_with_link_non_anonymous_does_expose_contributor_id + res = app.get(private_node_one_url, { + 'view_only': private_node_one_private_link.key, 'embed': 'contributors', }) assert res.status_code == 200 contributors = res.json['data']['embeds']['contributors']['data'] for contributor in contributors: - assert contributor['id'].split('-')[1] in self.valid_contributors + assert contributor['id'].split('-')[1] in valid_contributors - def test_private_node_logged_in_with_anonymous_link_does_not_expose_contributor_id(self): - res = self.app.get(self.private_node_one_url, { - 'view_only': self.private_node_one_private_link.key, + # test_private_node_logged_in_with_anonymous_link_does_not_expose_contributor_id + res = app.get(private_node_one_url, { + 'view_only': private_node_one_private_link.key, 'embed': 'contributors', - }, auth=self.creation_user.auth) + }, auth=creation_user.auth) assert res.status_code == 200 contributors = res.json['data']['embeds']['contributors']['data'] for contributor in contributors: - assert contributor['id'].split('-')[1] in self.valid_contributors + assert contributor['id'].split('-')[1] in valid_contributors - def test_public_node_with_link_anonymous_does_not_expose_user_id(self): - res = self.app.get(self.public_node_one_url, { - 'view_only': self.public_node_one_anonymous_link.key, + # test_public_node_with_link_anonymous_does_not_expose_user_id + res = app.get(public_node_one_url, { + 'view_only': public_node_one_anonymous_link.key, 'embed': 'contributors', }) assert res.status_code == 200 @@ -121,58 +175,57 @@ def test_public_node_with_link_anonymous_does_not_expose_user_id(self): for contributor in contributors: assert contributor['id'] == '' - def test_public_node_with_link_non_anonymous_does_expose_contributor_id(self): - res = self.app.get(self.public_node_one_url, { - 'view_only': self.public_node_one_private_link.key, + # test_public_node_with_link_non_anonymous_does_expose_contributor_id + res = app.get(public_node_one_url, { + 'view_only': public_node_one_private_link.key, 'embed': 'contributors', }) assert res.status_code == 200 contributors = res.json['data']['embeds']['contributors']['data'] for contributor in contributors: - assert contributor['id'].split('-')[1] in self.valid_contributors + assert contributor['id'].split('-')[1] in valid_contributors - def test_public_node_with_link_unused_does_expose_contributor_id(self): - res = self.app.get(self.public_node_one_url, { + # test_public_node_with_link_unused_does_expose_contributor_id + res = app.get(public_node_one_url, { 'embed': 'contributors', }) assert res.status_code == 200 contributors = res.json['data']['embeds']['contributors']['data'] for contributor in contributors: - assert contributor['id'].split('-')[1] in self.valid_contributors + assert contributor['id'].split('-')[1] in valid_contributors - def test_view_only_link_does_not_grant_write_permission(self): + # test_view_only_link_does_not_grant_write_permission payload = { 'data': { 'attributes': { 'title': 'Cannot touch this' }, - 'id': self.private_node_one._id, + 'id': private_node_one._id, 'type': 'nodes', } } - res = self.app.patch_json_api(self.private_node_one_url, payload, { - 'view_only': self.private_node_one_private_link.key, + res = app.patch_json_api(private_node_one_url, payload, { + 'view_only': private_node_one_private_link.key, }, expect_errors=True) assert res.status_code == 401 - def test_view_only_link_from_anther_project_does_not_grant_view_permission(self): - res = self.app.get(self.private_node_one_url, { - 'view_only': self.public_node_one_private_link.key, + # test_view_only_link_from_anther_project_does_not_grant_view_permission + res = app.get(private_node_one_url, { + 'view_only': public_node_one_private_link.key, }, expect_errors=True) assert res.status_code == 401 - def test_private_project_logs_with_anonymous_link_does_not_expose_user_id(self): - res = self.app.get(self.private_node_one_url+'logs/', { - 'view_only': str(self.private_node_one_anonymous_link.key), + # test_private_project_logs_with_anonymous_link_does_not_expose_user_id + res = app.get(private_node_one_url+'logs/', { + 'view_only': str(private_node_one_anonymous_link.key), }) assert res.status_code == 200 body = res.body - assert self.contributing_write_user._id not in body - assert self.contributing_read_user._id not in body - assert self.creation_user._id not in body + for id in valid_contributors: + assert id not in body - def test_private_project_with_anonymous_link_does_not_expose_registrations_or_forks(self): - res = self.app.get(self.private_node_one_url, { - 'view_only': self.private_node_one_anonymous_link.key, + # test_private_project_with_anonymous_link_does_not_expose_registrations_or_forks + res = app.get(private_node_one_url, { + 'view_only': private_node_one_anonymous_link.key, }) assert res.status_code == 200 relationships = res.json['data']['relationships'] @@ -185,50 +238,56 @@ def test_private_project_with_anonymous_link_does_not_expose_registrations_or_fo assert 'registrations' not in embeds assert 'forks' not in embeds, 'Add forks view to blacklist in hide_view_when_anonymous().' - def test_bad_view_only_link_does_not_modify_permissions(self): - res = self.app.get(self.private_node_one_url+'logs/', { + # test_bad_view_only_link_does_not_modify_permissions + res = app.get(private_node_one_url+'logs/', { 'view_only': 'thisisnotarealprivatekey', }, expect_errors=True) assert res.status_code == 401 - res = self.app.get(self.private_node_one_url+'logs/', { + res = app.get(private_node_one_url+'logs/', { 'view_only': 'thisisnotarealprivatekey', - }, auth=self.creation_user.auth) + }, auth=creation_user.auth) assert res.status_code == 200 - def test_view_only_key_in_relationships_links(self): - res = self.app.get(self.private_node_one_url, {'view_only': self.private_node_one_private_link.key}) + # test_view_only_key_in_relationships_links + res = app.get(private_node_one_url, {'view_only': private_node_one_private_link.key}) assert res.status_code == 200 res_relationships = res.json['data']['relationships'] for key, value in res_relationships.iteritems(): if value['links'].get('related'): - assert self.private_node_one_private_link.key in value['links']['related']['href'] + assert private_node_one_private_link.key in value['links']['related']['href'] if value['links'].get('self'): - assert self.private_node_one_private_link.key in value['links']['self']['href'] + assert private_node_one_private_link.key in value['links']['self']['href'] - def test_view_only_key_in_self_and_html_links(self): - res = self.app.get(self.private_node_one_url, {'view_only': self.private_node_one_private_link.key}) + # test_view_only_key_in_self_and_html_links + res = app.get(private_node_one_url, {'view_only': private_node_one_private_link.key}) assert res.status_code == 200 links = res.json['data']['links'] - assert self.private_node_one_private_link.key in links['self'] - assert self.private_node_one_private_link.key in links['html'] + assert private_node_one_private_link.key in links['self'] + assert private_node_one_private_link.key in links['html'] @pytest.mark.django_db -class TestNodeListViewOnlyLinks(ViewOnlyTestCase): +@pytest.mark.usefixtures('creation_user', 'viewing_user', 'contributing_read_user', 'contributing_write_user', 'valid_contributors', + 'private_node_one', 'private_node_one_anonymous_link', 'private_node_one_private_link', 'private_node_one_url', + 'private_node_two', 'private_node_two_url', 'public_node_one', 'public_node_one_anonymous_link', + 'public_node_one_private_link', 'public_node_one_url', 'public_node_two', 'public_node_two_url') +class TestNodeListViewOnlyLinks: + + def test_node_list_view_only_links(self, app, valid_contributors, private_node_one, private_node_one_private_link, private_node_one_anonymous_link): - def test_private_link_does_not_show_node_in_list(self): - res = self.app.get('/{}nodes/'.format(API_BASE), { - 'view_only': self.private_node_one_private_link.key, + # test_private_link_does_not_show_node_in_list + res = app.get('/{}nodes/'.format(API_BASE), { + 'view_only': private_node_one_private_link.key, }) assert res.status_code == 200 nodes = res.json['data'] node_ids = [] for node in nodes: node_ids.append(node['id']) - assert self.private_node_one._id not in node_ids + assert private_node_one._id not in node_ids - def test_anonymous_link_does_not_show_contributor_id_in_node_list(self): - res = self.app.get('/{}nodes/'.format(API_BASE), { - 'view_only': self.private_node_one_anonymous_link.key, + # test_anonymous_link_does_not_show_contributor_id_in_node_list + res = app.get('/{}nodes/'.format(API_BASE), { + 'view_only': private_node_one_anonymous_link.key, 'embed': 'contributors', }) assert res.status_code == 200 @@ -241,9 +300,9 @@ def test_anonymous_link_does_not_show_contributor_id_in_node_list(self): assert contributor['id'] == '' assert assertions != 0 - def test_non_anonymous_link_does_show_contributor_id_in_node_list(self): - res = self.app.get('/{}nodes/'.format(API_BASE), { - 'view_only': self.private_node_one_private_link.key, + # test_non_anonymous_link_does_show_contributor_id_in_node_list + res = app.get('/{}nodes/'.format(API_BASE), { + 'view_only': private_node_one_private_link.key, 'embed': 'contributors', }) assert res.status_code == 200 @@ -253,5 +312,5 @@ def test_non_anonymous_link_does_show_contributor_id_in_node_list(self): contributors = node['embeds']['contributors']['data'] for contributor in contributors: assertions += 1 - assert contributor['id'].split('-')[1] in self.valid_contributors + assert contributor['id'].split('-')[1] in valid_contributors assert assertions != 0 diff --git a/tests/utils.py b/tests/utils.py index e1a9c76c34e..7cbb34976b3 100644 --- a/tests/utils.py +++ b/tests/utils.py @@ -7,14 +7,11 @@ from django.utils import timezone from nose import SkipTest from nose.tools import assert_equal, assert_not_equal - from framework.auth import Auth from framework.celery_tasks.handlers import celery_teardown_request - from website.archiver import ARCHIVER_SUCCESS from website.archiver import listeners as archiver_listeners from website.project.sanctions import Sanction - from tests.base import get_default_metaschema def requires_module(module): @@ -46,7 +43,7 @@ def test_update_node(self): def outer_wrapper(func): @functools.wraps(func) def wrapper(self, *args, **kwargs): - node = getattr(self, node_key) + node = getattr(self, node_key) last_log = node.logs.latest() func(self, *args, **kwargs) node.reload() @@ -72,6 +69,16 @@ def wrapper(self, *args, **kwargs): return wrapper return outer_wrapper +@contextlib.contextmanager +def assert_latest_log(log_action, node_key, index=-1): + node = node_key + last_log = node.logs.latest() + node.reload() + yield + new_log = node.logs.order_by('-date')[-index - 1] + assert last_log._id != new_log._id + assert new_log.action == log_action + @contextlib.contextmanager def mock_archive(project, schema=None, auth=None, data=None, parent=None, embargo=False, embargo_end_date=None, From b1af41498b261c6efd55116bc70f1245fdb812d0 Mon Sep 17 00:00:00 2001 From: Rheisen Dennis Date: Mon, 5 Jun 2017 11:14:55 -0400 Subject: [PATCH 043/163] Clean unused imports & remove print statements --- api_tests/nodes/views/test_node_links_detail.py | 2 +- api_tests/nodes/views/test_node_links_list.py | 3 +-- api_tests/nodes/views/test_node_logs.py | 1 - api_tests/nodes/views/test_node_view_only_links_list.py | 2 -- 4 files changed, 2 insertions(+), 6 deletions(-) diff --git a/api_tests/nodes/views/test_node_links_detail.py b/api_tests/nodes/views/test_node_links_detail.py index b6d4f74ad3c..dc10d41dbbf 100644 --- a/api_tests/nodes/views/test_node_links_detail.py +++ b/api_tests/nodes/views/test_node_links_detail.py @@ -1,7 +1,7 @@ import pytest from urlparse import urlparse -from framework.auth.core import Auth # possibly deleted? +from framework.auth.core import Auth from osf.models import NodeLog from api.base.settings.defaults import API_BASE from tests.base import ApiTestCase diff --git a/api_tests/nodes/views/test_node_links_list.py b/api_tests/nodes/views/test_node_links_list.py index 3567204b4d2..5f014962050 100644 --- a/api_tests/nodes/views/test_node_links_list.py +++ b/api_tests/nodes/views/test_node_links_list.py @@ -1,10 +1,9 @@ import pytest from urlparse import urlparse -from framework.auth.core import Auth # possibly deleted? +from framework.auth.core import Auth from osf.models import NodeLog from api.base.settings.defaults import API_BASE -from tests.json_api_test_app import JSONAPITestApp from tests.base import ApiTestCase from tests.utils import assert_latest_log from osf_tests.factories import ( diff --git a/api_tests/nodes/views/test_node_logs.py b/api_tests/nodes/views/test_node_logs.py index e5fdeef1475..1ab4904085f 100644 --- a/api_tests/nodes/views/test_node_logs.py +++ b/api_tests/nodes/views/test_node_logs.py @@ -10,7 +10,6 @@ from website.util import disconnected_from_listeners from website.project.signals import contributor_removed from api.base.settings.defaults import API_BASE -from tests.json_api_test_app import JSONAPITestApp from tests.base import ApiTestCase, assert_datetime_equal from osf_tests.factories import ( ProjectFactory, diff --git a/api_tests/nodes/views/test_node_view_only_links_list.py b/api_tests/nodes/views/test_node_view_only_links_list.py index 1166ec7a587..f9c991a3051 100644 --- a/api_tests/nodes/views/test_node_view_only_links_list.py +++ b/api_tests/nodes/views/test_node_view_only_links_list.py @@ -54,8 +54,6 @@ def test_non_mutating_view_only_links_list_tests(self, app, user, read_write_use res = app.get(url, auth=user.auth) assert res.status_code == 200 data = res.json['data'] - print data - print url assert len(data) == 1 assert data[0]['attributes']['name'] == 'testlink' From cc14df02c78d061762b17404e53ceed6d3ed2fd8 Mon Sep 17 00:00:00 2001 From: Rheisen Dennis Date: Mon, 5 Jun 2017 14:23:24 -0400 Subject: [PATCH 044/163] fix mixin conversion, clean grouping comments --- .../nodes/views/test_node_sparse_fieldsets.py | 22 +- .../views/test_view_only_link_detail.py | 82 +++-- .../views/test_view_only_link_nodes.py | 294 +++++++++++------- 3 files changed, 245 insertions(+), 153 deletions(-) diff --git a/api_tests/nodes/views/test_node_sparse_fieldsets.py b/api_tests/nodes/views/test_node_sparse_fieldsets.py index e2b1556b456..ae56e34f189 100644 --- a/api_tests/nodes/views/test_node_sparse_fieldsets.py +++ b/api_tests/nodes/views/test_node_sparse_fieldsets.py @@ -34,14 +34,14 @@ def url(self): def test_node_sparse_fields_list(self, app, user, deleted_project, private_project, public_project, url): - # def test_empty_fields_returns_no_attributes(self): + # test_empty_fields_returns_no_attributes res = app.get(url) node_json = res.json['data'][0] assert node_json['attributes'] == {} assert set(node_json.keys()) == set(['links', 'type', 'id', 'attributes']) - # def test_sparse_fields_includes_relationships(self): + # test_sparse_fields_includes_relationships res = app.get(url + 'children') node_json = res.json['data'][0] @@ -49,7 +49,7 @@ def test_node_sparse_fields_list(self, app, user, deleted_project, private_proje assert set(node_json.keys()) == set(['links', 'type', 'id', 'attributes', 'relationships']) assert node_json['relationships']['children']['links']['related']['href'].endswith('/{}nodes/{}/children/'.format(API_BASE, public_project._id)) - # def test_returns_expected_nodes(self): + # test_returns_expected_nodes res = app.get(url + 'title') node_json = res.json['data'] @@ -64,7 +64,7 @@ def test_node_sparse_fields_list(self, app, user, deleted_project, private_proje assert len(node_json['attributes']) == 1 assert set(node_json.keys()) == set(['links', 'type', 'id', 'attributes']) - # def test_filtering_by_id(self): + # test_filtering_by_id url = '/{}nodes/?filter[id]={}&fields[nodes]='.format(API_BASE, public_project._id) res = app.get(url) assert [each['id'] for each in res.json['data']] == [public_project._id] @@ -73,7 +73,7 @@ def test_node_sparse_fields_list(self, app, user, deleted_project, private_proje assert set(node_json.keys()) == set(['links', 'type', 'id', 'attributes']) assert node_json['attributes'] == {} - # def test_filtering_by_excluded_field(self): + # test_filtering_by_excluded_field url = '/{}nodes/?filter[title]={}&fields[nodes]='.format(API_BASE, public_project.title) res = app.get(url) assert [each['id'] for each in res.json['data']] == [public_project._id] @@ -82,7 +82,7 @@ def test_node_sparse_fields_list(self, app, user, deleted_project, private_proje assert set(node_json.keys()) == set(['links', 'type', 'id', 'attributes']) assert node_json['attributes'] == {} - # def test_create_with_sparse_fields(self): + # test_create_with_sparse_fields payload = { 'data': { 'type': 'nodes', @@ -113,14 +113,14 @@ def url(self, node): def test_node_sparse_fields_detail_non_mutating_tests(self, app, user, node, url): - # def test_empty_fields_returns_no_attributes(self, app, url): + # test_empty_fields_returns_no_attributes res = app.get(url + '?fields[nodes]=') node_json = res.json['data'] assert node_json['attributes'] == {} assert set(node_json.keys()) == set(['links', 'type', 'id', 'attributes']) - # def test_embed_sparse_same_type(self, app, user, node, url): + # test_embed_sparse_same_type child = ProjectFactory(parent=node, is_public=True, creator=user) res_url = '{}?embed=children&fields[nodes]=title,children'.format(url) res = app.get(res_url) @@ -132,7 +132,7 @@ def test_node_sparse_fields_detail_non_mutating_tests(self, app, user, node, url assert node_json['embeds']['children']['data'][0]['attributes'].keys() == ['title'] assert node_json['embeds']['children']['data'][0]['attributes']['title'] == child.title - # def test_embed_sparse_different_types(self, app, user, node, url): + # test_embed_sparse_different_types res_url = '{}?embed=contributors&fields[nodes]=title,contributors'.format(url) res = app.get(res_url) node_json = res.json['data'] @@ -143,7 +143,7 @@ def test_node_sparse_fields_detail_non_mutating_tests(self, app, user, node, url assert node_json['embeds']['contributors']['data'][0]['id'] == '{}-{}'.format(node._id, user._id) assert len(node_json['embeds']['contributors']['data'][0]['attributes']) > 1 - # def test_sparse_embedded_type(self): + # test_sparse_embedded_type res_url = '{}?embed=contributors&fields[contributors]='.format(url) res = app.get(res_url) node_json = res.json['data'] @@ -154,7 +154,7 @@ def test_node_sparse_fields_detail_non_mutating_tests(self, app, user, node, url assert node_json['embeds']['contributors']['data'][0]['id'] == '{}-{}'.format(node._id, user._id) assert len(node_json['embeds']['contributors']['data'][0]['attributes']) == 0 - # def test_multiple_sparse_types(self): + # test_multiple_sparse_types res_url = '{}?fields[nodes]=contributors,title&embed=contributors&fields[contributors]=bibliographic'.format(url) res = app.get(res_url) node_json = res.json['data'] diff --git a/api_tests/view_only_links/views/test_view_only_link_detail.py b/api_tests/view_only_links/views/test_view_only_link_detail.py index e5106749819..733f57c40ed 100644 --- a/api_tests/view_only_links/views/test_view_only_link_detail.py +++ b/api_tests/view_only_links/views/test_view_only_link_detail.py @@ -1,33 +1,71 @@ -from nose.tools import * # flake8: noqa +import pytest +from website.util import permissions from api.base.settings.defaults import API_BASE +from tests.base import ApiTestCase +from osf_tests.factories import ( + ProjectFactory, + AuthUserFactory, + PrivateLinkFactory +) -from api_tests.nodes.views.test_node_view_only_links_list import ViewOnlyLinkTestCase +@pytest.mark.django_db +class TestViewOnlyLinksDetail: + @pytest.fixture() + def user(self): + return AuthUserFactory() -class TestViewOnlyLinksDetail(ViewOnlyLinkTestCase): + @pytest.fixture() + def read_only_user(self): + return AuthUserFactory() - def setUp(self): - super(TestViewOnlyLinksDetail, self).setUp() - self.url = '/{}view_only_links/{}/'.format(API_BASE, self.view_only_link._id) + @pytest.fixture() + def read_write_user(self): + return AuthUserFactory() - def test_admin_can_view_vol_detail(self): - res = self.app.get(self.url, auth=self.user.auth) - assert_equal(res.status_code, 200) - assert_equal(res.json['data']['attributes']['name'], 'testlink') + @pytest.fixture() + def non_contributor(self): + return AuthUserFactory() - def test_read_write_cannot_view_vol_detail(self): - res = self.app.get(self.url, auth=self.read_write_user.auth, expect_errors=True) - assert_equal(res.status_code, 403) + @pytest.fixture() + def public_project(self, user, read_only_user, read_write_user): + public_project = ProjectFactory(is_public=True, creator=user) + public_project.add_contributor(read_only_user, permissions=[permissions.READ]) + public_project.add_contributor(read_write_user, permissions=[permissions.WRITE]) + public_project.save() + return public_project - def test_read_only_cannot_view_vol_detail(self): - res = self.app.get(self.url, auth=self.read_only_user.auth, expect_errors=True) - assert_equal(res.status_code, 403) + @pytest.fixture() + def view_only_link(self, public_project): + view_only_link = PrivateLinkFactory(name='testlink') + view_only_link.nodes.add(public_project) + view_only_link.save() + return view_only_link - def test_logged_in_user_cannot_view_vol_detail(self): - res = self.app.get(self.url, auth=self.non_contributor.auth, expect_errors=True) - assert_equal(res.status_code, 403) + @pytest.fixture() + def url(self, view_only_link): + return '/{}view_only_links/{}/'.format(API_BASE, view_only_link._id) - def test_unauthenticated_user_cannot_view_vol_detail(self): - res = self.app.get(self.url, expect_errors=True) - assert_equal(res.status_code, 403) + def test_view_only_links_detail(self, app, user, read_only_user, read_write_user, non_contributor, url): + + # test_admin_can_view_vol_detail + res = app.get(url, auth=user.auth) + assert res.status_code == 200 + assert res.json['data']['attributes']['name'] == 'testlink' + + # test_read_write_cannot_view_vol_detail + res = app.get(url, auth=read_write_user.auth, expect_errors=True) + assert res.status_code == 403 + + # test_read_only_cannot_view_vol_detail + res = app.get(url, auth=read_only_user.auth, expect_errors=True) + assert res.status_code == 403 + + # test_logged_in_user_cannot_view_vol_detail + res = app.get(url, auth=non_contributor.auth, expect_errors=True) + assert res.status_code == 403 + + # test_unauthenticated_user_cannot_view_vol_detail + res = app.get(url, expect_errors=True) + assert res.status_code == 403 diff --git a/api_tests/view_only_links/views/test_view_only_link_nodes.py b/api_tests/view_only_links/views/test_view_only_link_nodes.py index 5345a32de26..8ad031eb969 100644 --- a/api_tests/view_only_links/views/test_view_only_link_nodes.py +++ b/api_tests/view_only_links/views/test_view_only_link_nodes.py @@ -1,111 +1,164 @@ +import pytest from nose.tools import * # flake8: noqa +from website.util import permissions from api.base.settings.defaults import API_BASE - -from api_tests.nodes.views.test_node_view_only_links_list import ViewOnlyLinkTestCase - -from osf_tests.factories import NodeFactory - - -class TestViewOnlyLinksNodes(ViewOnlyLinkTestCase): - - def setUp(self): - super(TestViewOnlyLinksNodes, self).setUp() - self.url = '/{}view_only_links/{}/nodes/'.format(API_BASE, self.view_only_link._id) - - def test_admin_can_view_vol_nodes_detail(self): - res = self.app.get(self.url, auth=self.user.auth) - assert_equal(res.status_code, 200) - - def test_read_write_cannot_view_vol_detail(self): - res = self.app.get(self.url, auth=self.read_write_user.auth, expect_errors=True) - assert_equal(res.status_code, 403) - - def test_read_only_cannot_view_vol_detail(self): - res = self.app.get(self.url, auth=self.read_only_user.auth, expect_errors=True) - assert_equal(res.status_code, 403) - - def test_logged_in_user_cannot_view_vol_detail(self): - res = self.app.get(self.url, auth=self.non_contributor.auth, expect_errors=True) - assert_equal(res.status_code, 403) - - def test_unauthenticated_user_cannot_view_vol_detail(self): - res = self.app.get(self.url, expect_errors=True) - assert_equal(res.status_code, 403) - - -class TestViewOnlyLinkNodesSet(ViewOnlyLinkTestCase): - - def setUp(self): - super(TestViewOnlyLinkNodesSet, self).setUp() - self.component_one = NodeFactory(creator=self.user, parent=self.public_project, is_public=True) - self.component_two = NodeFactory(creator=self.user, parent=self.public_project, is_public=False) - - self.project_two = NodeFactory(creator=self.user) - - self.first_level_component = NodeFactory(creator=self.user, parent=self.public_project) - self.second_level_component = NodeFactory(creator=self.user, parent=self.first_level_component) - - self.component_one_payload = { +from tests.base import ApiTestCase +from osf_tests.factories import ( + ProjectFactory, + AuthUserFactory, + PrivateLinkFactory, + NodeFactory +) + + +@pytest.fixture(scope='function') +def user(): + return AuthUserFactory() + +@pytest.fixture(scope='function') +def read_only_user(): + return AuthUserFactory() + +@pytest.fixture(scope='function') +def read_write_user(): + return AuthUserFactory() + +@pytest.fixture(scope='function') +def non_contributor(): + return AuthUserFactory() + +@pytest.fixture(scope='function') +def public_project(user, read_only_user, read_write_user): + public_project = ProjectFactory(is_public=True, creator=user) + public_project.add_contributor(read_only_user, permissions=[permissions.READ]) + public_project.add_contributor(read_write_user, permissions=[permissions.WRITE]) + public_project.save() + return public_project + +@pytest.fixture(scope='function') +def view_only_link(public_project): + view_only_link = PrivateLinkFactory(name='testlink') + view_only_link.nodes.add(public_project) + view_only_link.save() + return view_only_link + +@pytest.mark.django_db +class TestViewOnlyLinksNodes: + + @pytest.fixture() + def url(self, view_only_link): + return '/{}view_only_links/{}/nodes/'.format(API_BASE, view_only_link._id) + + def test_view_only_links_nodes(self, app, user, read_only_user, read_write_user, non_contributor, url): + + # test_admin_can_view_vol_nodes_detail + res = app.get(url, auth=user.auth) + assert res.status_code == 200 + + # test_read_write_cannot_view_vol_detail + res = app.get(url, auth=read_write_user.auth, expect_errors=True) + assert res.status_code == 403 + + # test_read_only_cannot_view_vol_detail + res = app.get(url, auth=read_only_user.auth, expect_errors=True) + assert res.status_code == 403 + + # test_logged_in_user_cannot_view_vol_detail + res = app.get(url, auth=non_contributor.auth, expect_errors=True) + assert res.status_code == 403 + + # test_unauthenticated_user_cannot_view_vol_detail + res = app.get(url, expect_errors=True) + assert res.status_code == 403 + +@pytest.mark.django_db +class TestViewOnlyLinkNodesSet: + + @pytest.fixture() + def component_one(self, user, public_project): + return NodeFactory(creator=user, parent=public_project, is_public=True) + + @pytest.fixture() + def component_two(self, user, public_project): + return NodeFactory(creator=user, parent=public_project, is_public=False) + + @pytest.fixture() + def project_two(self, user): + return NodeFactory(creator=user) + + @pytest.fixture() + def first_level_component(self, user, public_project): + return NodeFactory(creator=user, parent=public_project) + + @pytest.fixture() + def second_level_component(self, user, first_level_component): + return NodeFactory(creator=user, parent=first_level_component) + + @pytest.fixture() + def component_one_payload(self, component_one): + return { 'data': [ { 'type': 'nodes', - 'id': self.component_one._id + 'id': component_one._id } ] } - self.url = '/{}view_only_links/{}/relationships/nodes/'.format(API_BASE, self.view_only_link._id) + @pytest.fixture() + def url(self, view_only_link): + return '/{}view_only_links/{}/relationships/nodes/'.format(API_BASE, view_only_link._id) - def test_admin_can_set_single_node(self): - res = self.app.post_json_api(self.url, self.component_one_payload, auth=self.user.auth) - self.view_only_link.reload() - assert_equal(res.status_code, 201) - assert_in(self.public_project, self.view_only_link.nodes.all()) - assert_in(self.component_one, self.view_only_link.nodes.all()) + def test_admin_can_set_single_node(self, app, user, public_project, component_one, component_one_payload, view_only_link, url): + res = app.post_json_api(url, component_one_payload, auth=user.auth) + view_only_link.reload() + assert res.status_code == 201 + assert public_project in view_only_link.nodes.all() + assert component_one in view_only_link.nodes.all() - def test_admin_can_set_multiple_nodes(self): + def test_admin_can_set_multiple_nodes(self, app, user, public_project, component_one, component_two, view_only_link, url): payload = { 'data': [ { 'type': 'nodes', - 'id': self.component_one._id + 'id': component_one._id }, { 'type': 'nodes', - 'id': self.component_two._id + 'id': component_two._id } ] } - res = self.app.post_json_api(self.url, payload, auth=self.user.auth) - self.view_only_link.reload() - assert_equal(res.status_code, 201) - assert_in(self.public_project, self.view_only_link.nodes.all()) - assert_in(self.component_one, self.view_only_link.nodes.all()) - assert_in(self.component_two, self.view_only_link.nodes.all()) - - def test_set_nodes_does_not_duplicate_nodes(self): + res = app.post_json_api(url, payload, auth=user.auth) + view_only_link.reload() + assert res.status_code == 201 + assert public_project in view_only_link.nodes.all() + assert component_one in view_only_link.nodes.all() + assert component_two in view_only_link.nodes.all() + + def test_set_nodes_does_not_duplicate_nodes(self, app, user, public_project, component_one, view_only_link, url): payload = { 'data': [ { 'type': 'nodes', - 'id': self.public_project._id + 'id': public_project._id }, { 'type': 'nodes', - 'id': self.component_one._id + 'id': component_one._id }, { 'type': 'nodes', - 'id': self.component_one._id + 'id': component_one._id } ] } - res = self.app.post_json_api(self.url, payload, auth=self.user.auth) - self.view_only_link.reload() - assert_equal(res.status_code, 201) - assert_equal(self.view_only_link.nodes.count(), 2) - assert_in(self.public_project, self.view_only_link.nodes.all()) - assert_in(self.component_one, self.view_only_link.nodes.all()) - - def test_set_node_not_component(self): + res = app.post_json_api(url, payload, auth=user.auth) + view_only_link.reload() + assert res.status_code == 201 + assert view_only_link.nodes.count() == 2 + assert public_project in view_only_link.nodes.all() + assert component_one in view_only_link.nodes.all() + + def test_set_node_not_component(self, app, user, project_two, url): """ Project One (already associated with VOL) -> Level One Component (can be associated with VOL) @@ -116,15 +169,15 @@ def test_set_node_not_component(self): 'data': [ { 'type': 'nodes', - 'id': self.project_two._id + 'id': project_two._id }, ] } - res = self.app.post_json_api(self.url, payload, auth=self.user.auth, expect_errors=True) - assert_equal(res.status_code, 400) - assert_equal(res.json['errors'][0]['detail'], 'The node {0} cannot be affiliated with this View Only Link because the node you\'re trying to affiliate is not descended from the node that the View Only Link is attached to.'.format(self.project_two._id)) + res = app.post_json_api(url, payload, auth=user.auth, expect_errors=True) + assert res.status_code == 400 + assert res.json['errors'][0]['detail'] == 'The node {0} cannot be affiliated with this View Only Link because the node you\'re trying to affiliate is not descended from the node that the View Only Link is attached to.'.format(project_two._id) - def test_set_node_second_level_component_without_first_level_parent(self): + def test_set_node_second_level_component_without_first_level_parent(self, app, user, public_project, second_level_component, view_only_link, url): """ Parent Project (already associated with VOL) -> First Level Component (NOT included) @@ -134,18 +187,18 @@ def test_set_node_second_level_component_without_first_level_parent(self): 'data': [ { 'type': 'nodes', - 'id': self.second_level_component._id + 'id': second_level_component._id }, ] } - res = self.app.post_json_api(self.url, payload, auth=self.user.auth, expect_errors=True) - self.view_only_link.reload() - assert_equal(res.status_code, 201) - assert_equal(len(res.json['data']), 2) - assert_in(self.public_project, self.view_only_link.nodes.all()) - assert_in(self.second_level_component, self.view_only_link.nodes.all()) - - def test_set_node_second_level_component_with_first_level_parent(self): + res = app.post_json_api(url, payload, auth=user.auth, expect_errors=True) + view_only_link.reload() + assert res.status_code == 201 + assert len(res.json['data']) == 2 + assert public_project in view_only_link.nodes.all() + assert second_level_component in view_only_link.nodes.all() + + def test_set_node_second_level_component_with_first_level_parent(self, app, user, first_level_component, second_level_component, view_only_link, url): """ Parent Project (already associated with VOL) -> First Level Component (included) @@ -155,64 +208,65 @@ def test_set_node_second_level_component_with_first_level_parent(self): 'data': [ { 'type': 'nodes', - 'id': self.first_level_component._id + 'id': first_level_component._id }, { 'type': 'nodes', - 'id': self.second_level_component._id + 'id': second_level_component._id } ] } - res = self.app.post_json_api(self.url, payload, auth=self.user.auth) - self.view_only_link.reload() - assert_equal(res.status_code, 201) - assert_in(self.first_level_component, self.view_only_link.nodes.all()) - assert_in(self.second_level_component, self.view_only_link.nodes.all()) + res = app.post_json_api(url, payload, auth=user.auth) + view_only_link.reload() + assert res.status_code == 201 + assert first_level_component in view_only_link.nodes.all() + assert second_level_component in view_only_link.nodes.all() - def test_invalid_nodes_in_payload(self): + def test_view_only_link_nodes_set_errors(self, app, user, read_write_user, read_only_user, non_contributor, component_one_payload, component_one, url): + + # test_invalid_nodes_in_payload payload = { 'data': [{ 'type': 'nodes', 'id': 'abcde' }] } - res = self.app.post_json_api(self.url, payload, auth=self.user.auth, expect_errors=True) - assert_equal(res.status_code, 404) + res = app.post_json_api(url, payload, auth=user.auth, expect_errors=True) + assert res.status_code == 404 - def test_type_required_in_payload(self): + # test_type_required_in_payload payload = { 'data': [{ - 'id': self.component_one._id + 'id': component_one._id }] } - res = self.app.post_json_api(self.url, payload, auth=self.user.auth, expect_errors=True) - assert_equal(res.status_code, 400) + res = app.post_json_api(url, payload, auth=user.auth, expect_errors=True) + assert res.status_code == 400 - def test_id_required_in_payload(self): + # test_id_required_in_payload payload = { 'data': [{ 'type': 'nodes', }] } - res = self.app.post_json_api(self.url, payload, auth=self.user.auth, expect_errors=True) - assert_equal(res.status_code, 400) + res = app.post_json_api(url, payload, auth=user.auth, expect_errors=True) + assert res.status_code == 400 - def test_read_write_contributor_cannot_set_nodes(self): - res = self.app.post_json_api(self.url, self.component_one_payload, auth=self.read_write_user.auth, expect_errors=True) - assert_equal(res.status_code, 403) + # test_read_write_contributor_cannot_set_nodes + res = app.post_json_api(url, component_one_payload, auth=read_write_user.auth, expect_errors=True) + assert res.status_code == 403 - def test_read_only_contributor_cannot_set_nodes(self): - res = self.app.post_json_api(self.url, self.component_one_payload, auth=self.read_only_user.auth, expect_errors=True) - assert_equal(res.status_code, 403) + # test_read_only_contributor_cannot_set_nodes + res = app.post_json_api(url, component_one_payload, auth=read_only_user.auth, expect_errors=True) + assert res.status_code == 403 - def test_logged_in_user_cannot_set_nodes(self): - res = self.app.post_json_api(self.url, self.component_one_payload, auth=self.non_contributor.auth, expect_errors=True) - assert_equal(res.status_code, 403) - - def test_unauthenticated_user_cannot_set_nodes(self): - res = self.app.post_json_api(self.url, self.component_one_payload, expect_errors=True) - assert_equal(res.status_code, 401) + # test_logged_in_user_cannot_set_nodes + res = app.post_json_api(url, component_one_payload, auth=non_contributor.auth, expect_errors=True) + assert res.status_code == 403 + # test_unauthenticated_user_cannot_set_nodes + res = app.post_json_api(url, component_one_payload, expect_errors=True) + assert res.status_code == 401 class TestViewOnlyLinkNodesUpdate(TestViewOnlyLinkNodesSet): From 8599671f3d6eb38675859ec49deadcef0ec3fe0e Mon Sep 17 00:00:00 2001 From: Alex Schiller Date: Mon, 5 Jun 2017 16:13:46 -0400 Subject: [PATCH 045/163] Fix imports --- admin/nodes/views.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/admin/nodes/views.py b/admin/nodes/views.py index a3718166c2f..891939ec60d 100644 --- a/admin/nodes/views.py +++ b/admin/nodes/views.py @@ -16,7 +16,7 @@ from osf.models import SpamStatus from admin.base.views import GuidFormView, GuidView from osf.models.admin_log_entry import ( - update_admin_log + update_admin_log, NODE_REMOVED, NODE_RESTORED, CONTRIBUTOR_REMOVED, @@ -27,7 +27,6 @@ ) from admin.nodes.templatetags.node_extras import reverse_node from admin.nodes.serializers import serialize_node, serialize_simple_user_and_node_permissions -from website.project.spam.model import SpamStatus from website.project.tasks import update_share from website.project.views.register import osf_admin_change_status_identifier From a76dc2fbfa7a81dac258ae88b5e4c8350e29aae5 Mon Sep 17 00:00:00 2001 From: Rheisen Dennis Date: Mon, 5 Jun 2017 16:32:01 -0400 Subject: [PATCH 046/163] abstract fixtures, prevent duplicate running of tests --- .../views/test_view_only_link_nodes.py | 355 +++++++++--------- 1 file changed, 181 insertions(+), 174 deletions(-) diff --git a/api_tests/view_only_links/views/test_view_only_link_nodes.py b/api_tests/view_only_links/views/test_view_only_link_nodes.py index 8ad031eb969..abee5276c33 100644 --- a/api_tests/view_only_links/views/test_view_only_link_nodes.py +++ b/api_tests/view_only_links/views/test_view_only_link_nodes.py @@ -43,6 +43,37 @@ def view_only_link(public_project): view_only_link.save() return view_only_link +@pytest.fixture() +def component_one(user, public_project): + return NodeFactory(creator=user, parent=public_project, is_public=True) + +@pytest.fixture() +def component_two(user, public_project): + return NodeFactory(creator=user, parent=public_project, is_public=False) + +@pytest.fixture() +def project_two(user): + return NodeFactory(creator=user) + +@pytest.fixture() +def first_level_component(user, public_project): + return NodeFactory(creator=user, parent=public_project) + +@pytest.fixture() +def second_level_component(user, first_level_component): + return NodeFactory(creator=user, parent=first_level_component) + +@pytest.fixture() +def component_one_payload(component_one): + return { + 'data': [ + { + 'type': 'nodes', + 'id': component_one._id + } + ] + } + @pytest.mark.django_db class TestViewOnlyLinksNodes: @@ -75,37 +106,6 @@ def test_view_only_links_nodes(self, app, user, read_only_user, read_write_user, @pytest.mark.django_db class TestViewOnlyLinkNodesSet: - @pytest.fixture() - def component_one(self, user, public_project): - return NodeFactory(creator=user, parent=public_project, is_public=True) - - @pytest.fixture() - def component_two(self, user, public_project): - return NodeFactory(creator=user, parent=public_project, is_public=False) - - @pytest.fixture() - def project_two(self, user): - return NodeFactory(creator=user) - - @pytest.fixture() - def first_level_component(self, user, public_project): - return NodeFactory(creator=user, parent=public_project) - - @pytest.fixture() - def second_level_component(self, user, first_level_component): - return NodeFactory(creator=user, parent=first_level_component) - - @pytest.fixture() - def component_one_payload(self, component_one): - return { - 'data': [ - { - 'type': 'nodes', - 'id': component_one._id - } - ] - } - @pytest.fixture() def url(self, view_only_link): return '/{}view_only_links/{}/relationships/nodes/'.format(API_BASE, view_only_link._id) @@ -268,90 +268,95 @@ def test_view_only_link_nodes_set_errors(self, app, user, read_write_user, read_ res = app.post_json_api(url, component_one_payload, expect_errors=True) assert res.status_code == 401 -class TestViewOnlyLinkNodesUpdate(TestViewOnlyLinkNodesSet): +@pytest.mark.django_db +class TestViewOnlyLinkNodesUpdate: - def setUp(self): - super(TestViewOnlyLinkNodesUpdate, self).setUp() - self.update_payload = { + @pytest.fixture() + def url(self, view_only_link): + return '/{}view_only_links/{}/relationships/nodes/'.format(API_BASE, view_only_link._id) + + @pytest.fixture() + def update_payload(self, public_project, component_one): + return { 'data': [{ 'type': 'nodes', - 'id': self.public_project._id + 'id': public_project._id }, { 'type': 'nodes', - 'id': self.component_one._id + 'id': component_one._id }] } - def test_admin_can_update_nodes_single_node_to_add(self): - res = self.app.put_json_api(self.url, self.update_payload, auth=self.user.auth) - self.view_only_link.reload() - assert_equal(res.status_code, 200) - assert_equal(len(res.json['data']), 2) - assert_in(self.public_project, self.view_only_link.nodes.all()) - assert_in(self.component_one, self.view_only_link.nodes.all()) + def test_admin_can_update_nodes_single_node_to_add(self, app, user, url, public_project, component_one, view_only_link, update_payload): + res = app.put_json_api(url, update_payload, auth=user.auth) + view_only_link.reload() + assert res.status_code == 200 + assert len(res.json['data']) == 2 + assert public_project in view_only_link.nodes.all() + assert component_one in view_only_link.nodes.all() - def test_admin_can_update_nodes_multiple_nodes_to_add(self): - self.update_payload['data'].append({ + def test_admin_can_update_nodes_multiple_nodes_to_add(self, app, user, public_project, component_one, component_two, view_only_link, url, update_payload): + update_payload['data'].append({ 'type': 'nodes', - 'id': self.component_two._id + 'id': component_two._id }) - res = self.app.put_json_api(self.url, self.update_payload, auth=self.user.auth) - self.view_only_link.reload() - assert_equal(res.status_code, 200) - assert_equal(len(res.json['data']), 3) - assert_in(self.public_project, self.view_only_link.nodes.all()) - assert_in(self.component_one, self.view_only_link.nodes.all()) - assert_in(self.component_two, self.view_only_link.nodes.all()) - - def test_admin_can_update_nodes_single_node_to_remove(self): - self.view_only_link.nodes.add(self.component_one) - self.view_only_link.save() - self.update_payload['data'].pop() - res = self.app.put_json_api(self.url, self.update_payload, auth=self.user.auth) - self.view_only_link.reload() - assert_equal(res.status_code, 200) - assert_equal(len(res.json['data']), 1) - assert_in(self.public_project, self.view_only_link.nodes.all()) - assert_not_in(self.component_one, self.view_only_link.nodes.all()) - - def test_admin_can_update_nodes_multiple_nodes_to_remove(self): - self.view_only_link.nodes.add(self.component_one) - self.view_only_link.nodes.add(self.component_two) - self.view_only_link.save() - self.update_payload['data'].pop() - res = self.app.put_json_api(self.url, self.update_payload, auth=self.user.auth) - self.view_only_link.reload() - assert_equal(res.status_code, 200) - assert_equal(len(res.json['data']), 1) - assert_in(self.public_project, self.view_only_link.nodes.all()) - assert_not_in(self.component_one, self.view_only_link.nodes.all()) - assert_not_in(self.component_two, self.view_only_link.nodes.all()) - - - def test_admin_can_update_nodes_single_add_single_remove(self): - self.view_only_link.nodes.add(self.component_two) - self.view_only_link.save() - res = self.app.put_json_api(self.url, self.update_payload, auth=self.user.auth) - self.view_only_link.reload() - assert_equal(res.status_code, 200) - assert_equal(len(res.json['data']), 2) - assert_in(self.public_project, self.view_only_link.nodes.all()) - assert_in(self.component_one, self.view_only_link.nodes.all()) - assert_not_in(self.component_two, self.view_only_link.nodes.all()) - - - def test_admin_can_update_nodes_multiple_add_multiple_remove(self): - self.view_only_link.nodes.add(self.component_one) - self.view_only_link.nodes.add(self.component_two) - self.view_only_link.save() - - component_three = NodeFactory(creator=self.user, parent=self.public_project) - component_four = NodeFactory(creator=self.user, parent=self.public_project) + res = app.put_json_api(url, update_payload, auth=user.auth) + view_only_link.reload() + assert res.status_code == 200 + assert len(res.json['data']) == 3 + assert public_project in view_only_link.nodes.all() + assert component_one in view_only_link.nodes.all() + assert component_two in view_only_link.nodes.all() + + def test_admin_can_update_nodes_single_node_to_remove(self, app, user, public_project, component_one, view_only_link, update_payload, url): + view_only_link.nodes.add(component_one) + view_only_link.save() + update_payload['data'].pop() + res = app.put_json_api(url, update_payload, auth=user.auth) + view_only_link.reload() + assert res.status_code == 200 + assert len(res.json['data']) == 1 + assert public_project in view_only_link.nodes.all() + assert component_one not in view_only_link.nodes.all() + + def test_admin_can_update_nodes_multiple_nodes_to_remove(self, app, user, public_project, component_one, component_two, view_only_link, update_payload, url,): + view_only_link.nodes.add(component_one) + view_only_link.nodes.add(component_two) + view_only_link.save() + update_payload['data'].pop() + res = app.put_json_api(url, update_payload, auth=user.auth) + view_only_link.reload() + assert res.status_code == 200 + assert len(res.json['data']) == 1 + assert public_project in view_only_link.nodes.all() + assert component_one not in view_only_link.nodes.all() + assert component_two not in view_only_link.nodes.all() + + + def test_admin_can_update_nodes_single_add_single_remove(self, app, user, public_project, component_one, component_two, view_only_link, update_payload, url): + view_only_link.nodes.add(component_two) + view_only_link.save() + res = app.put_json_api(url, update_payload, auth=user.auth) + view_only_link.reload() + assert res.status_code == 200 + assert len(res.json['data']) == 2 + assert public_project in view_only_link.nodes.all() + assert component_one in view_only_link.nodes.all() + assert component_two not in view_only_link.nodes.all() + + + def test_admin_can_update_nodes_multiple_add_multiple_remove(self, app, user, public_project, component_one, component_two, view_only_link, url): + view_only_link.nodes.add(component_one) + view_only_link.nodes.add(component_two) + view_only_link.save() + + component_three = NodeFactory(creator=user, parent=public_project) + component_four = NodeFactory(creator=user, parent=public_project) payload = { 'data': [{ 'type': 'nodes', - 'id': self.public_project._id, + 'id': public_project._id, }, { 'type': 'nodes', 'id': component_three._id @@ -361,30 +366,30 @@ def test_admin_can_update_nodes_multiple_add_multiple_remove(self): }] } - res = self.app.put_json_api(self.url, payload, auth=self.user.auth) - self.view_only_link.reload() - assert_equal(res.status_code, 200) - assert_equal(len(res.json['data']), 3) - assert_in(self.public_project, self.view_only_link.nodes.all()) - assert_not_in(self.component_one, self.view_only_link.nodes.all()) - assert_not_in(self.component_two, self.view_only_link.nodes.all()) - assert_in(component_three, self.view_only_link.nodes.all()) - assert_in(component_four, self.view_only_link.nodes.all()) - - def test_update_nodes_no_changes(self): + res = app.put_json_api(url, payload, auth=user.auth) + view_only_link.reload() + assert res.status_code == 200 + assert len(res.json['data']) == 3 + assert public_project in view_only_link.nodes.all() + assert component_one not in view_only_link.nodes.all() + assert component_two not in view_only_link.nodes.all() + assert component_three in view_only_link.nodes.all() + assert component_four in view_only_link.nodes.all() + + def test_update_nodes_no_changes(self, app, user, public_project, view_only_link, url): payload = { 'data': [{ 'type': 'nodes', - 'id': self.public_project._id, + 'id': public_project._id, }] } - res = self.app.put_json_api(self.url, payload, auth=self.user.auth, expect_errors=True) - self.view_only_link.reload() - assert_equal(res.status_code, 200) - assert_equal(len(res.json['data']), 1) - assert_in(self.public_project, self.view_only_link.nodes.all()) + res = app.put_json_api(url, payload, auth=user.auth, expect_errors=True) + view_only_link.reload() + assert res.status_code == 200 + assert len(res.json['data']) == 1 + assert public_project in view_only_link.nodes.all() - def test_update_nodes_top_level_node_not_included(self): + def test_update_nodes_top_level_node_not_included(self, app, user, component_one, url): """ Parent Project (NOT included) -> First Level Component (included) -- NOT ALLOWED @@ -392,25 +397,25 @@ def test_update_nodes_top_level_node_not_included(self): payload = { 'data': [{ 'type': 'nodes', - 'id': self.component_one._id + 'id': component_one._id }] } - res = self.app.put_json_api(self.url, payload, auth=self.user.auth, expect_errors=True) - assert_equal(res.status_code, 400) - assert_equal(res.json['errors'][0]['detail'], 'The node {0} cannot be affiliated with this View Only Link because the node you\'re trying to affiliate is not descended from the node that the View Only Link is attached to.'.format(self.component_one._id)) + res = app.put_json_api(url, payload, auth=user.auth, expect_errors=True) + assert res.status_code == 400 + assert res.json['errors'][0]['detail'] == 'The node {0} cannot be affiliated with this View Only Link because the node you\'re trying to affiliate is not descended from the node that the View Only Link is attached to.'.format(component_one._id) - def test_update_node_not_component(self): + def test_update_node_not_component(self, app, user, project_two, component_two, url): payload = { 'data': [{ 'type': 'nodes', - 'id': self.project_two._id + 'id': project_two._id }] } - res = self.app.put_json_api(self.url, payload, auth=self.user.auth, expect_errors=True) - assert_equal(res.status_code, 400) - assert_equal(res.json['errors'][0]['detail'], 'The node {0} cannot be affiliated with this View Only Link because the node you\'re trying to affiliate is not descended from the node that the View Only Link is attached to.'.format(self.project_two._id)) + res = app.put_json_api(url, payload, auth=user.auth, expect_errors=True) + assert res.status_code == 400 + assert res.json['errors'][0]['detail'] == 'The node {0} cannot be affiliated with this View Only Link because the node you\'re trying to affiliate is not descended from the node that the View Only Link is attached to.'.format(project_two._id) - def test_update_node_second_level_component_without_first_level_parent(self): + def test_update_node_second_level_component_without_first_level_parent(self, app, user, public_project, second_level_component, view_only_link, url): """ Parent Project (included) -> First Level Component (NOT included) @@ -419,20 +424,20 @@ def test_update_node_second_level_component_without_first_level_parent(self): payload = { 'data': [{ 'type': 'nodes', - 'id': self.public_project._id + 'id': public_project._id }, { 'type': 'nodes', - 'id': self.second_level_component._id + 'id': second_level_component._id }] } - res = self.app.put_json_api(self.url, payload, auth=self.user.auth, expect_errors=True) - self.view_only_link.reload() - assert_equal(res.status_code, 200) - assert_equal(len(res.json['data']), 2) - assert_in(self.public_project, self.view_only_link.nodes.all()) - assert_in(self.second_level_component, self.view_only_link.nodes.all()) - - def test_update_node_second_level_component_with_first_level_parent(self): + res = app.put_json_api(url, payload, auth=user.auth, expect_errors=True) + view_only_link.reload() + assert res.status_code == 200 + assert len(res.json['data']) == 2 + assert public_project in view_only_link.nodes.all() + assert second_level_component in view_only_link.nodes.all() + + def test_update_node_second_level_component_with_first_level_parent(self, app, user, public_project, first_level_component, second_level_component, view_only_link, url): """ Parent Project (included) -> First Level Component (included) @@ -441,72 +446,74 @@ def test_update_node_second_level_component_with_first_level_parent(self): payload = { 'data': [{ 'type': 'nodes', - 'id': self.public_project._id + 'id': public_project._id }, { 'type': 'nodes', - 'id': self.first_level_component._id + 'id': first_level_component._id }, { 'type': 'nodes', - 'id': self.second_level_component._id + 'id': second_level_component._id }] } - res = self.app.put_json_api(self.url, payload, auth=self.user.auth, expect_errors=True) - self.view_only_link.reload() - assert_equal(res.status_code, 200) - assert_equal(len(res.json['data']), 3) - assert_in(self.public_project, self.view_only_link.nodes.all()) - assert_in(self.first_level_component, self.view_only_link.nodes.all()) - assert_in(self.second_level_component, self.view_only_link.nodes.all()) - - def test_invalid_nodes_in_payload(self): + res = app.put_json_api(url, payload, auth=user.auth, expect_errors=True) + view_only_link.reload() + assert res.status_code == 200 + assert len(res.json['data']) == 3 + assert public_project in view_only_link.nodes.all() + assert first_level_component in view_only_link.nodes.all() + assert second_level_component in view_only_link.nodes.all() + + def test_view_only_link_nodes_update_errors(self, app, user, read_write_user, read_only_user, non_contributor, public_project, component_one, update_payload, url): + + # test_invalid_nodes_in_payload payload = { 'data': [{ 'type': 'nodes', - 'id': self.public_project._id + 'id': public_project._id }, { 'type': 'nodes', 'id': 'abcde' }] } - res = self.app.put_json_api(self.url, payload, auth=self.user.auth, expect_errors=True) - assert_equal(res.status_code, 404) + res = app.put_json_api(url, payload, auth=user.auth, expect_errors=True) + assert res.status_code == 404 - def test_type_required_in_payload(self): + # test_type_required_in_payload payload = { 'data': [{ 'type': 'nodes', - 'id': self.public_project._id + 'id': public_project._id }, { - 'id': self.component_one._id + 'id': component_one._id }] } - res = self.app.put_json_api(self.url, payload, auth=self.user.auth, expect_errors=True) - assert_equal(res.status_code, 400) + res = app.put_json_api(url, payload, auth=user.auth, expect_errors=True) + assert res.status_code == 400 - def test_id_required_in_payload(self): + # test_id_required_in_payload payload = { 'data': [{ 'type': 'nodes', - 'id': self.public_project._id + 'id': public_project._id }, { 'type': 'nodes' }] } - res = self.app.put_json_api(self.url, payload, auth=self.user.auth, expect_errors=True) - assert_equal(res.status_code, 400) + res = app.put_json_api(url, payload, auth=user.auth, expect_errors=True) + assert res.status_code == 400 - def test_read_write_contributor_cannot_update_nodes(self): - res = self.app.put_json_api(self.url, self.update_payload, auth=self.read_write_user.auth, expect_errors=True) - assert_equal(res.status_code, 403) + # test_read_write_contributor_cannot_update_nodes + res = app.put_json_api(url, update_payload, auth=read_write_user.auth, expect_errors=True) + assert res.status_code == 403 - def test_read_only_contributor_cannot_update_nodes(self): - res = self.app.put_json_api(self.url, self.update_payload, auth=self.read_only_user.auth, expect_errors=True) - assert_equal(res.status_code, 403) + # test_read_only_contributor_cannot_update_nodes + res = app.put_json_api(url, update_payload, auth=read_only_user.auth, expect_errors=True) + assert res.status_code == 403 - def test_logged_in_user_cannot_update_nodes(self): - res = self.app.put_json_api(self.url, self.update_payload, auth=self.non_contributor.auth, expect_errors=True) - assert_equal(res.status_code, 403) + # test_logged_in_user_cannot_update_nodes + res = app.put_json_api(url, update_payload, auth=non_contributor.auth, expect_errors=True) + assert res.status_code == 403 - def test_unauthenticated_user_cannot_update_nodes(self): - res = self.app.put_json_api(self.url, self.update_payload, expect_errors=True) - assert_equal(res.status_code, 401) + # test_unauthenticated_user_cannot_update_nodes + res = app.put_json_api(url, update_payload, expect_errors=True) + assert res.status_code == 401 From caa27ce9f08f33ff3c6678093e564186fd15ed9c Mon Sep 17 00:00:00 2001 From: Alex Schiller Date: Tue, 6 Jun 2017 11:48:03 -0400 Subject: [PATCH 047/163] Add mock share urls for failing test --- admin_tests/preprints/test_views.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/admin_tests/preprints/test_views.py b/admin_tests/preprints/test_views.py index 7c985cb5ec0..02d2faeb178 100644 --- a/admin_tests/preprints/test_views.py +++ b/admin_tests/preprints/test_views.py @@ -128,6 +128,8 @@ def setUp(self): self.preprint = PreprintFactory(creator=self.user) @mock.patch('admin.preprints.views.on_preprint_updated') + @mock.patch('website.settings.SHARE_URL', 'ima_real_website') + @mock.patch('website.settings.SHARE_API_TOKEN', 'ima_real_token') def test_reindex_preprint_share(self, mock_reindex_preprint): count = AdminLogEntry.objects.count() view = views.PreprintReindexShare() From c41f191b6b157867c34b2fd6d1ef4d44161a9a2b Mon Sep 17 00:00:00 2001 From: Nan Chen Date: Tue, 6 Jun 2017 23:05:19 -0400 Subject: [PATCH 048/163] fix the problem that use only have fullname but not family_name and given_name leaves no citation --- framework/auth/utils.py | 2 +- osf/models/user.py | 20 ++++++++++++++++---- 2 files changed, 17 insertions(+), 5 deletions(-) diff --git a/framework/auth/utils.py b/framework/auth/utils.py index 31a208a821b..fb11e9f47f3 100644 --- a/framework/auth/utils.py +++ b/framework/auth/utils.py @@ -134,5 +134,5 @@ def generate_csl_given_name(given_name, middle_names, suffix): parts.extend(each[0] for each in re.split(r'\s+', middle_names)) given = ' '.join(parts) if suffix: - given = '%s ,%s' % (given, suffix) + given = '%s, %s' % (given, suffix) return given diff --git a/osf/models/user.py b/osf/models/user.py index fab7ade9166..a3075fecd95 100644 --- a/osf/models/user.py +++ b/osf/models/user.py @@ -467,10 +467,22 @@ def csl_given_name(self): @property def csl_name(self): - return { - 'family': self.family_name, - 'given': self.csl_given_name, - } + if self.family_name and self.given_name: + return { + 'family': self.family_name, + 'given': self.csl_given_name, + } + else: + parsed = utils.impute_names(self.fullname) + given_name = parsed['given'] + middle_names = parsed['middle'] + family_name = parsed['family'] + suffix = parsed['suffix'] + csl_given_name = utils.generate_csl_given_name(given_name, middle_names, suffix) + return { + 'family': family_name, + 'given': csl_given_name, + } @property def contributor_to(self): From 586e15838ecbb1c05103f347bc869b324964d4af Mon Sep 17 00:00:00 2001 From: Nan Chen Date: Tue, 6 Jun 2017 23:26:51 -0400 Subject: [PATCH 049/163] finish tests --- tests/test_auth.py | 21 ++++++++++++++------- tests/test_utils.py | 10 ++++++++++ 2 files changed, 24 insertions(+), 7 deletions(-) diff --git a/tests/test_auth.py b/tests/test_auth.py index e9d7e5c4aa2..aa22c8b3fc8 100644 --- a/tests/test_auth.py +++ b/tests/test_auth.py @@ -13,7 +13,7 @@ from framework import auth from framework.auth import cas -from framework.auth.utils import validate_recaptcha, generate_csl_given_name +from framework.auth.utils import validate_recaptcha from framework.sessions import Session from framework.exceptions import HTTPError from tests.base import OsfTestCase, assert_is_redirect, fake @@ -42,12 +42,19 @@ class TestAuthUtils(OsfTestCase): - def test_generate_csl_given_name(self): - given_name = 'Cause' - middle_names = 'Awesome' - suffix = 'Jr.' - csl_given_name = generate_csl_given_name(given_name, middle_names, suffix) - assert_equal(csl_given_name, 'Cause A ,Jr.') + def test_citation_with_only_fullname(self): + user = UserFactory() + user.fullname = 'Martin Luther King Jr.' + user.family_name = None + user.given_name = None + user.middle_names = None + user.suffix = None + user.save() + resp = user.csl_name + family_name = resp['family'] + given_name = resp['given'] + assert_equal(family_name, 'King') + assert_equal(given_name, 'Martin L, Jr.') def test_unreg_user_can_register(self): user = UnregUserFactory() diff --git a/tests/test_utils.py b/tests/test_utils.py index 424c4b44c8b..15f02a30ef8 100644 --- a/tests/test_utils.py +++ b/tests/test_utils.py @@ -13,6 +13,7 @@ from tests.base import OsfTestCase from osf_tests.factories import RegistrationFactory +from framework.auth.utils import generate_csl_given_name from framework.routing import Rule, json_renderer from framework.utils import secure_filename from website.routes import process_rules, OsfWebRenderer @@ -447,3 +448,12 @@ def test_temporary_disconnect(self): with util.disconnected_from(self.signal_, self.listener): self.signal_.send() assert_false(self.mock_listener.called) + +class TestUserUtils(unittest.TestCase): + + def test_generate_csl_given_name(self): + given_name = 'Cause' + middle_names = 'Awesome' + suffix = 'Jr.' + csl_given_name = generate_csl_given_name(given_name, middle_names, suffix) + assert_equal(csl_given_name, 'Cause A, Jr.') \ No newline at end of file From c9e9d2ab5ae7911e5c11849add1f26d0f8039154 Mon Sep 17 00:00:00 2001 From: Nan Chen Date: Wed, 7 Jun 2017 00:47:09 -0400 Subject: [PATCH 050/163] solve merge conflict --- framework/auth/core.py | 1420 ---------------------------------------- 1 file changed, 1420 deletions(-) diff --git a/framework/auth/core.py b/framework/auth/core.py index 0feb029b6c4..b1d364bb318 100644 --- a/framework/auth/core.py +++ b/framework/auth/core.py @@ -203,1423 +203,3 @@ def from_kwargs(cls, request_args, kwargs): user=user, private_key=private_key, ) -<<<<<<< HEAD - - -class User(GuidStoredObject, AddonModelMixin): - - # Node fields that trigger an update to the search engine on save - SEARCH_UPDATE_FIELDS = { - 'fullname', - 'given_name', - 'middle_names', - 'family_name', - 'suffix', - 'merged_by', - 'date_disabled', - 'date_confirmed', - 'jobs', - 'schools', - 'social', - } - - # TODO: Add SEARCH_UPDATE_NODE_FIELDS, for fields that should trigger a - # search update for all nodes to which the user is a contributor. - - SOCIAL_FIELDS = { - 'orcid': u'http://orcid.org/{}', - 'github': u'http://github.com/{}', - 'scholar': u'http://scholar.google.com/citations?user={}', - 'twitter': u'http://twitter.com/{}', - 'profileWebsites': [], - 'linkedIn': u'https://www.linkedin.com/{}', - 'impactStory': u'https://impactstory.org/{}', - 'researcherId': u'http://researcherid.com/rid/{}', - 'researchGate': u'https://researchgate.net/profile/{}', - 'academiaInstitution': u'https://{}', - 'academiaProfileID': u'.academia.edu/{}', - 'baiduScholar': u'http://xueshu.baidu.com/scholarID/{}', - 'ssrn': u'http://papers.ssrn.com/sol3/cf_dev/AbsByAuth.cfm?per_id={}', - } - - # This is a GuidStoredObject, so this will be a GUID. - _id = fields.StringField(primary=True) - - # The primary email address for the account. - # This value is unique, but multiple "None" records exist for: - # * unregistered contributors where an email address was not provided. - # TODO: Update mailchimp subscription on username change in user.save() - username = fields.StringField(required=False, unique=True, index=True) - - # Hashed. Use `User.set_password` and `User.check_password` - password = fields.StringField() - - fullname = fields.StringField(required=True, validate=string_required) - - # user has taken action to register the account - is_registered = fields.BooleanField(index=True) - - # user has claimed the account - # TODO: This should be retired - it always reflects is_registered. - # While a few entries exist where this is not the case, they appear to be - # the result of a bug, as they were all created over a small time span. - is_claimed = fields.BooleanField(default=False, index=True) - - # a list of strings - for internal use - system_tags = fields.StringField(list=True) - - # security emails that have been sent - # TODO: This should be removed and/or merged with system_tags - security_messages = fields.DictionaryField() - # Format: { - # : - # ... - # } - - # user was invited (as opposed to registered unprompted) - is_invited = fields.BooleanField(default=False, index=True) - - # Per-project unclaimed user data: - # TODO: add validation - unclaimed_records = fields.DictionaryField(required=False) - # Format: { - # : { - # 'name': , - # 'referrer_id': , - # 'token': , - # 'expires': , - # 'email': , - # 'claimer_email': , - # 'last_sent': - # } - # ... - # } - - # Time of last sent notification email to newly added contributors - contributor_added_email_records = fields.DictionaryField(default=dict) - # Format : { - # : { - # 'last_sent': time.time() - # } - # ... - # } - - # The user into which this account was merged - merged_by = fields.ForeignField('user', default=None, index=True) - - # verification key v1: only the token string, no expiration time - # used for cas login with username and verification key - verification_key = fields.StringField() - - # verification key v2: token, and expiration time - # used for password reset, confirm account/email, claim account/contributor-ship - verification_key_v2 = fields.DictionaryField(default=dict) - # Format: { - # 'token': - # 'expires': - # } - - email_last_sent = fields.DateTimeField() - - # confirmed emails - # emails should be stripped of whitespace and lower-cased before appending - # TODO: Add validator to ensure an email address only exists once across - # all User's email lists - emails = fields.StringField(list=True) - - # email verification tokens - # see also ``unconfirmed_emails`` - email_verifications = fields.DictionaryField(default=dict) - # Format: { - # : { - # 'email': , - # 'expiration': , - # 'confirmed': whether user is confirmed or not, - # 'external_identity': user's external identity, - # } - # } - - # TODO remove this field once migration (scripts/migration/migrate_mailing_lists_to_mailchimp_fields.py) - # has been run. This field is deprecated and replaced with mailchimp_mailing_lists - mailing_lists = fields.DictionaryField() - - # email lists to which the user has chosen a subscription setting - mailchimp_mailing_lists = fields.DictionaryField() - # Format: { - # 'list1': True, - # 'list2: False, - # ... - # } - - # email lists to which the user has chosen a subscription setting, being sent from osf, rather than mailchimp - osf_mailing_lists = fields.DictionaryField(default=lambda: {settings.OSF_HELP_LIST: True}) - # Format: { - # 'list1': True, - # 'list2: False, - # ... - # } - - # the date this user was registered - # TODO: consider removal - this can be derived from date_registered - date_registered = fields.DateTimeField(auto_now_add=dt.datetime.utcnow, - index=True) - - # watched nodes are stored via a list of WatchConfigs - watched = fields.ForeignField('WatchConfig', list=True) - - # list of collaborators that this user recently added to nodes as a contributor - recently_added = fields.ForeignField('user', list=True) - - # Attached external accounts (OAuth) - external_accounts = fields.ForeignField('externalaccount', list=True) - - # CSL names - given_name = fields.StringField() - middle_names = fields.StringField() - family_name = fields.StringField() - suffix = fields.StringField() - - # identity for user logged in through external idp - external_identity = fields.DictionaryField() - # Format: { - # : { - # : , - # ... - # }, - # ... - # } - - # Employment history - jobs = fields.DictionaryField(list=True, validate=validate_history_item) - # Format: { - # 'title': , - # 'institution': , - # 'department': , - # 'location': , - # 'startMonth': , - # 'startYear': , - # 'endMonth': , - # 'endYear': , - # 'ongoing: - # } - - # Educational history - schools = fields.DictionaryField(list=True, validate=validate_history_item) - # Format: { - # 'degree': , - # 'institution': , - # 'department': , - # 'location': , - # 'startMonth': , - # 'startYear': , - # 'endMonth': , - # 'endYear': , - # 'ongoing: - # } - - # Social links - social = fields.DictionaryField(validate=validate_social) - # Format: { - # 'profileWebsites': - # 'twitter': , - # } - - # date the user last sent a request - date_last_login = fields.DateTimeField() - - # date the user first successfully confirmed an email address - date_confirmed = fields.DateTimeField(index=True) - - # When the user was disabled. - date_disabled = fields.DateTimeField(index=True) - - # when comments were last viewed - comments_viewed_timestamp = fields.DictionaryField() - # Format: { - # 'Comment.root_target._id': 'timestamp', - # ... - # } - - # timezone for user's locale (e.g. 'America/New_York') - timezone = fields.StringField(default='Etc/UTC') - - # user language and locale data (e.g. 'en_US') - locale = fields.StringField(default='en_US') - - # whether the user has requested to deactivate their account - requested_deactivation = fields.BooleanField(default=False) - - # dictionary of projects a user has changed the setting on - notifications_configured = fields.DictionaryField() - # Format: { - # : True - # ... - # } - - # If this user was created through the API, - # keep track of who added them. - registered_by = fields.ForeignField('user', default=None, index=True) - - _meta = {'optimistic': True} - - def __repr__(self): - return ''.format(self.username, self._id) - - def __str__(self): - return self.fullname.encode('ascii', 'replace') - - __unicode__ = __str__ - - # For compatibility with Django auth - @property - def pk(self): - return self._id - - @property - def email(self): - return self.username - - @property - def is_authenticated(self): # Needed for django compat - return True - - @property - def is_anonymous(self): - return False - - @property - def absolute_api_v2_url(self): - from website import util - return util.api_v2_url('users/{}/'.format(self.pk)) - - # used by django and DRF - def get_absolute_url(self): - if not self.is_registered: - return None - return self.absolute_api_v2_url - - @classmethod - def create_unregistered(cls, fullname, email=None): - """Create a new unregistered user. - """ - user = cls( - username=email, - fullname=fullname, - is_invited=True, - is_registered=False, - ) - user.update_guessed_names() - return user - - @classmethod - def create(cls, username, password, fullname): - utils.validate_email(username) # Raises ValidationError if spam address - - user = cls( - username=username, - fullname=fullname, - ) - user.update_guessed_names() - user.set_password(password) - return user - - @classmethod - def create_unconfirmed(cls, username, password, fullname, external_identity=None, - do_confirm=True, campaign=None): - """Create a new user who has begun registration but needs to verify - their primary email address (username). - """ - user = cls.create(username, password, fullname) - user.add_unconfirmed_email(username, external_identity=external_identity) - user.is_registered = False - if external_identity: - user.external_identity.update(external_identity) - if campaign: - # needed to prevent circular import - from framework.auth.campaigns import system_tag_for_campaign # skipci - user.add_system_tag(system_tag_for_campaign(campaign)) - return user - - @classmethod - def create_confirmed(cls, username, password, fullname): - user = cls.create(username, password, fullname) - user.is_registered = True - user.is_claimed = True - user.date_confirmed = user.date_registered - user.emails.append(username) - return user - - @classmethod - def from_cookie(cls, cookie, secret=None): - """Attempt to load a user from their signed cookie - :returns: None if a user cannot be loaded else User - """ - if not cookie: - return None - - secret = secret or settings.SECRET_KEY - - try: - token = itsdangerous.Signer(secret).unsign(cookie) - except itsdangerous.BadSignature: - return None - - user_session = Session.load(token) - - if user_session is None: - return None - - return cls.load(user_session.data.get('auth_user_id')) - - def get_or_create_cookie(self, secret=None): - """Find the cookie for the given user - Create a new session if no cookie is found - - :param str secret: The key to sign the cookie with - :returns: The signed cookie - """ - secret = secret or settings.SECRET_KEY - sessions = Session.find( - Q('data.auth_user_id', 'eq', self._id) - ).sort( - '-date_modified' - ).limit(1) - - if sessions.count() > 0: - user_session = sessions[0] - else: - user_session = Session(data={ - 'auth_user_id': self._id, - 'auth_user_username': self.username, - 'auth_user_fullname': self.fullname, - }) - user_session.save() - - signer = itsdangerous.Signer(secret) - return signer.sign(user_session._id) - - def update_guessed_names(self): - """Updates the CSL name fields inferred from the the full name. - """ - parsed = utils.impute_names(self.fullname) - self.given_name = parsed['given'] - self.middle_names = parsed['middle'] - self.family_name = parsed['family'] - self.suffix = parsed['suffix'] - - def register(self, username, password=None): - """Registers the user. - """ - self.username = username - if password: - self.set_password(password) - if username not in self.emails: - self.emails.append(username) - self.is_registered = True - self.is_claimed = True - self.date_confirmed = timezone.now() - self.update_search() - self.update_search_nodes() - - # Emit signal that a user has confirmed - signals.user_confirmed.send(self) - - return self - - def add_unclaimed_record(self, node, referrer, given_name, email=None): - """Add a new project entry in the unclaimed records dictionary. - - :param Node node: Node this unclaimed user was added to. - :param User referrer: User who referred this user. - :param str given_name: The full name that the referrer gave for this user. - :param str email: The given email address. - :returns: The added record - """ - if not node.can_edit(user=referrer): - raise PermissionsError( - 'Referrer does not have permission to add a contributor to project {0}'.format(node._primary_key) - ) - project_id = node._primary_key - referrer_id = referrer._primary_key - if email: - clean_email = email.lower().strip() - else: - clean_email = None - - verification_key = generate_verification_key(verification_type='claim') - record = { - 'name': given_name, - 'referrer_id': referrer_id, - 'token': verification_key['token'], - 'expires': verification_key['expires'], - 'email': clean_email, - } - self.unclaimed_records[project_id] = record - return record - - def display_full_name(self, node=None): - """Return the full name , as it would display in a contributor list for a - given node. - - NOTE: Unclaimed users may have a different name for different nodes. - """ - if node: - unclaimed_data = self.unclaimed_records.get(node._primary_key, None) - if unclaimed_data: - return unclaimed_data['name'] - return self.fullname - - @property - def is_active(self): - """Returns True if the user is active. The user must have activated - their account, must not be deleted, suspended, etc. - - :return: bool - """ - return (self.is_registered and - self.password is not None and - not self.is_merged and - not self.is_disabled and - self.is_confirmed) - - def get_unclaimed_record(self, project_id): - """ - Get an unclaimed record for a given project_id. Return the one record if found. Otherwise, raise ValueError. - - :param project_id, the project node id - :raises: ValueError if there is no record for the given project. - """ - - try: - return self.unclaimed_records[project_id] - except KeyError: # re-raise as ValueError - raise ValueError('No unclaimed record for user {self._id} on node {project_id}'.format(**locals())) - - def verify_claim_token(self, token, project_id): - """ - Verify the claim token for this user for a given node which she/he was added as a unregistered contributor for. - Return `True` if record found, token valid and not expired. Otherwise return False. - - :param token: the claim token - :param project_id: the project node id - """ - - try: - record = self.get_unclaimed_record(project_id) - except ValueError: # No unclaimed record for given pid - return False - valid = record['token'] == token - if 'expires' in record: - valid = valid and record['expires'] > timezone.now() - return valid - - def get_claim_url(self, project_id, external=False): - """ - Return the URL that an unclaimed user should use to claim their account. - Raise `ValueError` if there is no unclaimed_record for the given project ID. - - :param project_id: the project id for the unclaimed record - :param external: absolute url or relative - :returns: the claim url - :raises: ValueError if there is no record for the given project. - """ - - unclaimed_record = self.get_unclaimed_record(project_id) - uid = self._primary_key - base_url = settings.DOMAIN if external else '/' - token = unclaimed_record['token'] - return '{base_url}user/{uid}/{project_id}/claim/?token={token}'.format(**locals()) - - def verify_password_token(self, token): - """ - Verify that the password reset token for this user is valid. - - :param token: the token in verification key - :return `True` if valid, otherwise `False` - """ - - if token and self.verification_key_v2: - try: - return (self.verification_key_v2['token'] == token and - self.verification_key_v2['expires'] > timezone.now()) - except AttributeError: - return False - return False - - def set_password(self, raw_password, notify=True): - """Set the password for this user to the hash of ``raw_password``. - If this is a new user, we're done. If this is a password change, - then email the user about the change and clear all the old sessions - so that users will have to log in again with the new password. - - :param raw_password: the plaintext value of the new password - :param notify: Only meant for unit tests to keep extra notifications from being sent - :rtype: list - :returns: Changed fields from the user save - """ - had_existing_password = bool(self.password and self.is_confirmed) - self.password = generate_password_hash(raw_password) - if self.username == raw_password: - raise ChangePasswordError(['Password cannot be the same as your email address']) - if had_existing_password and notify: - mails.send_mail( - to_addr=self.username, - mail=mails.PASSWORD_RESET, - mimetype='plain', - user=self - ) - remove_sessions_for_user(self) - - def check_password(self, raw_password): - """Return a boolean of whether ``raw_password`` was correct.""" - if not self.password or not raw_password: - return False - return check_password_hash(self.password, raw_password) - - @property - def csl_given_name(self): - return utils.generate_csl_given_name(self.given_name, self.middle_names, self.suffix) - - @property - def csl_name(self): - return { - 'family': self.family_name, - 'given': self.csl_given_name, - } - - @property - def created(self): - from website.project.model import Node - return Node.find(Q('creator', 'eq', self._id)) - - # TODO: This should not be on the User object. - def change_password(self, raw_old_password, raw_new_password, raw_confirm_password): - """Change the password for this user to the hash of ``raw_new_password``.""" - raw_old_password = (raw_old_password or '').strip() - raw_new_password = (raw_new_password or '').strip() - raw_confirm_password = (raw_confirm_password or '').strip() - - # TODO: Move validation to set_password - issues = [] - if not self.check_password(raw_old_password): - issues.append('Old password is invalid') - elif raw_old_password == raw_new_password: - issues.append('Password cannot be the same') - elif raw_new_password == self.username: - issues.append('Password cannot be the same as your email address') - if not raw_old_password or not raw_new_password or not raw_confirm_password: - issues.append('Passwords cannot be blank') - elif len(raw_new_password) < 8: - issues.append('Password should be at least eight characters') - elif len(raw_new_password) > 255: - issues.append('Password should not be longer than 255 characters') - - if raw_new_password != raw_confirm_password: - issues.append('Password does not match the confirmation') - - if issues: - raise ChangePasswordError(issues) - self.set_password(raw_new_password) - - def add_unconfirmed_email(self, email, expiration=None, external_identity=None): - """ - Add an email verification token for a given email. - - :param email: the email to confirm - :param email: overwrite default expiration time - :param external_identity: the user's external identity - :return: a token - :raises: ValueError if email already confirmed, except for login through external idp. - """ - - # TODO: This is technically not compliant with RFC 822, which requires - # that case be preserved in the "local-part" of an address. From - # a practical standpoint, the vast majority of email servers do - # not preserve case. - # ref: https://tools.ietf.org/html/rfc822#section-6 - - email = email.lower().strip() - - if not external_identity and email in self.emails: - raise ValueError('Email already confirmed to this user.') - - utils.validate_email(email) - - # If the unconfirmed email is already present, remove it and generate a new one - if email in self.unconfirmed_emails: - self.remove_unconfirmed_email(email) - verification_key = generate_verification_key(verification_type='confirm') - # handle when email_verifications is None - if not self.email_verifications: - self.email_verifications = {} - self.email_verifications[verification_key['token']] = { - 'email': email, - 'confirmed': False, - 'expiration': expiration if expiration else verification_key['expires'], - 'external_identity': external_identity, - } - - return verification_key['token'] - - def remove_unconfirmed_email(self, email): - """Remove an unconfirmed email addresses and their tokens.""" - for token, value in self.email_verifications.iteritems(): - if value.get('email') == email: - del self.email_verifications[token] - return True - - return False - - def remove_email(self, email): - """Remove a confirmed email""" - if email == self.username: - raise PermissionsError("Can't remove primary email") - if email in self.emails: - self.emails.remove(email) - signals.user_email_removed.send(self, email=email) - - @signals.user_email_removed.connect - def _send_email_removal_confirmations(self, email): - mails.send_mail(to_addr=self.username, - mail=mails.REMOVED_EMAIL, - user=self, - removed_email=email, - security_addr='alternate email address ({})'.format(email)) - mails.send_mail(to_addr=email, - mail=mails.REMOVED_EMAIL, - user=self, - removed_email=email, - security_addr='primary email address ({})'.format(self.username)) - - def get_confirmation_token(self, email, force=False, renew=False): - """ - Return the confirmation token for a given email. - - :param str email: The email to get the token for. - :param bool force: If an expired token exists for the given email, generate a new one and return it. - :param bool renew: Generate a new token and return it. - :return Return the confirmation token. - :raises: ExpiredTokenError if trying to access a token that is expired and force=False. - :raises: KeyError if there no token for the email. - """ - - # TODO: Refactor "force" flag into User.get_or_add_confirmation_token - for token, info in self.email_verifications.items(): - if info['email'].lower() == email.lower(): - # Old records will not have an expiration key. If it's missing, assume the token is expired. - expiration = info.get('expiration') - if renew: - new_token = self.add_unconfirmed_email(email) - self.save() - return new_token - if not expiration or (expiration and expiration < timezone.now()): - if not force: - raise ExpiredTokenError('Token for email "{0}" is expired'.format(email)) - else: - new_token = self.add_unconfirmed_email(email) - self.save() - return new_token - return token - raise KeyError('No confirmation token for email "{0}"'.format(email)) - - def get_confirmation_url(self, email, external=True, force=False, renew=False, external_id_provider=None, destination=None): - """ - Return the confirmation url for a given email. - - :param email: The email to confirm. - :param external: Use absolute or relative url. - :param force: If an expired token exists for the given email, generate a new one and return it. - :param renew: Generate a new token and return it. - :param external_id_provider: The external identity provider that authenticates the user. - :param destination: The destination page to redirect after confirmation - :return: Return the confirmation url. - :raises: ExpiredTokenError if trying to access a token that is expired. - :raises: KeyError if there is no token for the email. - """ - - base = settings.DOMAIN if external else '/' - token = self.get_confirmation_token(email, force=force, renew=renew) - external = 'external/' if external_id_provider else '' - destination = '?{}'.format(urllib.urlencode({'destination': destination})) if destination else '' - return '{0}confirm/{1}{2}/{3}/{4}'.format(base, external, self._primary_key, token, destination) - - def get_unconfirmed_email_for_token(self, token): - """Return email if valid. - :rtype: bool - :raises: ExpiredTokenError if trying to access a token that is expired. - :raises: InvalidTokenError if trying to access a token that is invalid. - - """ - if token not in self.email_verifications: - raise InvalidTokenError - - verification = self.email_verifications[token] - # Not all tokens are guaranteed to have expiration dates - if ( - 'expiration' in verification and - verification['expiration'] < timezone.now() - ): - raise ExpiredTokenError - - return verification['email'] - - def clean_email_verifications(self, given_token=None): - email_verifications = deepcopy(self.email_verifications or {}) - for token in self.email_verifications or {}: - try: - self.get_unconfirmed_email_for_token(token) - except (KeyError, ExpiredTokenError): - email_verifications.pop(token) - continue - if token == given_token: - email_verifications.pop(token) - self.email_verifications = email_verifications - - def confirm_email(self, token, merge=False): - """Confirm the email address associated with the token""" - email = self.get_unconfirmed_email_for_token(token) - - # If this email is confirmed on another account, abort - try: - user_to_merge = User.find_one(Q('emails', 'iexact', email)) - except NoResultsFound: - user_to_merge = None - - if user_to_merge and merge: - self.merge_user(user_to_merge) - elif user_to_merge: - raise MergeConfirmedRequiredError( - 'Merge requires confirmation', - user=self, - user_to_merge=user_to_merge, - ) - - # If another user has this email as its username, get it - try: - unregistered_user = User.find_one(Q('username', 'eq', email) & - Q('_id', 'ne', self._id)) - except NoResultsFound: - unregistered_user = None - - if unregistered_user: - self.merge_user(unregistered_user) - self.save() - - if email not in self.emails: - self.emails.append(email) - - # Complete registration if primary email - if email.lower() == self.username.lower(): - self.register(self.username) - self.date_confirmed = timezone.now() - # Revoke token - del self.email_verifications[token] - - # TODO: We can't assume that all unclaimed records are now claimed. - # Clear unclaimed records, so user's name shows up correctly on - # all projects - self.unclaimed_records = {} - self.save() - - self.update_search_nodes() - - return True - - @property - def unconfirmed_emails(self): - # Handle when email_verifications field is None - email_verifications = self.email_verifications or {} - return [ - each['email'] - for each - in email_verifications.values() - ] - - def update_search_nodes(self): - """Call `update_search` on all nodes on which the user is a - contributor. Needed to add self to contributor lists in search upon - registration or claiming. - - """ - for node in self.contributed: - node.update_search() - - def update_search_nodes_contributors(self): - """ - Bulk update contributor name on all nodes on which the user is - a contributor. - :return: - """ - from website.search import search - search.update_contributors_async(self.id) - - def update_affiliated_institutions_by_email_domain(self): - """ - Append affiliated_institutions by email domain. - :return: - """ - # Avoid circular import - from website.project.model import Institution - try: - email_domains = [email.split('@')[1] for email in self.emails] - insts = Institution.find(Q('email_domains', 'in', email_domains)) - for inst in insts: - if inst not in self.affiliated_institutions: - self.affiliated_institutions.append(inst) - except (IndexError, NoResultsFound): - pass - - @property - def is_confirmed(self): - return bool(self.date_confirmed) - - @property - def social_links(self): - social_user_fields = {} - for key, val in self.social.items(): - if val and key in self.SOCIAL_FIELDS: - if not isinstance(val, basestring): - social_user_fields[key] = val - else: - social_user_fields[key] = self.SOCIAL_FIELDS[key].format(val) - return social_user_fields - - @property - def biblio_name(self): - given_names = self.given_name + ' ' + self.middle_names - surname = self.family_name - if surname != given_names: - initials = [ - name[0].upper() + '.' - for name in given_names.split(' ') - if name and re.search(r'\w', name[0], re.I) - ] - return u'{0}, {1}'.format(surname, ' '.join(initials)) - return surname - - @property - def given_name_initial(self): - """ - The user's preferred initialization of their given name. - - Some users with common names may choose to distinguish themselves from - their colleagues in this way. For instance, there could be two - well-known researchers in a single field named "Robert Walker". - "Walker, R" could then refer to either of them. "Walker, R.H." could - provide easy disambiguation. - - NOTE: The internal representation for this should never end with a - period. "R" and "R.H" would be correct in the prior case, but - "R.H." would not. - """ - return self.given_name[0] - - @property - def url(self): - return '/{}/'.format(self._primary_key) - - @property - def api_url(self): - return '/api/v1/profile/{0}/'.format(self._primary_key) - - @property - def absolute_url(self): - return urlparse.urljoin(settings.DOMAIN, self.url) - - @property - def display_absolute_url(self): - url = self.absolute_url - if url is not None: - return re.sub(r'https?:', '', url).strip('/') - - @property - def deep_url(self): - return '/profile/{}/'.format(self._primary_key) - - @property - def unconfirmed_email_info(self): - """Return a list of dictionaries containing information about each of this - user's unconfirmed emails. - """ - unconfirmed_emails = [] - email_verifications = self.email_verifications or [] - for token in email_verifications: - if self.email_verifications[token].get('confirmed', False): - try: - user_merge = User.find_one(Q('emails', 'eq', self.email_verifications[token]['email'].lower())) - except NoResultsFound: - user_merge = False - - unconfirmed_emails.append({'address': self.email_verifications[token]['email'], - 'token': token, - 'confirmed': self.email_verifications[token]['confirmed'], - 'user_merge': user_merge.email if user_merge else False}) - return unconfirmed_emails - - def profile_image_url(self, size=None): - """A generalized method for getting a user's profile picture urls. - We may choose to use some service other than gravatar in the future, - and should not commit ourselves to using a specific service (mostly - an API concern). - - As long as we use gravatar, this is just a proxy to User.gravatar_url - """ - return self._gravatar_url(size) - - def _gravatar_url(self, size): - return filters.gravatar( - self, - use_ssl=True, - size=size - ) - - def get_activity_points(self, db=None): - db = db or framework.mongo.database - return analytics.get_total_activity_count(self._primary_key, db=db) - - def disable_account(self): - """ - Disables user account, making is_disabled true, while also unsubscribing user - from mailchimp emails, remove any existing sessions. - """ - from website import mailchimp_utils - from framework.auth import logout - - try: - mailchimp_utils.unsubscribe_mailchimp( - list_name=settings.MAILCHIMP_GENERAL_LIST, - user_id=self._id, - username=self.username - ) - except mailchimp_utils.mailchimp.ListNotSubscribedError: - pass - except mailchimp_utils.mailchimp.InvalidApiKeyError: - if not settings.ENABLE_EMAIL_SUBSCRIPTIONS: - pass - else: - raise - except mailchimp_utils.mailchimp.EmailNotExistsError: - pass - self.is_disabled = True - - # we must call both methods to ensure the current session is cleared and all existing - # sessions are revoked. - req = get_cache_key() - if isinstance(req, FlaskRequest): - logout() - remove_sessions_for_user(self) - - @property - def is_disabled(self): - """Whether or not this account has been disabled. - - Abstracts ``User.date_disabled``. - - :return: bool - """ - return self.date_disabled is not None - - @is_disabled.setter - def is_disabled(self, val): - """Set whether or not this account has been disabled.""" - if val and not self.date_disabled: - self.date_disabled = timezone.now() - elif val is False: - self.date_disabled = None - - @property - def is_merged(self): - '''Whether or not this account has been merged into another account. - ''' - return self.merged_by is not None - - @property - def profile_url(self): - return '/{}/'.format(self._id) - - @property - def contributed(self): - from website.project.model import Node - return Node.find(Q('contributors', 'eq', self._id)) - - @property - def contributor_to(self): - from website.project.model import Node - return Node.find( - Q('contributors', 'eq', self._id) & - Q('is_deleted', 'ne', True) & - Q('is_collection', 'ne', True) - ) - - @property - def visible_contributor_to(self): - from website.project.model import Node - return Node.find( - Q('contributors', 'eq', self._id) & - Q('is_deleted', 'ne', True) & - Q('is_collection', 'ne', True) & - Q('visible_contributor_ids', 'eq', self._id) - ) - - def get_summary(self, formatter='long'): - return { - 'user_fullname': self.fullname, - 'user_profile_url': self.profile_url, - 'user_display_name': name_formatters[formatter](self), - 'user_is_claimed': self.is_claimed - } - - def save(self, *args, **kwargs): - # TODO: Update mailchimp subscription on username change - # Avoid circular import - first_save = not self._is_loaded - self.username = self.username.lower().strip() if self.username else None - ret = super(User, self).save(*args, **kwargs) - if self.SEARCH_UPDATE_FIELDS.intersection(ret) and self.is_confirmed: - self.update_search() - self.update_search_nodes_contributors() - if first_save: - from website.project import new_bookmark_collection # Avoid circular import - new_bookmark_collection(self) - return ret - - def update_search(self): - from website import search - try: - search.search.update_user(self) - except search.exceptions.SearchUnavailableError as e: - logger.exception(e) - log_exception() - - @classmethod - def find_by_email(cls, email): - try: - user = cls.find_one( - Q('emails', 'eq', email) - ) - return [user] - except: - return [] - - def serialize(self, anonymous=False): - return { - 'id': utils.privacy_info_handle(self._primary_key, anonymous), - 'fullname': utils.privacy_info_handle(self.fullname, anonymous, name=True), - 'registered': self.is_registered, - 'url': utils.privacy_info_handle(self.url, anonymous), - 'api_url': utils.privacy_info_handle(self.api_url, anonymous), - } - - ###### OSF-Specific methods ###### - - def watch(self, watch_config): - """Watch a node by adding its WatchConfig to this user's ``watched`` - list. Raises ``ValueError`` if the node is already watched. - - :param watch_config: The WatchConfig to add. - :param save: Whether to save the user. - - """ - watched_nodes = [each.node for each in self.watched] - if watch_config.node in watched_nodes: - raise ValueError('Node is already being watched.') - watch_config.save() - self.watched.append(watch_config) - return None - - def unwatch(self, watch_config): - """Unwatch a node by removing its WatchConfig from this user's ``watched`` - list. Raises ``ValueError`` if the node is not already being watched. - - :param watch_config: The WatchConfig to remove. - :param save: Whether to save the user. - - """ - for each in self.watched: - if watch_config.node._id == each.node._id: - from framework.transactions.context import TokuTransaction # Avoid circular import - with TokuTransaction(): - # Ensure that both sides of the relationship are removed - each.__class__.remove_one(each) - self.watched.remove(each) - self.save() - return None - raise ValueError('Node not being watched.') - - def is_watching(self, node): - '''Return whether a not a user is watching a Node.''' - watched_node_ids = set([config.node._id for config in self.watched]) - return node._id in watched_node_ids - - def get_recent_log_ids(self, since=None): - '''Return a generator of recent logs' ids. - - :param since: A datetime specifying the oldest time to retrieve logs - from. If ``None``, defaults to 60 days before today. Must be a tz-aware - datetime because PyMongo's generation times are tz-aware. - - :rtype: generator of log ids (strings) - ''' - log_ids = [] - # Default since to 60 days before today if since is None - # timezone aware utcnow - utcnow = timezone.now() - since_date = since or (utcnow - dt.timedelta(days=60)) - for config in self.watched: - # Extract the timestamps for each log from the log_id (fast!) - # The first 4 bytes of Mongo's ObjectId encodes time - # This prevents having to load each Log Object and access their - # date fields - node_log_ids = [log.pk for log in config.node.logs - if bson.ObjectId(log.pk).generation_time > since_date and - log.pk not in log_ids] - # Log ids in reverse chronological order - log_ids = _merge_into_reversed(log_ids, node_log_ids) - return (l_id for l_id in log_ids) - - def get_daily_digest_log_ids(self): - '''Return a generator of log ids generated in the past day - (starting at UTC 00:00). - ''' - utcnow = timezone.now() - midnight = dt.datetime( - utcnow.year, utcnow.month, utcnow.day, - 0, 0, 0, tzinfo=pytz.utc - ) - return self.get_recent_log_ids(since=midnight) - - @property - def can_be_merged(self): - """The ability of the `merge_user` method to fully merge the user""" - return all((addon.can_be_merged for addon in self.get_addons())) - - def merge_user(self, user): - """Merge a registered user into this account. This user will be - a contributor on any project. if the registered user and this account - are both contributors of the same project. Then it will remove the - registered user and set this account to the highest permission of the two - and set this account to be visible if either of the two are visible on - the project. - :param user: A User object to be merged. - """ - # Fail if the other user has conflicts. - if not user.can_be_merged: - raise MergeConflictError('Users cannot be merged') - # Move over the other user's attributes - # TODO: confirm - for system_tag in user.system_tags: - if system_tag not in self.system_tags: - self.system_tags.append(system_tag) - - self.is_claimed = self.is_claimed or user.is_claimed - self.is_invited = self.is_invited or user.is_invited - - # copy over profile only if this user has no profile info - if user.jobs and not self.jobs: - self.jobs = user.jobs - - if user.schools and not self.schools: - self.schools = user.schools - - if user.social and not self.social: - self.social = user.social - - unclaimed = user.unclaimed_records.copy() - unclaimed.update(self.unclaimed_records) - self.unclaimed_records = unclaimed - # - unclaimed records should be connected to only one user - user.unclaimed_records = {} - - security_messages = user.security_messages.copy() - security_messages.update(self.security_messages) - self.security_messages = security_messages - - notifications_configured = user.notifications_configured.copy() - notifications_configured.update(self.notifications_configured) - self.notifications_configured = notifications_configured - - if not settings.RUNNING_MIGRATION: - for key, value in user.mailchimp_mailing_lists.iteritems(): - # subscribe to each list if either user was subscribed - subscription = value or self.mailchimp_mailing_lists.get(key) - signals.user_merged.send(self, list_name=key, subscription=subscription) - - # clear subscriptions for merged user - signals.user_merged.send(user, list_name=key, subscription=False, send_goodbye=False) - - for target_id, timestamp in user.comments_viewed_timestamp.iteritems(): - if not self.comments_viewed_timestamp.get(target_id): - self.comments_viewed_timestamp[target_id] = timestamp - elif timestamp > self.comments_viewed_timestamp[target_id]: - self.comments_viewed_timestamp[target_id] = timestamp - - for email in user.emails: - if email not in self.emails: - self.emails.append(email) - user.emails = [] - - for k, v in user.email_verifications.iteritems(): - email_to_confirm = v['email'] - if k not in self.email_verifications and email_to_confirm != user.username: - self.email_verifications[k] = v - user.email_verifications = {} - - for institution in user.affiliated_institutions: - self.affiliated_institutions.append(institution) - user._affiliated_institutions = [] - - for service in user.external_identity: - for service_id in user.external_identity[service].iterkeys(): - if not (service_id in self.external_identity.get(service, '') and self.external_identity[service][service_id] == 'VERIFIED'): - # Prevent 'CREATE', merging user has already been created. - status = 'VERIFIED' if user.external_identity[service][service_id] == 'VERIFIED' else 'LINK' - if self.external_identity.get(service): - self.external_identity[service].update( - {service_id: status} - ) - else: - self.external_identity[service] = { - service_id: status - } - user.external_identity = {} - - # FOREIGN FIELDS - for watched in user.watched: - if watched not in self.watched: - self.watched.append(watched) - user.watched = [] - - for account in user.external_accounts: - if account not in self.external_accounts: - self.external_accounts.append(account) - user.external_accounts = [] - - # - addons - # Note: This must occur before the merged user is removed as a - # contributor on the nodes, as an event hook is otherwise fired - # which removes the credentials. - for addon in user.get_addons(): - user_settings = self.get_or_add_addon(addon.config.short_name) - user_settings.merge(addon) - user_settings.save() - - # Disconnect signal to prevent emails being sent about being a new contributor when merging users - # be sure to reconnect it at the end of this code block. Import done here to prevent circular import error. - from addons.osfstorage.listeners import checkin_files_by_user - from website.project.signals import contributor_added, contributor_removed - from website.project.views.contributor import notify_added_contributor - from website.util import disconnected_from - - # - projects where the user was a contributor - with disconnected_from(signal=contributor_added, listener=notify_added_contributor): - for node in user.contributed: - # Skip bookmark collection node - if node.is_bookmark_collection: - continue - # if both accounts are contributor of the same project - if node.is_contributor(self) and node.is_contributor(user): - if node.permissions[user._id] > node.permissions[self._id]: - permissions = node.permissions[user._id] - else: - permissions = node.permissions[self._id] - node.set_permissions(user=self, permissions=permissions) - - visible1 = self._id in node.visible_contributor_ids - visible2 = user._id in node.visible_contributor_ids - if visible1 != visible2: - node.set_visible(user=self, visible=True, log=True, auth=Auth(user=self)) - - else: - node.add_contributor( - contributor=self, - permissions=node.get_permissions(user), - visible=node.get_visible(user), - log=False, - send_email='false' - ) - - with disconnected_from(signal=contributor_removed, listener=checkin_files_by_user): - try: - node.remove_contributor( - contributor=user, - auth=Auth(user=self), - log=False, - ) - except ValueError: - logger.error('Contributor {0} not in list on node {1}'.format( - user._id, node._id - )) - - node.save() - - # - projects where the user was the creator - for node in user.created: - node.creator = self - node.save() - - # - file that the user has checked_out, import done here to prevent import error - from website.files.models.base import FileNode - for file_node in FileNode.files_checked_out(user=user): - file_node.checkout = self - file_node.save() - - # finalize the merge - - remove_sessions_for_user(user) - - # - username is set to _id to ensure uniqueness - user.username = user._id - user.password = None - user.verification_key = None - user.osf_mailing_lists = {} - user.merged_by = self - - user.save() - - def get_projects_in_common(self, other_user, primary_keys=True): - """Returns either a collection of "shared projects" (projects that both users are contributors for) - or just their primary keys - """ - if primary_keys: - projects_contributed_to = set(self.contributor_to.get_keys()) - other_projects_primary_keys = set(other_user.contributor_to.get_keys()) - return projects_contributed_to.intersection(other_projects_primary_keys) - else: - projects_contributed_to = set(self.contributor_to) - return projects_contributed_to.intersection(other_user.contributor_to) - - def n_projects_in_common(self, other_user): - """Returns number of "shared projects" (projects that both users are contributors for)""" - return len(self.get_projects_in_common(other_user, primary_keys=True)) - - def is_affiliated_with_institution(self, inst): - return inst in self.affiliated_institutions - - def remove_institution(self, inst_id): - removed = False - for inst in self.affiliated_institutions: - if inst._id == inst_id: - self.affiliated_institutions.remove(inst) - removed = True - return removed - - _affiliated_institutions = fields.ForeignField('node', list=True) - - @property - def affiliated_institutions(self): - from website.institutions.model import Institution, AffiliatedInstitutionsList - return AffiliatedInstitutionsList([Institution(inst) for inst in self._affiliated_institutions], obj=self, private_target='_affiliated_institutions') - - def get_node_comment_timestamps(self, target_id): - """ Returns the timestamp for when comments were last viewed on a node, file or wiki. - """ - default_timestamp = dt.datetime(1970, 1, 1, 12, 0, 0) - return self.comments_viewed_timestamp.get(target_id, default_timestamp) - - -def _merge_into_reversed(*iterables): - '''Merge multiple sorted inputs into a single output in reverse order. - ''' - return sorted(itertools.chain(*iterables), reverse=True) -======= ->>>>>>> fbde375a06680a8364b48f032ec7ccb6e5c1db5d From 1e8b12b6d06a1edd9ccd5a0ec3aa4f5d12959ce9 Mon Sep 17 00:00:00 2001 From: Nan Chen Date: Wed, 7 Jun 2017 00:51:54 -0400 Subject: [PATCH 051/163] fix flake 8 --- tests/test_utils.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/test_utils.py b/tests/test_utils.py index 8ca42b2b90f..fa4d6405466 100644 --- a/tests/test_utils.py +++ b/tests/test_utils.py @@ -471,4 +471,4 @@ def test_generate_csl_given_name(self): middle_names = 'Awesome' suffix = 'Jr.' csl_given_name = generate_csl_given_name(given_name, middle_names, suffix) - assert_equal(csl_given_name, 'Cause A, Jr.') \ No newline at end of file + assert_equal(csl_given_name, 'Cause A, Jr.') From e446e18301fc7c5c4ff63229e5fd224febed40ed Mon Sep 17 00:00:00 2001 From: Nan Chen Date: Wed, 7 Jun 2017 01:32:44 -0400 Subject: [PATCH 052/163] fix test --- tests/test_auth.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/tests/test_auth.py b/tests/test_auth.py index 984b13493c4..201933f63d5 100644 --- a/tests/test_auth.py +++ b/tests/test_auth.py @@ -44,10 +44,10 @@ class TestAuthUtils(OsfTestCase): def test_citation_with_only_fullname(self): user = UserFactory() user.fullname = 'Martin Luther King Jr.' - user.family_name = None - user.given_name = None - user.middle_names = None - user.suffix = None + user.family_name = '' + user.given_name = '' + user.middle_names = '' + user.suffix = '' user.save() resp = user.csl_name family_name = resp['family'] From b1b751f33ea7991c1dc060f79ff7e4061c569cb9 Mon Sep 17 00:00:00 2001 From: Nan Chen Date: Wed, 7 Jun 2017 09:30:51 -0400 Subject: [PATCH 053/163] fix test and prefect test case --- framework/auth/utils.py | 2 +- tests/test_auth.py | 2 +- tests/test_utils.py | 28 ++++++++++++++++++++++++++-- 3 files changed, 28 insertions(+), 4 deletions(-) diff --git a/framework/auth/utils.py b/framework/auth/utils.py index 4925f7b9e3f..10dc7bb4de8 100644 --- a/framework/auth/utils.py +++ b/framework/auth/utils.py @@ -128,7 +128,7 @@ def validate_recaptcha(response, remote_ip=None): return resp.status_code == httplib.OK and resp.json().get('success') -def generate_csl_given_name(given_name, middle_names, suffix): +def generate_csl_given_name(given_name, middle_names='', suffix=''): parts = [given_name] if middle_names: parts.extend(each[0] for each in re.split(r'\s+', middle_names)) diff --git a/tests/test_auth.py b/tests/test_auth.py index 201933f63d5..ad79d20843e 100644 --- a/tests/test_auth.py +++ b/tests/test_auth.py @@ -43,7 +43,7 @@ class TestAuthUtils(OsfTestCase): def test_citation_with_only_fullname(self): user = UserFactory() - user.fullname = 'Martin Luther King Jr.' + user.fullname = 'Martin Luther King, Jr.' user.family_name = '' user.given_name = '' user.middle_names = '' diff --git a/tests/test_utils.py b/tests/test_utils.py index fa4d6405466..2b0c70b81c7 100644 --- a/tests/test_utils.py +++ b/tests/test_utils.py @@ -464,11 +464,35 @@ def test_temporary_disconnect(self): self.signal_.send() assert_false(self.mock_listener.called) + class TestUserUtils(unittest.TestCase): - def test_generate_csl_given_name(self): + def test_generate_csl_given_name_with_given_middle_suffix(self): given_name = 'Cause' middle_names = 'Awesome' suffix = 'Jr.' - csl_given_name = generate_csl_given_name(given_name, middle_names, suffix) + csl_given_name = generate_csl_given_name( + given_name=given_name, middle_name=middle_names, suffix=suffix + ) assert_equal(csl_given_name, 'Cause A, Jr.') + + def test_generate_csl_given_name_with_given_middle(self): + given_name = 'Cause' + middle_names = 'Awesome' + csl_given_name = generate_csl_given_name( + given_name=given_name, middle_name=middle_names + ) + assert_equal(csl_given_name, 'Cause A') + + def test_generate_csl_given_name_with_given_suffix(self): + given_name = 'Cause' + suffix = 'Jr.' + csl_given_name = generate_csl_given_name( + given_name=given_name, suffix=suffix + ) + assert_equal(csl_given_name, 'Cause A') + + def test_generate_csl_given_name_with_given(self): + given_name = 'Cause' + csl_given_name = generate_csl_given_name(given_name) + assert_equal(csl_given_name, 'Cause') \ No newline at end of file From 2dfe80f1c6d19858e368089f86d2d08a44cf3433 Mon Sep 17 00:00:00 2001 From: Nan Chen Date: Wed, 7 Jun 2017 09:31:36 -0400 Subject: [PATCH 054/163] fix flake 8 --- tests/test_utils.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/test_utils.py b/tests/test_utils.py index 2b0c70b81c7..c88f3bc8bb4 100644 --- a/tests/test_utils.py +++ b/tests/test_utils.py @@ -495,4 +495,4 @@ def test_generate_csl_given_name_with_given_suffix(self): def test_generate_csl_given_name_with_given(self): given_name = 'Cause' csl_given_name = generate_csl_given_name(given_name) - assert_equal(csl_given_name, 'Cause') \ No newline at end of file + assert_equal(csl_given_name, 'Cause') From 1e50e025460f03744e83083cfddb2a4559f4da86 Mon Sep 17 00:00:00 2001 From: Nan Chen Date: Wed, 7 Jun 2017 12:10:43 -0400 Subject: [PATCH 055/163] fix tests --- tests/test_utils.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/test_utils.py b/tests/test_utils.py index c88f3bc8bb4..20cc24aa9fb 100644 --- a/tests/test_utils.py +++ b/tests/test_utils.py @@ -472,7 +472,7 @@ def test_generate_csl_given_name_with_given_middle_suffix(self): middle_names = 'Awesome' suffix = 'Jr.' csl_given_name = generate_csl_given_name( - given_name=given_name, middle_name=middle_names, suffix=suffix + given_name=given_name, middle_names=middle_names, suffix=suffix ) assert_equal(csl_given_name, 'Cause A, Jr.') @@ -480,7 +480,7 @@ def test_generate_csl_given_name_with_given_middle(self): given_name = 'Cause' middle_names = 'Awesome' csl_given_name = generate_csl_given_name( - given_name=given_name, middle_name=middle_names + given_name=given_name, middle_names=middle_names ) assert_equal(csl_given_name, 'Cause A') @@ -490,7 +490,7 @@ def test_generate_csl_given_name_with_given_suffix(self): csl_given_name = generate_csl_given_name( given_name=given_name, suffix=suffix ) - assert_equal(csl_given_name, 'Cause A') + assert_equal(csl_given_name, 'Cause, Jr.') def test_generate_csl_given_name_with_given(self): given_name = 'Cause' From c6dea48a188df5bf39f68abdbbe7226c8b1d147e Mon Sep 17 00:00:00 2001 From: Rheisen Dennis Date: Wed, 7 Jun 2017 12:50:41 -0400 Subject: [PATCH 056/163] initial pytest conversion of test_preprint_provider_detail & test_preprint_detail --- .../views/test_preprint_provider_detail.py | 59 +- .../preprints/views/test_preprint_detail.py | 918 ++++++++++-------- 2 files changed, 539 insertions(+), 438 deletions(-) diff --git a/api_tests/preprint_providers/views/test_preprint_provider_detail.py b/api_tests/preprint_providers/views/test_preprint_provider_detail.py index a56e15e5c10..7222d34dde5 100644 --- a/api_tests/preprint_providers/views/test_preprint_provider_detail.py +++ b/api_tests/preprint_providers/views/test_preprint_provider_detail.py @@ -1,43 +1,48 @@ -from nose.tools import * # flake8: noqa +import pytest from api.base.settings.defaults import API_BASE - from tests.base import ApiTestCase from osf_tests.factories import PreprintProviderFactory - -class TestPreprintProviderExists(ApiTestCase): +@pytest.mark.django_db +class TestPreprintProviderExists: # Regression for https://openscience.atlassian.net/browse/OSF-7621 - def setUp(self): - super(TestPreprintProviderExists, self).setUp() - self.preprint_provider = PreprintProviderFactory() - self.fake_url = '/{}preprint_providers/fake/'.format(API_BASE) - self.provider_url = '/{}preprint_providers/{}/'.format(API_BASE, self.preprint_provider._id) + @pytest.fixture() + def preprint_provider(self): + return PreprintProviderFactory() + + @pytest.fixture() + def fake_url(self): + return '/{}preprint_providers/fake/'.format(API_BASE) + + @pytest.fixture() + def provider_url(self, preprint_provider): + return '/{}preprint_providers/{}/'.format(API_BASE, preprint_provider._id) - def test_preprint_provider(self): - detail_res = self.app.get(self.provider_url) - assert_equals(detail_res.status_code, 200) + def test_preprint_provider_exists(self, app, provider_url, fake_url): + detail_res = app.get(provider_url) + assert detail_res.status_code == 200 - licenses_res = self.app.get('{}licenses/'.format(self.provider_url)) - assert_equals(licenses_res.status_code, 200) + licenses_res = app.get('{}licenses/'.format(provider_url)) + assert licenses_res.status_code == 200 - preprints_res = self.app.get('{}preprints/'.format(self.provider_url)) - assert_equals(preprints_res.status_code, 200) + preprints_res = app.get('{}preprints/'.format(provider_url)) + assert preprints_res.status_code == 200 - taxonomies_res = self.app.get('{}taxonomies/'.format(self.provider_url)) - assert_equals(taxonomies_res.status_code, 200) + taxonomies_res = app.get('{}taxonomies/'.format(provider_url)) + assert taxonomies_res.status_code == 200 - def test_preprint_provider_does_not_exist_returns_404(self): - detail_res = self.app.get(self.fake_url, expect_errors=True) - assert_equals(detail_res.status_code, 404) + # test_preprint_provider_does_not_exist_returns_404 + detail_res = app.get(fake_url, expect_errors=True) + assert detail_res.status_code == 404 - licenses_res = self.app.get('{}licenses/'.format(self.fake_url), expect_errors=True) - assert_equals(licenses_res.status_code, 404) + licenses_res = app.get('{}licenses/'.format(fake_url), expect_errors=True) + assert licenses_res.status_code == 404 - preprints_res = self.app.get('{}preprints/'.format(self.fake_url), expect_errors=True) - assert_equals(preprints_res.status_code, 404) + preprints_res = app.get('{}preprints/'.format(fake_url), expect_errors=True) + assert preprints_res.status_code == 404 - taxonomies_res = self.app.get('{}taxonomies/'.format(self.fake_url), expect_errors=True) - assert_equals(taxonomies_res.status_code, 404) + taxonomies_res = app.get('{}taxonomies/'.format(fake_url), expect_errors=True) + assert taxonomies_res.status_code == 404 diff --git a/api_tests/preprints/views/test_preprint_detail.py b/api_tests/preprints/views/test_preprint_detail.py index 4a899e98c50..f2c2120ba77 100644 --- a/api_tests/preprints/views/test_preprint_detail.py +++ b/api_tests/preprints/views/test_preprint_detail.py @@ -1,17 +1,23 @@ -import mock import functools +import mock +import pytest from modularodm import Q -from nose.tools import * # flake8: noqa from api.base.settings.defaults import API_BASE from api_tests import utils as test_utils from framework.auth.core import Auth -from osf_tests.factories import PreprintFactory, AuthUserFactory, ProjectFactory, SubjectFactory, PreprintProviderFactory from osf.models import PreprintService, NodeLicense from website.project.licenses import ensure_licenses from website.project.signals import contributor_added from website.identifiers.utils import build_ezid_metadata from tests.base import ApiTestCase, fake, capture_signals +from osf_tests.factories import ( + PreprintFactory, + AuthUserFactory, + ProjectFactory, + SubjectFactory, + PreprintProviderFactory +) ensure_licenses = functools.partial(ensure_licenses, warn=False) @@ -25,112 +31,137 @@ def build_preprint_update_payload(node_id, attributes=None, relationships=None): } return payload +@pytest.fixture() +def user(): + return AuthUserFactory() + +@pytest.mark.django_db +class TestPreprintDetail: + + @pytest.fixture() + def preprint(self, user): + return PreprintFactory(creator=user) + + @pytest.fixture() + def url(self, preprint): + return '/{}preprints/{}/'.format(API_BASE, preprint._id) + + @pytest.fixture() + def res(self, app, url): + return app.get(url) + + @pytest.fixture() + def data(self, res): + return res.json['data'] + + def test_preprint_detail(self, app, user, preprint, url, res, data): -class TestPreprintDetail(ApiTestCase): - def setUp(self): - super(TestPreprintDetail, self).setUp() + # test_preprint_detail_success + assert res.status_code == 200 + assert res.content_type == 'application/vnd.api+json' - self.user = AuthUserFactory() - self.preprint = PreprintFactory(creator=self.user) - self.url = '/{}preprints/{}/'.format(API_BASE, self.preprint._id) - self.res = self.app.get(self.url) - self.data = self.res.json['data'] + # test_preprint_top_level + assert data['type'] == 'preprints' + assert data['id'] == preprint._id - def test_preprint_detail_success(self): - assert_equal(self.res.status_code, 200) - assert_equal(self.res.content_type, 'application/vnd.api+json') + # test_preprint_node_deleted_detail_failure + deleted_node = ProjectFactory(creator=user, is_deleted=True) + deleted_preprint = PreprintFactory(project=deleted_node, creator=user) - def test_preprint_top_level(self): - assert_equal(self.data['type'], 'preprints') - assert_equal(self.data['id'], self.preprint._id) + deleted_preprint_url = '/{}preprints/{}/'.format(API_BASE, deleted_preprint._id) + deleted_preprint_res = app.get(deleted_preprint_url, expect_errors=True) + assert deleted_preprint_res.status_code == 404 + assert res.content_type == 'application/vnd.api+json' - def test_preprint_node_deleted_detail_failure(self): - deleted_node = ProjectFactory(creator=self.user, is_deleted=True) - deleted_preprint = PreprintFactory(project=deleted_node, creator=self.user) +@pytest.mark.django_db +class TestPreprintDelete: - url = '/{}preprints/{}/'.format(API_BASE, deleted_preprint._id) - res = self.app.get(url, expect_errors=True) - assert_equal(res.status_code, 404) - assert_equal(self.res.content_type, 'application/vnd.api+json') + @pytest.fixture() + def unpublished_preprint(self, user): + return PreprintFactory(creator=user, is_published=False) + @pytest.fixture() + def published_preprint(self, user): + return PreprintFactory(creator=user) -class TestPreprintDelete(ApiTestCase): - def setUp(self): - super(TestPreprintDelete, self).setUp() - self.user = AuthUserFactory() - self.unpublished_preprint = PreprintFactory(creator=self.user, is_published=False) - self.published_preprint = PreprintFactory(creator=self.user) - self.url = '/{}preprints/{{}}/'.format(API_BASE) + @pytest.fixture() + def url(self, user): + return '/{}preprints/{{}}/'.format(API_BASE) - def test_can_delete_unpublished(self): + def test_can_delete_unpublished(self, app, user, url, unpublished_preprint): previous_ids = list(PreprintService.objects.all().values_list('pk', flat=True)) - self.app.delete(self.url.format(self.unpublished_preprint._id), auth=self.user.auth) + app.delete(url.format(unpublished_preprint._id), auth=user.auth) remaining_ids = list(PreprintService.objects.all().values_list('pk', flat=True)) - assert_in(self.unpublished_preprint.pk, previous_ids) - assert_not_in(self.unpublished_preprint.pk, remaining_ids) + assert unpublished_preprint.pk in previous_ids + assert unpublished_preprint.pk not in remaining_ids - def test_cannot_delete_published(self): + def test_cannot_delete_published(self, app, user, published_preprint, url): previous_ids = list(PreprintService.objects.all().values_list('pk', flat=True)) - res = self.app.delete(self.url.format(self.published_preprint._id), auth=self.user.auth, expect_errors=True) + res = app.delete(url.format(published_preprint._id), auth=user.auth, expect_errors=True) remaining_ids = list(PreprintService.objects.all().values_list('pk', flat=True)) - assert_equal(res.status_code, 409) - assert_equal(previous_ids, remaining_ids) - assert_in(self.published_preprint.pk, remaining_ids) + assert res.status_code == 409 + assert previous_ids == remaining_ids + assert published_preprint.pk in remaining_ids - def test_deletes_only_requested_document(self): + def test_deletes_only_requested_document(self, app, user, published_preprint, unpublished_preprint, url): previous_ids = list(PreprintService.objects.all().values_list('pk', flat=True)) - res = self.app.delete(self.url.format(self.unpublished_preprint._id), auth=self.user.auth) + res = app.delete(url.format(unpublished_preprint._id), auth=user.auth) remaining_ids = list(PreprintService.objects.all().values_list('pk', flat=True)) - assert_in(self.unpublished_preprint.pk, previous_ids) - assert_in(self.published_preprint.pk, previous_ids) + assert unpublished_preprint.pk in previous_ids + assert published_preprint.pk in previous_ids - assert_not_in(self.unpublished_preprint.pk, remaining_ids) - assert_in(self.published_preprint.pk, remaining_ids) + assert unpublished_preprint.pk not in remaining_ids + assert published_preprint.pk in remaining_ids -class TestPreprintUpdate(ApiTestCase): - def setUp(self): - super(TestPreprintUpdate, self).setUp() - self.user = AuthUserFactory() +@pytest.mark.django_db +class TestPreprintUpdate: - self.preprint = PreprintFactory(creator=self.user) - self.url = '/{}preprints/{}/'.format(API_BASE, self.preprint._id) + @pytest.fixture() + def preprint(self, user): + return PreprintFactory(creator=user) - self.subject = SubjectFactory() + @pytest.fixture() + def url(self, preprint): + return '/{}preprints/{}/'.format(API_BASE, preprint._id) - def test_update_preprint_permission_denied(self): - update_doi_payload = build_preprint_update_payload(self.preprint._id, attributes={'article_doi': '10.123/456/789'}) + @pytest.fixture() + def subject(self): + return SubjectFactory() + + def test_update_preprint_permission_denied(self, app, preprint, url): + update_doi_payload = build_preprint_update_payload(preprint._id, attributes={'article_doi': '10.123/456/789'}) noncontrib = AuthUserFactory() - res = self.app.patch_json_api(self.url, update_doi_payload, auth=noncontrib.auth, expect_errors=True) - assert_equal(res.status_code, 403) + res = app.patch_json_api(url, update_doi_payload, auth=noncontrib.auth, expect_errors=True) + assert res.status_code == 403 - res = self.app.patch_json_api(self.url, update_doi_payload, expect_errors=True) - assert_equal(res.status_code, 401) + res = app.patch_json_api(url, update_doi_payload, expect_errors=True) + assert res.status_code == 401 - def test_update_subjects(self): - assert_false(self.preprint.subjects.filter(_id=self.subject._id).exists()) - update_subjects_payload = build_preprint_update_payload(self.preprint._id, attributes={"subjects": [[self.subject._id]]}) + def test_update_subjects(self, app, user, preprint, subject, url): + assert not preprint.subjects.filter(_id=subject._id).exists() + update_subjects_payload = build_preprint_update_payload(preprint._id, attributes={"subjects": [[subject._id]]}) - res = self.app.patch_json_api(self.url, update_subjects_payload, auth=self.user.auth) - assert_equal(res.status_code, 200) + res = app.patch_json_api(url, update_subjects_payload, auth=user.auth) + assert res.status_code == 200 - self.preprint.reload() - assert_true(self.preprint.subjects.filter(_id=self.subject._id).exists()) + preprint.reload() + assert preprint.subjects.filter(_id=subject._id).exists() - def test_update_invalid_subjects(self): - subjects = self.preprint.subjects - update_subjects_payload = build_preprint_update_payload(self.preprint._id, attributes={"subjects": [['wwe']]}) + def test_update_invalid_subjects(self, app, user, preprint, url): + subjects = preprint.subjects + update_subjects_payload = build_preprint_update_payload(preprint._id, attributes={"subjects": [['wwe']]}) - res = self.app.patch_json_api(self.url, update_subjects_payload, auth=self.user.auth, expect_errors=True) - assert_equal(res.status_code, 400) + res = app.patch_json_api(url, update_subjects_payload, auth=user.auth, expect_errors=True) + assert res.status_code == 400 - self.preprint.reload() - assert_equal(self.preprint.subjects, subjects) + preprint.reload() + assert preprint.subjects == subjects - def test_update_primary_file(self): - new_file = test_utils.create_test_file(self.preprint.node, self.user, filename='openupthatwindow.pdf') + def test_update_primary_file(self, app, user, preprint, url): + new_file = test_utils.create_test_file(preprint.node, user, filename='shook_that_mans_hand.pdf') relationships = { "primary_file": { "data": { @@ -139,23 +170,23 @@ def test_update_primary_file(self): } } } - assert_not_equal(self.preprint.primary_file, new_file) - update_file_payload = build_preprint_update_payload(self.preprint._id, relationships=relationships) + assert preprint.primary_file != new_file + update_file_payload = build_preprint_update_payload(preprint._id, relationships=relationships) - res = self.app.patch_json_api(self.url, update_file_payload, auth=self.user.auth) - assert_equal(res.status_code, 200) + res = app.patch_json_api(url, update_file_payload, auth=user.auth) + assert res.status_code == 200 - self.preprint.node.reload() - assert_equal(self.preprint.primary_file, new_file) + preprint.node.reload() + assert preprint.primary_file == new_file # check logs - log = self.preprint.node.logs.latest() - assert_equal(log.action, 'preprint_file_updated') - assert_equal(log.params.get('preprint'), self.preprint._id) + log = preprint.node.logs.latest() + assert log.action == 'preprint_file_updated' + assert log.params.get('preprint') == preprint._id - def test_new_primary_not_in_node(self): + def test_new_primary_not_in_node(self, app, user, preprint, url): project = ProjectFactory() - file_for_project = test_utils.create_test_file(project, self.user, filename='letoutthatantidote.pdf') + file_for_project = test_utils.create_test_file(project, user, filename='six_pack_novak.pdf') relationships = { "primary_file": { @@ -166,37 +197,39 @@ def test_new_primary_not_in_node(self): } } - update_file_payload = build_preprint_update_payload(self.preprint._id, relationships=relationships) + update_file_payload = build_preprint_update_payload(preprint._id, relationships=relationships) - res = self.app.patch_json_api(self.url, update_file_payload, auth=self.user.auth, expect_errors=True) - assert_equal(res.status_code, 400) + res = app.patch_json_api(url, update_file_payload, auth=user.auth, expect_errors=True) + assert res.status_code == 400 - self.preprint.reload() - assert_not_equal(self.preprint.primary_file, file_for_project) + preprint.reload() + assert preprint.primary_file != file_for_project - def test_update_article_doi(self): + def test_update_article_doi(self, app, user, preprint, url): new_doi = '10.1234/ASDFASDF' - assert_not_equal(self.preprint.article_doi, new_doi) - update_subjects_payload = build_preprint_update_payload(self.preprint._id, attributes={"doi": new_doi}) + assert preprint.article_doi != new_doi + update_subjects_payload = build_preprint_update_payload(preprint._id, attributes={"doi": new_doi}) + + res = app.patch_json_api(url, update_subjects_payload, auth=user.auth) + assert res.status_code == 200 - res = self.app.patch_json_api(self.url, update_subjects_payload, auth=self.user.auth) - assert_equal(res.status_code, 200) + preprint.node.reload() + assert preprint.article_doi == new_doi - self.preprint.node.reload() - assert_equal(self.preprint.article_doi, new_doi) + preprint_detail = app.get(url, auth=user.auth).json['data'] + assert preprint_detail['links']['doi'] == 'https://dx.doi.org/{}'.format(new_doi) - preprint_detail = self.app.get(self.url, auth=self.user.auth).json['data'] - assert_equal(preprint_detail['links']['doi'], 'https://dx.doi.org/{}'.format(new_doi)) + def test_cannot_set_primary_file(self, app, user, preprint, url): - def test_write_contrib_cannot_set_primary_file(self): - user_two = AuthUserFactory() - self.preprint.node.add_contributor(user_two, permissions=['read', 'write'], auth=Auth(self.user), save=True) - new_file = test_utils.create_test_file(self.preprint.node, self.user, filename='openupthatwindow.pdf') + # test_write_contrib_cannot_set_primary_file + read_write_contrib = AuthUserFactory() + preprint.node.add_contributor(read_write_contrib, permissions=['read', 'write'], auth=Auth(user), save=True) + new_file = test_utils.create_test_file(preprint.node, user, filename='lovechild_reason.pdf') data = { 'data':{ 'type': 'primary_file', - 'id': self.preprint._id, + 'id': preprint._id, 'attributes': {}, 'relationships': { 'primary_file': { @@ -209,17 +242,17 @@ def test_write_contrib_cannot_set_primary_file(self): } } - res = self.app.patch_json_api(self.url, data, auth=user_two.auth, expect_errors=True) - assert_equal(res.status_code, 403) + res = app.patch_json_api(url, data, auth=read_write_contrib.auth, expect_errors=True) + assert res.status_code == 403 - def test_noncontrib_cannot_set_primary_file(self): - user_two = AuthUserFactory() - new_file = test_utils.create_test_file(self.preprint.node, self.user, filename='openupthatwindow.pdf') + # test_noncontrib_cannot_set_primary_file + non_contrib = AuthUserFactory() + new_file = test_utils.create_test_file(preprint.node, user, filename='flowerchild_nik.pdf') data = { 'data':{ 'type': 'primary_file', - 'id': self.preprint._id, + 'id': preprint._id, 'attributes': {}, 'relationships': { 'primary_file': { @@ -232,451 +265,514 @@ def test_noncontrib_cannot_set_primary_file(self): } } - res = self.app.patch_json_api(self.url, data, auth=user_two.auth, expect_errors=True) - assert_equal(res.status_code, 403) + res = app.patch_json_api(url, data, auth=non_contrib.auth, expect_errors=True) + assert res.status_code == 403 + + def test_contribs_cannot_set_subjects(self, app, user, preprint, subject, url): - def test_write_contrib_cannot_set_subjects(self): - user_two = AuthUserFactory() - self.preprint.node.add_contributor(user_two, permissions=['read', 'write'], auth=Auth(self.user), save=True) + # def test_write_contrib_cannot_set_subjects(self, app, user, preprint, subject, url): + write_contrib = AuthUserFactory() + preprint.node.add_contributor(write_contrib, permissions=['read', 'write'], auth=Auth(user), save=True) - assert_false(self.preprint.subjects.filter(_id=self.subject._id).exists()) - update_subjects_payload = build_preprint_update_payload(self.preprint._id, attributes={"subjects": [[self.subject._id]]}) + assert not preprint.subjects.filter(_id=subject._id).exists() + update_subjects_payload = build_preprint_update_payload(preprint._id, attributes={"subjects": [[subject._id]]}) - res = self.app.patch_json_api(self.url, update_subjects_payload, auth=user_two.auth, expect_errors=True) - assert_equal(res.status_code, 403) + res = app.patch_json_api(url, update_subjects_payload, auth=write_contrib.auth, expect_errors=True) + assert res.status_code == 403 - assert_false(self.preprint.subjects.filter(_id=self.subject._id).exists()) + assert not preprint.subjects.filter(_id=subject._id).exists() - def test_noncontrib_cannot_set_subjects(self): - user_two = AuthUserFactory() - self.preprint.node.add_contributor(user_two, permissions=['read', 'write'], auth=Auth(self.user), save=True) + # def test_non_contrib_cannot_set_subjects(self, app, user, preprint, subject, url): + non_contrib = AuthUserFactory() - assert_false(self.preprint.subjects.filter(_id=self.subject._id).exists()) + assert not preprint.subjects.filter(_id=subject._id).exists() - update_subjects_payload = build_preprint_update_payload(self.preprint._id, attributes={"subjects": [[self.subject._id]]}) + update_subjects_payload = build_preprint_update_payload(preprint._id, attributes={"subjects": [[subject._id]]}) - res = self.app.patch_json_api(self.url, update_subjects_payload, auth=user_two.auth, expect_errors=True) - assert_equal(res.status_code, 403) + res = app.patch_json_api(url, update_subjects_payload, auth=non_contrib.auth, expect_errors=True) + assert res.status_code == 403 - assert_false(self.preprint.subjects.filter(_id=self.subject._id).exists()) + assert not preprint.subjects.filter(_id=subject._id).exists() - def test_update_published(self): - unpublished = PreprintFactory(creator=self.user, is_published=False) + def test_update_published(self, app, user): + unpublished = PreprintFactory(creator=user, is_published=False) url = '/{}preprints/{}/'.format(API_BASE, unpublished._id) payload = build_preprint_update_payload(unpublished._id, attributes={'is_published': True}) - res = self.app.patch_json_api(url, payload, auth=self.user.auth) + res = app.patch_json_api(url, payload, auth=user.auth) unpublished.reload() - assert_true(unpublished.is_published) + assert unpublished.is_published @mock.patch('website.preprints.tasks.on_preprint_updated.s') - def test_update_preprint_task_called_on_api_update(self, mock_on_preprint_updated): - update_doi_payload = build_preprint_update_payload(self.preprint._id, attributes={'doi': '10.1234/ASDFASDF'}) + def test_update_preprint_task_called_on_api_update(self, mock_on_preprint_updated, app, user, preprint, url): + update_doi_payload = build_preprint_update_payload(preprint._id, attributes={'doi': '10.1234/ASDFASDF'}) - self.app.patch_json_api(self.url, update_doi_payload, auth=self.user.auth) - self.preprint.node.reload() + app.patch_json_api(url, update_doi_payload, auth=user.auth) + preprint.node.reload() assert mock_on_preprint_updated.called -class TestPreprintUpdateLicense(ApiTestCase): - - def setUp(self): - super(TestPreprintUpdateLicense, self).setUp() - - ensure_licenses() - - self.admin_contributor = AuthUserFactory() - self.rw_contributor = AuthUserFactory() - self.read_contributor = AuthUserFactory() - self.non_contributor = AuthUserFactory() +@pytest.mark.django_db +class TestPreprintUpdateLicense: - self.preprint_provider = PreprintProviderFactory() - self.preprint = PreprintFactory(creator=self.admin_contributor, provider=self.preprint_provider) + @pytest.fixture() + def admin_contributor(self): + return AuthUserFactory() - self.preprint.node.add_contributor(self.rw_contributor, auth=Auth(self.admin_contributor)) - self.preprint.node.add_contributor(self.read_contributor, auth=Auth(self.admin_contributor), permissions=['read']) - self.preprint.node.save() + @pytest.fixture() + def rw_contributor(self): + return AuthUserFactory() - self.cc0_license = NodeLicense.find_one(Q('name', 'eq', 'CC0 1.0 Universal')) - self.mit_license = NodeLicense.find_one(Q('name', 'eq', 'MIT License')) - self.no_license = NodeLicense.find_one(Q('name', 'eq', 'No license')) + @pytest.fixture() + def read_contributor(self): + return AuthUserFactory() - self.preprint_provider.licenses_acceptable = [self.cc0_license, self.no_license] - self.preprint_provider.save() + @pytest.fixture() + def non_contributor(self): + return AuthUserFactory() - self.url = '/{}preprints/{}/'.format(API_BASE, self.preprint._id) + @pytest.fixture() + def cc0_license(self): + ensure_licenses() + return NodeLicense.find_one(Q('name', 'eq', 'CC0 1.0 Universal')) - def make_payload(self, node_id, license_id=None, license_year=None, copyright_holders=None): - attributes = {} + @pytest.fixture() + def mit_license(self): + ensure_licenses() + return NodeLicense.find_one(Q('name', 'eq', 'MIT License')) - if license_year and copyright_holders: - attributes = { - 'license_record': { - 'year': license_year, - 'copyright_holders': copyright_holders + @pytest.fixture() + def no_license(self): + ensure_licenses() + return NodeLicense.find_one(Q('name', 'eq', 'No license')) + + @pytest.fixture() + def preprint_provider(self, cc0_license, no_license): + preprint_provider = PreprintProviderFactory() + preprint_provider.licenses_acceptable = [cc0_license, no_license] + preprint_provider.save() + return preprint_provider + + @pytest.fixture() + def preprint(self, admin_contributor, rw_contributor, read_contributor, preprint_provider): + preprint = PreprintFactory(creator=admin_contributor, provider=preprint_provider) + preprint.node.add_contributor(rw_contributor, auth=Auth(admin_contributor)) + preprint.node.add_contributor(read_contributor, auth=Auth(admin_contributor), permissions=['read']) + preprint.node.save() + return preprint + + @pytest.fixture() + def url(self, preprint): + return '/{}preprints/{}/'.format(API_BASE, preprint._id) + + @pytest.fixture() + def make_payload(self): + def payload(node_id, license_id=None, license_year=None, copyright_holders=None): + attributes = {} + + if license_year and copyright_holders: + attributes = { + 'license_record': { + 'year': license_year, + 'copyright_holders': copyright_holders + } } - } - elif license_year: - attributes = { - 'license_record': { - 'year': license_year + elif license_year: + attributes = { + 'license_record': { + 'year': license_year + } } - } - elif copyright_holders: - attributes = { - 'license_record': { - 'copyright_holders': copyright_holders + elif copyright_holders: + attributes = { + 'license_record': { + 'copyright_holders': copyright_holders + } } - } - return { - 'data': { - 'id': node_id, - 'attributes': attributes, - 'relationships': { - 'license': { - 'data': { - 'type': 'licenses', - 'id': license_id + return { + 'data': { + 'id': node_id, + 'attributes': attributes, + 'relationships': { + 'license': { + 'data': { + 'type': 'licenses', + 'id': license_id + } } } } + } if license_id else { + 'data': { + 'id': node_id, + 'attributes': attributes + } } - } if license_id else { - 'data': { - 'id': node_id, - 'attributes': attributes - } - } - def make_request(self, url, data, auth=None, expect_errors=False): - return self.app.patch_json_api(url, data, auth=auth, expect_errors=expect_errors) + return payload + + @pytest.fixture() + def make_request(self, app): + def request(url, data, auth=None, expect_errors=False): + return app.patch_json_api(url, data, auth=auth, expect_errors=expect_errors) + return request - def test_admin_update_license_with_invalid_id(self): - data = self.make_payload( - node_id=self.preprint._id, + def test_admin_update_license_with_invalid_id(self, admin_contributor, preprint, url, make_payload, make_request): + data = make_payload( + node_id=preprint._id, license_id='thisisafakelicenseid' ) - assert_equal(self.preprint.license, None) + assert preprint.license == None - res = self.make_request(self.url, data, auth=self.admin_contributor.auth, expect_errors=True) - assert_equal(res.status_code, 404) - assert_equal(res.json['errors'][0]['detail'], 'Unable to find specified license.') + res = make_request(url, data, auth=admin_contributor.auth, expect_errors=True) + assert res.status_code == 404 + assert res.json['errors'][0]['detail'] == 'Unable to find specified license.' - self.preprint.reload() - assert_equal(self.preprint.license, None) + preprint.reload() + assert preprint.license == None - def test_admin_can_update_license(self): - data = self.make_payload( - node_id=self.preprint._id, - license_id=self.cc0_license._id + def test_admin_can_update_license(self, admin_contributor, preprint, cc0_license, url, make_payload, make_request): + data = make_payload( + node_id=preprint._id, + license_id=cc0_license._id ) - assert_equal(self.preprint.license, None) + assert preprint.license == None - res = self.make_request(self.url, data, auth=self.admin_contributor.auth) - assert_equal(res.status_code, 200) - self.preprint.reload() + res = make_request(url, data, auth=admin_contributor.auth) + assert res.status_code == 200 + preprint.reload() - assert_equal(self.preprint.license.node_license, self.cc0_license) - assert_equal(self.preprint.license.year, None) - assert_equal(self.preprint.license.copyright_holders, []) + assert preprint.license.node_license == cc0_license + assert preprint.license.year == None + assert preprint.license.copyright_holders == [] # check logs - log = self.preprint.node.logs.latest() - assert_equal(log.action, 'preprint_license_updated') - assert_equal(log.params.get('preprint'), self.preprint._id) - - def test_admin_can_update_license_record(self): - data = self.make_payload( - node_id=self.preprint._id, - license_id=self.no_license._id, + log = preprint.node.logs.latest() + assert log.action == 'preprint_license_updated' + assert log.params.get('preprint') == preprint._id + + def test_admin_can_update_license_record(self, admin_contributor, preprint, no_license, url, make_payload, make_request): + data = make_payload( + node_id=preprint._id, + license_id=no_license._id, license_year='2015', - copyright_holders=['Bojack Horseman, Princess Carolyn'] + copyright_holders=['Tonya Shepoly, Lucas Pucas'] ) - assert_equal(self.preprint.license, None) + assert preprint.license == None - res = self.make_request(self.url, data, auth=self.admin_contributor.auth) - assert_equal(res.status_code, 200) - self.preprint.reload() + res = make_request(url, data, auth=admin_contributor.auth) + assert res.status_code == 200 + preprint.reload() + + assert preprint.license.node_license == no_license + assert preprint.license.year == '2015' + assert preprint.license.copyright_holders == ['Tonya Shepoly, Lucas Pucas'] + + def test_cannot_update_license(self, rw_contributor, read_contributor, non_contributor, preprint, cc0_license, url, make_payload, make_request): + + # test_rw_contributor_cannot_update_license + data = make_payload( + node_id=preprint._id, + license_id=cc0_license._id + ) - assert_equal(self.preprint.license.node_license, self.no_license) - assert_equal(self.preprint.license.year, '2015') - assert_equal(self.preprint.license.copyright_holders, ['Bojack Horseman, Princess Carolyn']) + res = make_request(url, data, auth=rw_contributor.auth, expect_errors=True) + assert res.status_code == 403 + assert res.json['errors'][0]['detail'] == 'User must be an admin to update a preprint.' - def test_rw_contributor_cannot_update_license(self): - data = self.make_payload( - node_id=self.preprint._id, - license_id=self.cc0_license._id + # test_read_contributor_cannot_update_license + data = make_payload( + node_id=preprint._id, + license_id=cc0_license._id ) - res = self.make_request(self.url, data, auth=self.rw_contributor.auth, expect_errors=True) - assert_equal(res.status_code, 403) - assert_equal(res.json['errors'][0]['detail'], 'User must be an admin to update a preprint.') + res = make_request(url, data, auth=read_contributor.auth, expect_errors=True) + assert res.status_code == 403 + assert res.json['errors'][0]['detail'] == 'You do not have permission to perform this action.' - def test_read_contributor_cannot_update_license(self): - data = self.make_payload( - node_id=self.preprint._id, - license_id=self.cc0_license._id + # test_non_contributor_cannot_update_license + data = make_payload( + node_id=preprint._id, + license_id=cc0_license._id ) - res = self.make_request(self.url, data, auth=self.read_contributor.auth, expect_errors=True) - assert_equal(res.status_code, 403) - assert_equal(res.json['errors'][0]['detail'], 'You do not have permission to perform this action.') + res = make_request(url, data, auth=non_contributor.auth, expect_errors=True) + assert res.status_code == 403 + assert res.json['errors'][0]['detail'] == 'You do not have permission to perform this action.' - def test_non_contributor_cannot_update_license(self): - data = self.make_payload( - node_id=self.preprint._id, - license_id=self.cc0_license._id + # test_unauthenticated_user_cannot_update_license + data = make_payload( + node_id=preprint._id, + license_id=cc0_license._id ) - res = self.make_request(self.url, data, auth=self.non_contributor.auth, expect_errors=True) - assert_equal(res.status_code, 403) - assert_equal(res.json['errors'][0]['detail'], 'You do not have permission to perform this action.') + res = make_request(url, data, expect_errors=True) + assert res.status_code == 401 + assert res.json['errors'][0]['detail'] == 'Authentication credentials were not provided.' + + def test_update_error(self, admin_contributor, preprint, preprint_provider, mit_license, no_license, url, make_payload, make_request): - def test_unauthenticated_user_cannot_update_license(self): - data = self.make_payload( - node_id=self.preprint._id, - license_id=self.cc0_license._id + # test_update_preprint_with_invalid_license_for_provider + data = make_payload( + node_id=preprint._id, + license_id=mit_license._id ) - res = self.make_request(self.url, data, expect_errors=True) - assert_equal(res.status_code, 401) - assert_equal(res.json['errors'][0]['detail'], 'Authentication credentials were not provided.') + assert preprint.license == None + + res = make_request(url, data, auth=admin_contributor.auth, expect_errors=True) + assert res.status_code == 403 + assert res.json['errors'][0]['detail'] == 'Invalid license chosen for {}'.format(preprint_provider.name) - def test_update_preprint_with_invalid_license_for_provider(self): - data = self.make_payload( - node_id=self.preprint._id, - license_id=self.mit_license._id + # test_update_preprint_license_without_required_year_in_payload + data = make_payload( + node_id=preprint._id, + license_id=no_license._id, + copyright_holders=['Rachel', 'Rheisen'] ) - assert_equal(self.preprint.license, None) + res = make_request(url, data, auth=admin_contributor.auth, expect_errors=True) + assert res.status_code == 400 + assert res.json['errors'][0]['detail'] == 'year must be specified for this license' + + # test_update_preprint_license_without_required_copyright_holders_in_payload + data = make_payload( + node_id=preprint._id, + license_id=no_license._id, + license_year='1994' + ) - res = self.make_request(self.url, data, auth=self.admin_contributor.auth, expect_errors=True) - assert_equal(res.status_code, 403) - assert_equal(res.json['errors'][0]['detail'], 'Invalid license chosen for {}'.format(self.preprint_provider.name)) + res = make_request(url, data, auth=admin_contributor.auth, expect_errors=True) + assert res.status_code == 400 + assert res.json['errors'][0]['detail'] == 'copyrightHolders must be specified for this license' - def test_update_preprint_with_existing_license_year_attribute_only(self): - self.preprint.set_preprint_license( + def test_update_preprint_with_existing_license_year_attribute_only(self, admin_contributor, preprint, no_license, url, make_payload, make_request): + preprint.set_preprint_license( { - 'id': self.no_license.license_id, + 'id': no_license.license_id, 'year': '2014', - 'copyrightHolders': ['Diane', 'Mr. Peanut Butter'] + 'copyrightHolders': ['Daniel FromBrazil', 'Queen Jaedyn'] }, - Auth(self.admin_contributor), + Auth(admin_contributor), ) - self.preprint.save() + preprint.save() - assert_equal(self.preprint.license.node_license, self.no_license) - assert_equal(self.preprint.license.year, '2014') - assert_equal(self.preprint.license.copyright_holders, ['Diane', 'Mr. Peanut Butter']) + assert preprint.license.node_license == no_license + assert preprint.license.year == '2014' + assert preprint.license.copyright_holders == ['Daniel FromBrazil', 'Queen Jaedyn'] - data = self.make_payload( - node_id=self.preprint._id, + data = make_payload( + node_id=preprint._id, license_year='2015' ) - res = self.make_request(self.url, data, auth=self.admin_contributor.auth) - assert_equal(res.status_code, 200) - self.preprint.license.reload() + res = make_request(url, data, auth=admin_contributor.auth) + assert res.status_code == 200 + preprint.license.reload() - assert_equal(self.preprint.license.node_license, self.no_license) - assert_equal(self.preprint.license.year, '2015') - assert_equal(self.preprint.license.copyright_holders, ['Diane', 'Mr. Peanut Butter']) + assert preprint.license.node_license == no_license + assert preprint.license.year == '2015' + assert preprint.license.copyright_holders == ['Daniel FromBrazil', 'Queen Jaedyn'] - def test_update_preprint_with_existing_license_copyright_holders_attribute_only(self): - self.preprint.set_preprint_license( + def test_update_preprint_with_existing_license_copyright_holders_attribute_only(self, admin_contributor, preprint, no_license, url, make_payload, make_request): + preprint.set_preprint_license( { - 'id': self.no_license.license_id, + 'id': no_license.license_id, 'year': '2014', - 'copyrightHolders': ['Diane', 'Mr. Peanut Butter'] + 'copyrightHolders': ['Captain Haley', 'Keegor Cannoli'] }, - Auth(self.admin_contributor), + Auth(admin_contributor), ) - self.preprint.save() + preprint.save() - assert_equal(self.preprint.license.node_license, self.no_license) - assert_equal(self.preprint.license.year, '2014') - assert_equal(self.preprint.license.copyright_holders, ['Diane', 'Mr. Peanut Butter']) + assert preprint.license.node_license == no_license + assert preprint.license.year == '2014' + assert preprint.license.copyright_holders == ['Captain Haley', 'Keegor Cannoli'] - data = self.make_payload( - node_id=self.preprint._id, - copyright_holders=['Bojack Horseman', 'Princess Carolyn'] + data = make_payload( + node_id=preprint._id, + copyright_holders=['Reason Danish', 'Ben the NJB'] ) - res = self.make_request(self.url, data, auth=self.admin_contributor.auth) - assert_equal(res.status_code, 200) - self.preprint.license.reload() + res = make_request(url, data, auth=admin_contributor.auth) + assert res.status_code == 200 + preprint.license.reload() - assert_equal(self.preprint.license.node_license, self.no_license) - assert_equal(self.preprint.license.year, '2014') - assert_equal(self.preprint.license.copyright_holders, ['Bojack Horseman', 'Princess Carolyn']) + assert preprint.license.node_license == no_license + assert preprint.license.year == '2014' + assert preprint.license.copyright_holders == ['Reason Danish', 'Ben the NJB'] - def test_update_preprint_with_existing_license_relationship_only(self): - self.preprint.set_preprint_license( + def test_update_preprint_with_existing_license_relationship_only(self, admin_contributor, preprint, cc0_license, no_license, url, make_payload, make_request): + preprint.set_preprint_license( { - 'id': self.no_license.license_id, + 'id': no_license.license_id, 'year': '2014', - 'copyrightHolders': ['Diane', 'Mr. Peanut Butter'] + 'copyrightHolders': ['Reason', 'Mr. Lulu'] }, - Auth(self.admin_contributor), + Auth(admin_contributor), ) - self.preprint.save() + preprint.save() - assert_equal(self.preprint.license.node_license, self.no_license) - assert_equal(self.preprint.license.year, '2014') - assert_equal(self.preprint.license.copyright_holders, ['Diane', 'Mr. Peanut Butter']) + assert preprint.license.node_license == no_license + assert preprint.license.year == '2014' + assert preprint.license.copyright_holders == ['Reason', 'Mr. Lulu'] - data = self.make_payload( - node_id=self.preprint._id, - license_id=self.cc0_license._id + data = make_payload( + node_id=preprint._id, + license_id=cc0_license._id ) - res = self.make_request(self.url, data, auth=self.admin_contributor.auth) - assert_equal(res.status_code, 200) - self.preprint.license.reload() + res = make_request(url, data, auth=admin_contributor.auth) + assert res.status_code == 200 + preprint.license.reload() - assert_equal(self.preprint.license.node_license, self.cc0_license) - assert_equal(self.preprint.license.year, '2014') - assert_equal(self.preprint.license.copyright_holders, ['Diane', 'Mr. Peanut Butter']) + assert preprint.license.node_license == cc0_license + assert preprint.license.year == '2014' + assert preprint.license.copyright_holders == ['Reason', 'Mr. Lulu'] - def test_update_preprint_with_existing_license_relationship_and_attributes(self): - self.preprint.set_preprint_license( + def test_update_preprint_with_existing_license_relationship_and_attributes(self, admin_contributor, preprint, cc0_license, no_license, url, make_payload, make_request): + preprint.set_preprint_license( { - 'id': self.no_license.license_id, + 'id': no_license.license_id, 'year': '2014', - 'copyrightHolders': ['Diane', 'Mr. Peanut Butter'] + 'copyrightHolders': ['Reason', 'Mr. Cosgrove'] }, - Auth(self.admin_contributor), + Auth(admin_contributor), save=True ) - assert_equal(self.preprint.license.node_license, self.no_license) - assert_equal(self.preprint.license.year, '2014') - assert_equal(self.preprint.license.copyright_holders, ['Diane', 'Mr. Peanut Butter']) + assert preprint.license.node_license == no_license + assert preprint.license.year == '2014' + assert preprint.license.copyright_holders == ['Reason', 'Mr. Cosgrove'] - data = self.make_payload( - node_id=self.preprint._id, - license_id=self.cc0_license._id, + data = make_payload( + node_id=preprint._id, + license_id=cc0_license._id, license_year='2015', - copyright_holders=['Bojack Horseman', 'Princess Carolyn'] - ) - - res = self.make_request(self.url, data, auth=self.admin_contributor.auth) - assert_equal(res.status_code, 200) - self.preprint.license.reload() - - assert_equal(self.preprint.license.node_license, self.cc0_license) - assert_equal(self.preprint.license.year, '2015') - assert_equal(self.preprint.license.copyright_holders, ['Bojack Horseman', 'Princess Carolyn']) - - def test_update_preprint_license_without_required_year_in_payload(self): - data = self.make_payload( - node_id=self.preprint._id, - license_id=self.no_license._id, - copyright_holders=['Rick', 'Morty'] + copyright_holders=['Rheisen', 'Princess Tyler'] ) - res = self.make_request(self.url, data, auth=self.admin_contributor.auth, expect_errors=True) - assert_equal(res.status_code, 400) - assert_equal(res.json['errors'][0]['detail'], 'year must be specified for this license') - - def test_update_preprint_license_without_required_copyright_holders_in_payload_(self): - data = self.make_payload( - node_id=self.preprint._id, - license_id=self.no_license._id, - license_year='1994' - ) + res = make_request(url, data, auth=admin_contributor.auth) + assert res.status_code == 200 + preprint.license.reload() - res = self.make_request(self.url, data, auth=self.admin_contributor.auth, expect_errors=True) - assert_equal(res.status_code, 400) - assert_equal(res.json['errors'][0]['detail'], 'copyrightHolders must be specified for this license') + assert preprint.license.node_license == cc0_license + assert preprint.license.year == '2015' + assert preprint.license.copyright_holders == ['Rheisen', 'Princess Tyler'] - def test_update_preprint_license_does_not_change_project_license(self): - self.preprint.node.set_node_license( + def test_update_preprint_license_does_not_change_project_license(self, admin_contributor, preprint, cc0_license, no_license, url, make_payload, make_request): + preprint.node.set_node_license( { - 'id': self.no_license.license_id, + 'id': no_license.license_id, 'year': '2015', 'copyrightHolders': ['Simba', 'Mufasa'] }, - auth=Auth(self.admin_contributor) + auth=Auth(admin_contributor) ) - self.preprint.node.save() - assert_equal(self.preprint.node.node_license.node_license, self.no_license) + preprint.node.save() + assert preprint.node.node_license.node_license == no_license - data = self.make_payload( - node_id=self.preprint._id, - license_id=self.cc0_license._id + data = make_payload( + node_id=preprint._id, + license_id=cc0_license._id ) - res = self.make_request(self.url, data, auth=self.admin_contributor.auth) - assert_equal(res.status_code, 200) - self.preprint.reload() + res = make_request(url, data, auth=admin_contributor.auth) + assert res.status_code == 200 + preprint.reload() - assert_equal(self.preprint.license.node_license, self.cc0_license) - assert_equal(self.preprint.node.node_license.node_license, self.no_license) + assert preprint.license.node_license == cc0_license + assert preprint.node.node_license.node_license == no_license - def test_update_preprint_license_without_change_does_not_add_log(self): - self.preprint.set_preprint_license( + def test_update_preprint_license_without_change_does_not_add_log(self, admin_contributor, preprint, no_license, url, make_payload, make_request): + preprint.set_preprint_license( { - 'id': self.no_license.license_id, + 'id': no_license.license_id, 'year': '2015', 'copyrightHolders': ['Kim', 'Kanye'] }, - auth=Auth(self.admin_contributor), + auth=Auth(admin_contributor), save=True ) - before_num_logs = self.preprint.node.logs.count() - before_update_log = self.preprint.node.logs.latest() + before_num_logs = preprint.node.logs.count() + before_update_log = preprint.node.logs.latest() - data = self.make_payload( - node_id=self.preprint._id, - license_id=self.no_license._id, + data = make_payload( + node_id=preprint._id, + license_id=no_license._id, license_year='2015', copyright_holders=['Kanye', 'Kim'] ) - res = self.make_request(self.url, data, auth=self.admin_contributor.auth) - self.preprint.node.reload() + res = make_request(url, data, auth=admin_contributor.auth) + preprint.node.reload() + + after_num_logs = preprint.node.logs.count() + after_update_log = preprint.node.logs.latest() + + assert res.status_code == 200 + assert before_num_logs == after_num_logs + assert before_update_log._id == after_update_log._id + + +@pytest.mark.django_db +class TestPreprintIsPublishedDetail: + + @pytest.fixture() + def admin(self): + return AuthUserFactory() + + @pytest.fixture() + def write_contrib(self): + return AuthUserFactory() + + @pytest.fixture() + def non_contrib(self): + return AuthUserFactory() - after_num_logs = self.preprint.node.logs.count() - after_update_log = self.preprint.node.logs.latest() + @pytest.fixture() + def public_project(self, admin, write_contrib): + public_project = ProjectFactory(creator=admin, is_public=True) + public_project.add_contributor(write_contrib, permissions=['read', 'write'], save=True) + return public_project - assert_equal(res.status_code, 200) - assert_equal(before_num_logs, after_num_logs) - assert_equal(before_update_log._id, after_update_log._id) + @pytest.fixture() + def subject(self): + return SubjectFactory() + @pytest.fixture() + def provider(self): + return PreprintProviderFactory() -class TestPreprintIsPublishedDetail(ApiTestCase): - def setUp(self): - super(TestPreprintIsPublishedDetail, self).setUp() - self.admin= AuthUserFactory() - self.write_contrib = AuthUserFactory() - self.non_contrib = AuthUserFactory() + @pytest.fixture() + def file_one_public_project(self, admin, public_project): + return test_utils.create_test_file(public_project, admin, 'toe_socks_and_sunrises.pdf') - self.public_project = ProjectFactory(creator=self.admin, is_public=True) - self.public_project.add_contributor(self.write_contrib, permissions=['read', 'write'], save=True) - self.subject = SubjectFactory() - self.provider = PreprintProviderFactory() - self.file_one_public_project = test_utils.create_test_file(self.public_project, self.admin, 'mgla.pdf') + @pytest.fixture() + def unpublished_preprint(self, admin, provider, subject, public_project): + return PreprintFactory(creator=admin, filename='toe_socks_and_sunrises.pdf', provider=provider, subjects=[[subject._id]], project=public_project, is_published=False) - self.unpublished_preprint = PreprintFactory(creator=self.admin, filename='mgla.pdf', provider=self.provider, subjects=[[self.subject._id]], project=self.public_project, is_published=False) + @pytest.fixture() + def url(self, unpublished_preprint): + return '/{}preprints/{}/'.format(API_BASE, unpublished_preprint._id) - self.url = '/{}preprints/{}/'.format(API_BASE, self.unpublished_preprint._id) + def test_preprint_is_published_detail(self, app, admin, write_contrib, non_contrib, unpublished_preprint, url): - def test_unpublished_visible_to_admins(self): - res = self.app.get(self.url, auth=self.admin.auth) - assert res.json['data']['id'] == self.unpublished_preprint._id + # test_unpublished_visible_to_admins + res = app.get(url, auth=admin.auth) + assert res.json['data']['id'] == unpublished_preprint._id - def test_unpublished_invisible_to_write_contribs(self): - res = self.app.get(self.url, auth=self.write_contrib.auth, expect_errors=True) + # test_unpublished_invisible_to_write_contribs + res = app.get(url, auth=write_contrib.auth, expect_errors=True) assert res.status_code == 403 - def test_unpublished_invisible_to_non_contribs(self): - res = self.app.get(self.url, auth=self.non_contrib.auth, expect_errors=True) + # test_unpublished_invisible_to_non_contribs + res = app.get(url, auth=non_contrib.auth, expect_errors=True) assert res.status_code == 403 - def test_unpublished_invisible_to_public(self): - res = self.app.get(self.url, expect_errors=True) + # test_unpublished_invisible_to_public + res = app.get(url, expect_errors=True) assert res.status_code == 401 From 5079ef52751288758596e1c9e0ffed119540a05e Mon Sep 17 00:00:00 2001 From: Fabrice Mizero Date: Wed, 7 Jun 2017 13:23:19 -0400 Subject: [PATCH 057/163] Allow passing extra data to sentry --- framework/sentry/__init__.py | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/framework/sentry/__init__.py b/framework/sentry/__init__.py index 677bd25cc07..5f74f6c618f 100644 --- a/framework/sentry/__init__.py +++ b/framework/sentry/__init__.py @@ -35,13 +35,11 @@ def log_exception(): }) -def log_message(message): +def log_message(message, extra={}): if not enabled: logger.warning( 'Sentry called to log message, but is not active: %s' % message ) return None - return sentry.captureMessage(message, extra={ - 'session': get_session_data(), - }) + return sentry.captureMessage(message, extra=extra) From c4bbf4181b3d32984a866c6a37d8bdc91fbb71d1 Mon Sep 17 00:00:00 2001 From: Fabrice Mizero Date: Wed, 7 Jun 2017 13:24:02 -0400 Subject: [PATCH 058/163] Pass guid as extra data --- website/views.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/website/views.py b/website/views.py index 2abfbad0953..01e9969de59 100644 --- a/website/views.py +++ b/website/views.py @@ -246,7 +246,7 @@ def resolve_guid(guid, suffix=None): # expected. if not hasattr(guid_object.referent, 'deep_url'): sentry.log_message( - 'Guid `{}` resolved to an object with no deep_url'.format(guid) + 'Guid resolved to an object with no deep_url', dict(guid = guid) ) raise HTTPError(http.NOT_FOUND) referent = guid_object.referent From 57f72a0f64ccc7713a38a03d016e05ec8c528b1d Mon Sep 17 00:00:00 2001 From: Fabrice Mizero Date: Wed, 7 Jun 2017 13:35:40 -0400 Subject: [PATCH 059/163] Add session info to extra data --- framework/sentry/__init__.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/framework/sentry/__init__.py b/framework/sentry/__init__.py index 5f74f6c618f..9abcce701e0 100644 --- a/framework/sentry/__init__.py +++ b/framework/sentry/__init__.py @@ -35,11 +35,16 @@ def log_exception(): }) -def log_message(message, extra={}): +def log_message(message, extra_data={}): if not enabled: logger.warning( 'Sentry called to log message, but is not active: %s' % message ) return None + extra = { + 'session': get_session_data(), + } + + if extra_data: extra.update(extra_data) return sentry.captureMessage(message, extra=extra) From 81c4af80ba7327b99dda66fd87039aa24c6af2f8 Mon Sep 17 00:00:00 2001 From: Fabrice Mizero Date: Wed, 7 Jun 2017 14:07:33 -0400 Subject: [PATCH 060/163] Fix jshint errors --- website/static/js/pages/project-dashboard-page.js | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/website/static/js/pages/project-dashboard-page.js b/website/static/js/pages/project-dashboard-page.js index b429205ba20..8eceb12abd4 100644 --- a/website/static/js/pages/project-dashboard-page.js +++ b/website/static/js/pages/project-dashboard-page.js @@ -201,13 +201,17 @@ $(document).ready(function () { var filebrowser = new Fangorn(fangornOpts); var newComponentElem = document.getElementById('newComponent'); if (window.contextVars.node.isPublic) { - m.mount(document.getElementById('shareButtonsPopover'), - m.component(SocialShare.ShareButtonsPopover, - {title: window.contextVars.node.title, url: window.location.href})); + m.mount( + document.getElementById('shareButtonsPopover'), + m.component( + SocialShare.ShareButtonsPopover, + {title: window.contextVars.node.title, url: window.location.href} + ) + ); } if (newComponentElem) { m.mount(newComponentElem, AddComponentButton); - }; + } m.endComputation(); }); From 3e17c60999391d5e47c45872118b1e715a53c98f Mon Sep 17 00:00:00 2001 From: Fabrice Mizero Date: Wed, 7 Jun 2017 14:34:41 -0400 Subject: [PATCH 061/163] Remove mutable default argument --- framework/sentry/__init__.py | 7 ++++--- website/views.py | 2 +- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/framework/sentry/__init__.py b/framework/sentry/__init__.py index 9abcce701e0..dba83c5fc0f 100644 --- a/framework/sentry/__init__.py +++ b/framework/sentry/__init__.py @@ -35,7 +35,7 @@ def log_exception(): }) -def log_message(message, extra_data={}): +def log_message(message, extra_data=None): if not enabled: logger.warning( 'Sentry called to log message, but is not active: %s' % message @@ -44,7 +44,8 @@ def log_message(message, extra_data={}): extra = { 'session': get_session_data(), } - - if extra_data: extra.update(extra_data) + if extra_data is None: + extra_data = {} + extra.update(extra_data) return sentry.captureMessage(message, extra=extra) diff --git a/website/views.py b/website/views.py index 01e9969de59..8e8c36ea02c 100644 --- a/website/views.py +++ b/website/views.py @@ -246,7 +246,7 @@ def resolve_guid(guid, suffix=None): # expected. if not hasattr(guid_object.referent, 'deep_url'): sentry.log_message( - 'Guid resolved to an object with no deep_url', dict(guid = guid) + 'Guid resolved to an object with no deep_url', {'guid' : guid} ) raise HTTPError(http.NOT_FOUND) referent = guid_object.referent From ff938916572c595265a2888c501ba96e5ca310e5 Mon Sep 17 00:00:00 2001 From: Rheisen Dennis Date: Wed, 7 Jun 2017 16:06:24 -0400 Subject: [PATCH 062/163] replace " with ', restructure imports, remove unused import --- .../views/test_preprint_provider_detail.py | 1 - .../preprints/views/test_preprint_detail.py | 52 +++++++++---------- 2 files changed, 26 insertions(+), 27 deletions(-) diff --git a/api_tests/preprint_providers/views/test_preprint_provider_detail.py b/api_tests/preprint_providers/views/test_preprint_provider_detail.py index 7222d34dde5..f978c5e87f3 100644 --- a/api_tests/preprint_providers/views/test_preprint_provider_detail.py +++ b/api_tests/preprint_providers/views/test_preprint_provider_detail.py @@ -1,7 +1,6 @@ import pytest from api.base.settings.defaults import API_BASE -from tests.base import ApiTestCase from osf_tests.factories import PreprintProviderFactory @pytest.mark.django_db diff --git a/api_tests/preprints/views/test_preprint_detail.py b/api_tests/preprints/views/test_preprint_detail.py index f2c2120ba77..513d82ecb2b 100644 --- a/api_tests/preprints/views/test_preprint_detail.py +++ b/api_tests/preprints/views/test_preprint_detail.py @@ -1,16 +1,12 @@ import functools import mock -import pytest from modularodm import Q +import pytest from api.base.settings.defaults import API_BASE from api_tests import utils as test_utils from framework.auth.core import Auth from osf.models import PreprintService, NodeLicense -from website.project.licenses import ensure_licenses -from website.project.signals import contributor_added -from website.identifiers.utils import build_ezid_metadata -from tests.base import ApiTestCase, fake, capture_signals from osf_tests.factories import ( PreprintFactory, AuthUserFactory, @@ -18,15 +14,20 @@ SubjectFactory, PreprintProviderFactory ) +from rest_framework import exceptions +from tests.base import fake, capture_signals +from website.project.licenses import ensure_licenses +from website.project.signals import contributor_added +from website.identifiers.utils import build_ezid_metadata ensure_licenses = functools.partial(ensure_licenses, warn=False) def build_preprint_update_payload(node_id, attributes=None, relationships=None): payload = { - "data": { - "id": node_id, - "attributes": attributes, - "relationships": relationships + 'data': { + 'id': node_id, + 'attributes': attributes, + 'relationships': relationships } } return payload @@ -142,7 +143,7 @@ def test_update_preprint_permission_denied(self, app, preprint, url): def test_update_subjects(self, app, user, preprint, subject, url): assert not preprint.subjects.filter(_id=subject._id).exists() - update_subjects_payload = build_preprint_update_payload(preprint._id, attributes={"subjects": [[subject._id]]}) + update_subjects_payload = build_preprint_update_payload(preprint._id, attributes={'subjects': [[subject._id]]}) res = app.patch_json_api(url, update_subjects_payload, auth=user.auth) assert res.status_code == 200 @@ -152,7 +153,7 @@ def test_update_subjects(self, app, user, preprint, subject, url): def test_update_invalid_subjects(self, app, user, preprint, url): subjects = preprint.subjects - update_subjects_payload = build_preprint_update_payload(preprint._id, attributes={"subjects": [['wwe']]}) + update_subjects_payload = build_preprint_update_payload(preprint._id, attributes={'subjects': [['wwe']]}) res = app.patch_json_api(url, update_subjects_payload, auth=user.auth, expect_errors=True) assert res.status_code == 400 @@ -163,10 +164,10 @@ def test_update_invalid_subjects(self, app, user, preprint, url): def test_update_primary_file(self, app, user, preprint, url): new_file = test_utils.create_test_file(preprint.node, user, filename='shook_that_mans_hand.pdf') relationships = { - "primary_file": { - "data": { - "type": "file", - "id": new_file._id + 'primary_file': { + 'data': { + 'type': 'file', + 'id': new_file._id } } } @@ -179,7 +180,6 @@ def test_update_primary_file(self, app, user, preprint, url): preprint.node.reload() assert preprint.primary_file == new_file - # check logs log = preprint.node.logs.latest() assert log.action == 'preprint_file_updated' assert log.params.get('preprint') == preprint._id @@ -189,10 +189,10 @@ def test_new_primary_not_in_node(self, app, user, preprint, url): file_for_project = test_utils.create_test_file(project, user, filename='six_pack_novak.pdf') relationships = { - "primary_file": { - "data": { - "type": "file", - "id": file_for_project._id + 'primary_file': { + 'data': { + 'type': 'file', + 'id': file_for_project._id } } } @@ -208,7 +208,7 @@ def test_new_primary_not_in_node(self, app, user, preprint, url): def test_update_article_doi(self, app, user, preprint, url): new_doi = '10.1234/ASDFASDF' assert preprint.article_doi != new_doi - update_subjects_payload = build_preprint_update_payload(preprint._id, attributes={"doi": new_doi}) + update_subjects_payload = build_preprint_update_payload(preprint._id, attributes={'doi': new_doi}) res = app.patch_json_api(url, update_subjects_payload, auth=user.auth) assert res.status_code == 200 @@ -275,7 +275,7 @@ def test_contribs_cannot_set_subjects(self, app, user, preprint, subject, url): preprint.node.add_contributor(write_contrib, permissions=['read', 'write'], auth=Auth(user), save=True) assert not preprint.subjects.filter(_id=subject._id).exists() - update_subjects_payload = build_preprint_update_payload(preprint._id, attributes={"subjects": [[subject._id]]}) + update_subjects_payload = build_preprint_update_payload(preprint._id, attributes={'subjects': [[subject._id]]}) res = app.patch_json_api(url, update_subjects_payload, auth=write_contrib.auth, expect_errors=True) assert res.status_code == 403 @@ -287,7 +287,7 @@ def test_contribs_cannot_set_subjects(self, app, user, preprint, subject, url): assert not preprint.subjects.filter(_id=subject._id).exists() - update_subjects_payload = build_preprint_update_payload(preprint._id, attributes={"subjects": [[subject._id]]}) + update_subjects_payload = build_preprint_update_payload(preprint._id, attributes={'subjects': [[subject._id]]}) res = app.patch_json_api(url, update_subjects_payload, auth=non_contrib.auth, expect_errors=True) assert res.status_code == 403 @@ -491,7 +491,7 @@ def test_cannot_update_license(self, rw_contributor, read_contributor, non_contr res = make_request(url, data, auth=read_contributor.auth, expect_errors=True) assert res.status_code == 403 - assert res.json['errors'][0]['detail'] == 'You do not have permission to perform this action.' + assert res.json['errors'][0]['detail'] == exceptions.PermissionDenied.default_detail # test_non_contributor_cannot_update_license data = make_payload( @@ -501,7 +501,7 @@ def test_cannot_update_license(self, rw_contributor, read_contributor, non_contr res = make_request(url, data, auth=non_contributor.auth, expect_errors=True) assert res.status_code == 403 - assert res.json['errors'][0]['detail'] == 'You do not have permission to perform this action.' + assert res.json['errors'][0]['detail'] == exceptions.PermissionDenied.default_detail # test_unauthenticated_user_cannot_update_license data = make_payload( @@ -511,7 +511,7 @@ def test_cannot_update_license(self, rw_contributor, read_contributor, non_contr res = make_request(url, data, expect_errors=True) assert res.status_code == 401 - assert res.json['errors'][0]['detail'] == 'Authentication credentials were not provided.' + assert res.json['errors'][0]['detail'] == exceptions.NotAuthenticated.default_detail def test_update_error(self, admin_contributor, preprint, preprint_provider, mit_license, no_license, url, make_payload, make_request): From 79de60ba536b2baa0fb6cdf7c854d780d91ecb88 Mon Sep 17 00:00:00 2001 From: Fabrice Mizero Date: Wed, 7 Jun 2017 16:21:36 -0400 Subject: [PATCH 063/163] Fix flake error --- website/views.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/website/views.py b/website/views.py index 8e8c36ea02c..03bc13af7b5 100644 --- a/website/views.py +++ b/website/views.py @@ -246,7 +246,7 @@ def resolve_guid(guid, suffix=None): # expected. if not hasattr(guid_object.referent, 'deep_url'): sentry.log_message( - 'Guid resolved to an object with no deep_url', {'guid' : guid} + 'Guid resolved to an object with no deep_url', dict(guid=guid) ) raise HTTPError(http.NOT_FOUND) referent = guid_object.referent From ee8175ebeca7ce2da683a5d4c80f2c08b5b8432c Mon Sep 17 00:00:00 2001 From: Alex Schiller Date: Wed, 7 Jun 2017 16:52:51 -0400 Subject: [PATCH 064/163] Fix Mock Stopper --- admin_tests/nodes/test_views.py | 1 + 1 file changed, 1 insertion(+) diff --git a/admin_tests/nodes/test_views.py b/admin_tests/nodes/test_views.py index 9118d7211d2..6d50082db2e 100644 --- a/admin_tests/nodes/test_views.py +++ b/admin_tests/nodes/test_views.py @@ -247,6 +247,7 @@ def tearDown(self): self.patcher_share_token.stop() self.patcher_mock_reindex_node.stop() self.patcher_mock_reindex_registration.stop() + self.patcher_mock_reindex_elastic.stop() def test_reindex_node_share(self): count = AdminLogEntry.objects.count() From d8803af5c71d1b3e2df7f71e89fb391a5a64adf6 Mon Sep 17 00:00:00 2001 From: Fabrice Mizero Date: Thu, 8 Jun 2017 00:14:11 -0400 Subject: [PATCH 065/163] Show licences acceptable as formatted list --- admin/preprint_providers/views.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/admin/preprint_providers/views.py b/admin/preprint_providers/views.py index b3f33ee04a3..3795c50acf1 100644 --- a/admin/preprint_providers/views.py +++ b/admin/preprint_providers/views.py @@ -86,7 +86,12 @@ def get_context_data(self, *args, **kwargs): preprint_provider_attributes = model_to_dict(preprint_provider) kwargs.setdefault('page_number', self.request.GET.get('page', '1')) - preprint_provider_attributes['licenses_acceptable'] = preprint_provider.licenses_acceptable.values_list('name', flat=True) + licenses_acceptable = list(preprint_provider.licenses_acceptable.values_list('name', flat=True)) + licenses_html = '
      ' + for license in licenses_acceptable: + licenses_html += '
    • {}
    • '.format(license) + licenses_html += '
    ' + preprint_provider_attributes['licenses_acceptable'] = licenses_html subject_html = '
      ' for parent in preprint_provider.top_level_subjects: From 461284efb07bb2c2dd19e592c8ffccdd812f312d Mon Sep 17 00:00:00 2001 From: Fabrice Mizero Date: Thu, 8 Jun 2017 12:03:58 -0400 Subject: [PATCH 066/163] Enforce pre populating user emails --- admin/users/views.py | 21 +++++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) diff --git a/admin/users/views.py b/admin/users/views.py index 13449ac3b4b..7b841a367d4 100644 --- a/admin/users/views.py +++ b/admin/users/views.py @@ -514,17 +514,26 @@ class ResetPasswordView(PermissionRequiredMixin, FormView): permission_required = 'osf.change_osfuser' raise_exception = True - def get_context_data(self, **kwargs): - user = OSFUser.load(self.kwargs.get('guid')) - try: - self.initial.setdefault('emails', [(r, r) for r in user.emails.values_list('address', flat=True)]) - except AttributeError: + def dispatch(self, request, *args, **kwargs): + self.user = OSFUser.load(self.kwargs.get('guid')) + if self.user is None: raise Http404( '{} with id "{}" not found.'.format( self.context_object_name.title(), self.kwargs.get('guid') )) - kwargs.setdefault('guid', user._id) + return super(ResetPasswordView, self).dispatch(request, *args, **kwargs) + + def get_initial(self): + user = self.user + self.initial = { + 'emails': [(r, r) for r in user.emails.values_list('address', flat=True)], + } + return super(ResetPasswordView, self).get_initial() + + def get_context_data(self, **kwargs): + kwargs.setdefault('guid', self.user._id) + kwargs.setdefault('emails', self.user.emails) return super(ResetPasswordView, self).get_context_data(**kwargs) def form_valid(self, form): From 4cf26890df375b21beff826fb415f9898f3378d6 Mon Sep 17 00:00:00 2001 From: Rheisen Dennis Date: Thu, 8 Jun 2017 14:01:19 -0400 Subject: [PATCH 067/163] cleanup tests, improve imports, add rest_framework/exception errors --- .../nodes/serializers/test_serializers.py | 67 +++++++++--------- api_tests/nodes/views/test_node_citations.py | 38 +++++----- api_tests/nodes/views/test_node_embeds.py | 69 ++++++++++--------- api_tests/nodes/views/test_node_exceptions.py | 39 ++++++----- .../nodes/views/test_node_links_detail.py | 22 +++--- api_tests/nodes/views/test_node_links_list.py | 39 ++++------- api_tests/nodes/views/test_node_logs.py | 40 +++++------ .../views/test_node_registrations_list.py | 7 +- .../nodes/views/test_node_sparse_fieldsets.py | 15 ++-- .../views/test_node_view_only_links_detail.py | 56 +++++++-------- .../views/test_node_view_only_links_list.py | 47 ++++++------- .../views/test_view_only_query_parameter.py | 65 ++++++++--------- .../views/test_view_only_link_nodes.py | 18 +++-- tests/utils.py | 15 ++-- 14 files changed, 257 insertions(+), 280 deletions(-) diff --git a/api_tests/nodes/serializers/test_serializers.py b/api_tests/nodes/serializers/test_serializers.py index 5e558feccb2..2fb820efed7 100644 --- a/api_tests/nodes/serializers/test_serializers.py +++ b/api_tests/nodes/serializers/test_serializers.py @@ -1,18 +1,24 @@ +from dateutil.parser import parse as parse_date import pytest from urlparse import urlparse -from dateutil.parser import parse as parse_date -from tests.base import DbTestCase, assert_datetime_equal -from tests.utils import make_drf_request_with_version -from osf_tests.factories import UserFactory, NodeFactory, RegistrationFactory, ProjectFactory -from framework.auth import Auth +from api.base.settings.defaults import API_BASE from api.nodes.serializers import NodeSerializer from api.registrations.serializers import RegistrationSerializer -from api.base.settings.defaults import API_BASE +from framework.auth import Auth +from osf_tests.factories import ( + AuthUserFactory, + UserFactory, + NodeFactory, + RegistrationFactory, + ProjectFactory +) +from tests.base import DbTestCase, assert_datetime_equal +from tests.utils import make_drf_request_with_version @pytest.fixture() def user(): - return UserFactory() + return AuthUserFactory() @pytest.mark.django_db class TestNodeSerializer: @@ -47,17 +53,15 @@ def test_node_serializer(self, user): assert 'files' in relationships assert 'parent' in relationships assert 'affiliated_institutions' in relationships - parent_link = relationships['parent']['links']['related']['href'] - assert ( - urlparse(parent_link).path == - '/{}nodes/{}/'.format(API_BASE, parent._id)) assert 'registrations' in relationships # Not a fork, so forked_from is removed entirely assert 'forked_from' not in relationships + parent_link = relationships['parent']['links']['related']['href'] + assert urlparse(parent_link).path == '/{}nodes/{}/'.format(API_BASE, parent._id) # test_fork_serialization node = NodeFactory(creator=user) - fork = node.fork_node(auth=Auth(user=node.creator)) + fork = node.fork_node(auth=Auth(user)) req = make_drf_request_with_version(version='2.0') result = NodeSerializer(fork, context={'request': req}).data data = result['data'] @@ -65,13 +69,11 @@ def test_node_serializer(self, user): # Relationships relationships = data['relationships'] forked_from = relationships['forked_from']['links']['related']['href'] - assert ( - urlparse(forked_from).path == - '/{}nodes/{}/'.format(API_BASE, node._id)) + assert urlparse(forked_from).path == '/{}nodes/{}/'.format(API_BASE, node._id) # test_template_serialization node = NodeFactory(creator=user) - fork = node.use_as_template(auth=Auth(user=node.creator)) + fork = node.use_as_template(auth=Auth(user)) req = make_drf_request_with_version(version='2.0') result = NodeSerializer(fork, context={'request': req}).data data = result['data'] @@ -79,20 +81,18 @@ def test_node_serializer(self, user): # Relationships relationships = data['relationships'] templated_from = relationships['template_node']['links']['related']['href'] - assert ( - urlparse(templated_from).path == - '/{}nodes/{}/'.format(API_BASE, node._id)) + assert urlparse(templated_from).path == '/{}nodes/{}/'.format(API_BASE, node._id) @pytest.mark.django_db class TestNodeRegistrationSerializer: def test_serialization(self): user = UserFactory() - req = make_drf_request_with_version(version='2.2') - reg = RegistrationFactory(creator=user) - result = RegistrationSerializer(reg, context={'request': req}).data + versioned_request = make_drf_request_with_version(version='2.2') + registration = RegistrationFactory(creator=user) + result = RegistrationSerializer(registration, context={'request': versioned_request}).data data = result['data'] - assert data['id'] == reg._id + assert data['id'] == registration._id assert data['type'] == 'registrations' should_not_relate_to_registrations = [ 'registered_from', @@ -104,27 +104,22 @@ def test_serialization(self): attributes = data['attributes'] assert_datetime_equal( parse_date(attributes['date_registered']), - reg.registered_date + registration.registered_date ) - assert attributes['withdrawn'] == reg.is_retracted + assert attributes['withdrawn'] == registration.is_retracted # Relationships relationships = data['relationships'] - relationship_urls = {} - for relationship in relationships: - relationship_urls[relationship]=relationships[relationship]['links']['related']['href'] + relationship_urls = {k: v['links']['related']['href'] for k, v in relationships.items()} assert 'registered_by' in relationships registered_by = relationships['registered_by']['links']['related']['href'] - assert ( - urlparse(registered_by).path == - '/{}users/{}/'.format(API_BASE, user._id)) + assert urlparse(registered_by).path == '/{}users/{}/'.format(API_BASE, user._id) assert 'registered_from' in relationships registered_from = relationships['registered_from']['links']['related']['href'] - assert ( - urlparse(registered_from).path == - '/{}nodes/{}/'.format(API_BASE, reg.registered_from._id)) + assert urlparse(registered_from).path == '/{}nodes/{}/'.format(API_BASE, registration.registered_from._id) + api_registrations_url = '/{}registrations/'.format(API_BASE) for relationship in relationship_urls: if relationship in should_not_relate_to_registrations: - assert '/{}registrations/'.format(API_BASE) not in relationship_urls[relationship] + assert api_registrations_url not in relationship_urls[relationship] else: - assert '/{}registrations/'.format(API_BASE) in relationship_urls[relationship], 'For key {}'.format(relationship) + assert api_registrations_url in relationship_urls[relationship], 'For key {}'.format(relationship) diff --git a/api_tests/nodes/views/test_node_citations.py b/api_tests/nodes/views/test_node_citations.py index 8c120f4950d..738ae0ae0b7 100644 --- a/api_tests/nodes/views/test_node_citations.py +++ b/api_tests/nodes/views/test_node_citations.py @@ -1,8 +1,8 @@ import pytest -from framework.auth.core import Auth from api.base.settings.defaults import API_BASE -from tests.base import ApiTestCase +from framework.auth.core import Auth +from rest_framework import exceptions from tests.factories import ( ProjectFactory, AuthUserFactory, @@ -10,18 +10,18 @@ @pytest.fixture() def admin_contributor(): - return AuthUserFactory() + return AuthUserFactory() @pytest.fixture() -def rw_contributor(): +def write_contrib(): return AuthUserFactory() @pytest.fixture() -def read_contributor(): +def read_contrib(): return AuthUserFactory() @pytest.fixture() -def non_contributor(): +def non_contrib(): return AuthUserFactory() @pytest.fixture() @@ -29,39 +29,39 @@ def public_project(admin_contributor): return ProjectFactory(creator=admin_contributor, is_public=True) @pytest.fixture() -def private_project(admin_contributor, rw_contributor, read_contributor): +def private_project(admin_contributor, write_contrib, read_contrib): private_project = ProjectFactory(creator=admin_contributor) - private_project.add_contributor(rw_contributor, auth=Auth(admin_contributor)) - private_project.add_contributor(read_contributor, permissions=['read'], auth=Auth(admin_contributor)) + private_project.add_contributor(write_contrib, permissions=['read','write'], auth=Auth(admin_contributor)) + private_project.add_contributor(read_contrib, permissions=['read'], auth=Auth(admin_contributor)) private_project.save() return private_project @pytest.mark.django_db class NodeCitationsMixin: - def test_node_citations(self, app, admin_contributor, rw_contributor, read_contributor, non_contributor, private_url, public_url): + def test_node_citations(self, app, admin_contributor, write_contrib, read_contrib, non_contrib, private_url, public_url): - # test_admin_can_view_private_project_citations + # test_admin_can_view_private_project_citations res = app.get(private_url, auth=admin_contributor.auth) assert res.status_code == 200 - # test_rw_contributor_can_view_private_project_citations - res = app.get(private_url, auth=rw_contributor.auth) + # test_write_contrib_can_view_private_project_citations + res = app.get(private_url, auth=write_contrib.auth) assert res.status_code == 200 - # test_read_contributor_can_view_private_project_citations - res = app.get(private_url, auth=read_contributor.auth) + # test_read_contrib_can_view_private_project_citations + res = app.get(private_url, auth=read_contrib.auth) assert res.status_code == 200 - # test_non_contributor_cannot_view_private_project_citations - res = app.get(private_url, auth=non_contributor.auth, expect_errors=True) + # test_non_contrib_cannot_view_private_project_citations + res = app.get(private_url, auth=non_contrib.auth, expect_errors=True) assert res.status_code == 403 - assert res.json['errors'][0]['detail'] == 'You do not have permission to perform this action.' + assert res.json['errors'][0]['detail'] == exceptions.PermissionDenied.default_detail # test_unauthenticated_cannot_view_private_project_citations res = app.get(private_url, expect_errors=True) assert res.status_code == 401 - assert res.json['errors'][0]['detail'] == 'Authentication credentials were not provided.' + assert res.json['errors'][0]['detail'] == exceptions.NotAuthenticated.default_detail # test_unauthenticated_can_view_public_project_citations res = app.get(public_url) diff --git a/api_tests/nodes/views/test_node_embeds.py b/api_tests/nodes/views/test_node_embeds.py index 265cda57d70..533c7dd4b24 100644 --- a/api_tests/nodes/views/test_node_embeds.py +++ b/api_tests/nodes/views/test_node_embeds.py @@ -1,13 +1,13 @@ -import pytest import functools +import pytest -from framework.auth.core import Auth from api.base.settings.defaults import API_BASE -from tests.base import ApiTestCase +from framework.auth.core import Auth from osf_tests.factories import ( ProjectFactory, AuthUserFactory ) +from rest_framework import exceptions @pytest.fixture() def user(): @@ -17,16 +17,16 @@ def user(): class TestNodeEmbeds: @pytest.fixture() - def contrib_one(self): + def write_contrib_one(self): return AuthUserFactory() @pytest.fixture() - def contrib_two(self): + def write_contrib_two(self): return AuthUserFactory() @pytest.fixture() - def contribs(self, contrib_one, contrib_two): - return [contrib_one, contrib_two] + def write_contribs(self, write_contrib_one, write_contrib_two): + return [write_contrib_one, write_contrib_two] @pytest.fixture() def auth(self, user): @@ -37,17 +37,17 @@ def make_public_node(self, user): return functools.partial(ProjectFactory, is_public=False, creator=user) @pytest.fixture() - def root_node(self, auth, contrib_one, contrib_two, make_public_node): + def root_node(self, auth, write_contrib_one, write_contrib_two, make_public_node): root_node = make_public_node() - root_node.add_contributor(contrib_one, ['read', 'write'], auth=auth, save=True) - root_node.add_contributor(contrib_two, ['read', 'write'], auth=auth, save=True) + root_node.add_contributor(write_contrib_one, ['read', 'write'], auth=auth, save=True) + root_node.add_contributor(write_contrib_two, ['read', 'write'], auth=auth, save=True) return root_node @pytest.fixture() - def child_one(self, auth, contrib_one, contrib_two, make_public_node, root_node): + def child_one(self, auth, write_contrib_one, write_contrib_two, make_public_node, root_node): child_one = make_public_node(parent=root_node) - child_one.add_contributor(contrib_one, ['read', 'write'], auth=auth, save=True) - child_one.add_contributor(contrib_two, ['read', 'write'], auth=auth, save=True) + child_one.add_contributor(write_contrib_one, ['read', 'write'], auth=auth, save=True) + child_one.add_contributor(write_contrib_two, ['read', 'write'], auth=auth, save=True) return child_one @pytest.fixture() @@ -55,75 +55,76 @@ def child_two(self, make_public_node, root_node): return make_public_node(parent=root_node) @pytest.fixture() - def subchild(self, child_two, contrib_one): - return ProjectFactory(parent=child_two, creator=contrib_one) + def subchild(self, child_two, write_contrib_one): + return ProjectFactory(parent=child_two, creator=write_contrib_one) - def test_node_embeds(self, app, user, contrib_one, contribs, subchild, root_node, child_one, child_two): + def test_node_embeds(self, app, user, write_contrib_one, write_contribs, subchild, root_node, child_one, child_two): # test_embed_children - url = '/{0}nodes/{1}/?embed=children'.format(API_BASE, root_node._id) + url = '/{}nodes/{}/?embed=children'.format(API_BASE, root_node._id) res = app.get(url, auth=user.auth) embeds = res.json['data']['embeds'] ids = [child_one._id, child_two._id] - for child in embeds['children']['data']: - assert child['id'] in ids + assert len(embeds['children']['data']) == len(ids) + children = [child._id for child in res.json['data']['embeds']['children']['data']] + assert set(child_one._id, child_two._id) == set(children) # test_embed_parent - url = '/{0}nodes/{1}/?embed=parent'.format(API_BASE, child_one._id) + url = '/{}nodes/{}/?embed=parent'.format(API_BASE, child_one._id) res = app.get(url, auth=user.auth) embeds = res.json['data']['embeds'] assert embeds['parent']['data']['id'] == root_node._id # test_embed_no_parent - url = '/{0}nodes/{1}/?embed=parent'.format(API_BASE, root_node._id) + url = '/{}nodes/{}/?embed=parent'.format(API_BASE, root_node._id) res = app.get(url, auth=user.auth) data = res.json['data'] assert 'embeds' not in data # test_embed_contributors - url = '/{0}nodes/{1}/?embed=contributors'.format(API_BASE, child_one._id) + url = '/{}nodes/{}/?embed=contributors'.format(API_BASE, child_one._id) res = app.get(url, auth=user.auth) embeds = res.json['data']['embeds'] - ids = [c._id for c in contribs] + [user._id] - ids = ['{}-{}'.format(child_one._id, id_) for id_ in ids] - for contrib in embeds['contributors']['data']: - assert contrib['id'] in ids + all_contribs = write_contribs + [user] + formatted_ids = ['{}-{}'.format(child_one._id, contrib._id) for contrib in all_contribs] + embed_contrib_ids = [contrib['id'] for contrib in embeds['contributors']['data']] + assert set(formatted_ids) == set(embed_contrib_ids) # test_embed_children_filters_unauthorized - url = '/{0}nodes/{1}/?embed=children'.format(API_BASE, root_node._id) + url = '/{}nodes/{}/?embed=children'.format(API_BASE, root_node._id) - res = app.get(url, auth=contrib_one.auth) + res = app.get(url, auth=write_contrib_one.auth) embeds = res.json['data']['embeds'] ids = [c['id'] for c in embeds['children']['data']] assert child_two._id not in ids assert child_one._id in ids # test_embed_parent_unauthorized - url = '/{0}nodes/{1}/?embed=parent'.format(API_BASE, subchild._id) + url = '/{}nodes/{}/?embed=parent'.format(API_BASE, subchild._id) - res = app.get(url, auth=contrib_one.auth) + res = app.get(url, auth=write_contrib_one.auth) assert 'errors' in res.json['data']['embeds']['parent'] - assert res.json['data']['embeds']['parent']['errors'][0]['detail'] == 'You do not have permission to perform this action.' + assert res.json['data']['embeds']['parent']['errors'][0]['detail'] == exceptions.PermissionDenied.default_detail # test_embed_attributes_not_relationships url = '/{}nodes/{}/?embed=title'.format(API_BASE, root_node._id) - res = app.get(url, auth=contrib_one.auth, expect_errors=True) + res = app.get(url, auth=write_contrib_one.auth, expect_errors=True) assert res.status_code == 400 assert res.json['errors'][0]['detail'] == 'The following fields are not embeddable: title' # test_embed_contributors_pagination url = '/{}nodes/{}/?embed=contributors'.format(API_BASE, root_node._id) - res = app.get(url, auth=contrib_one.auth) + res = app.get(url, auth=write_contrib_one.auth) assert res.status_code == 200 assert res.json['data']['embeds']['contributors']['links']['meta']['total_bibliographic'] == 3 # test_embed_contributors_updated_pagination url = '/{}nodes/{}/?version=2.1&embed=contributors'.format(API_BASE, root_node._id) - res = app.get(url, auth=contrib_one.auth) + res = app.get(url, auth=write_contrib_one.auth) assert res.status_code == 200 assert res.json['data']['embeds']['contributors']['meta']['total_bibliographic'] == 3 diff --git a/api_tests/nodes/views/test_node_exceptions.py b/api_tests/nodes/views/test_node_exceptions.py index 6010892db19..ae67c390447 100644 --- a/api_tests/nodes/views/test_node_exceptions.py +++ b/api_tests/nodes/views/test_node_exceptions.py @@ -1,11 +1,11 @@ import pytest from api.base.settings.defaults import API_BASE -from tests.base import ApiTestCase from osf_tests.factories import ( ProjectFactory, AuthUserFactory ) +from rest_framework import exceptions @pytest.fixture() def user(): @@ -44,47 +44,50 @@ def private_url(self, private_project): def test_exception_formatting(self, app, user, non_contrib, public_project, private_project, private_url, project_no_title): + error_required_field = 'This field is required.' + error_blank_field = 'This field may not be blank.' + # test_creates_project_with_no_title_formatting url = '/{}nodes/'.format(API_BASE) res = app.post_json_api(url, project_no_title, auth=user.auth, expect_errors=True) errors = res.json['errors'] - assert(isinstance(errors, list)) + assert isinstance(errors, list) assert res.json['errors'][0]['source'] == {'pointer': '/data/attributes/title'} - assert res.json['errors'][0]['detail'] == 'This field is required.' + assert res.json['errors'][0]['detail'] == error_required_field # test_node_does_not_exist_formatting url = '/{}nodes/{}/'.format(API_BASE, '12345') res = app.get(url, auth=user.auth, expect_errors=True) errors = res.json['errors'] - assert(isinstance(errors, list)) - assert errors[0] == {'detail': 'Not found.'} + assert isinstance(errors, list) + assert errors[0] == {'detail': exceptions.NotFound.default_detail} # test_forbidden_formatting res = app.get(private_url, auth=non_contrib.auth, expect_errors=True) errors = res.json['errors'] - assert(isinstance(errors, list)) - assert errors[0] == {'detail': 'You do not have permission to perform this action.'} + assert isinstance(errors, list) + assert errors[0] == {'detail': exceptions.PermissionDenied.default_detail} # test_not_authorized_formatting res = app.get(private_url, expect_errors=True) errors = res.json['errors'] - assert(isinstance(errors, list)) - assert errors[0] == {'detail': 'Authentication credentials were not provided.'} + assert isinstance(errors, list) + assert errors[0] == {'detail': exceptions.NotAuthenticated.default_detail} # test_update_project_with_no_title_or_category_formatting res = app.put_json_api(private_url, {'data': {'type': 'nodes', 'id': private_project._id, 'attributes': {'description': 'New description'}}}, auth=user.auth, expect_errors=True) errors = res.json['errors'] - assert(isinstance(errors, list)) + assert isinstance(errors, list) assert len(errors) == 2 errors = res.json['errors'] assert errors[0]['source'] == {'pointer': '/data/attributes/category'} assert errors[1]['source'] == {'pointer': '/data/attributes/title'} - assert errors[0]['detail'] == 'This field is required.' - assert errors[1]['detail'] == 'This field is required.' + assert errors[0]['detail'] == error_required_field + assert errors[1]['detail'] == error_required_field # test_create_node_link_no_target_formatting - url = private_url + 'node_links/' + url = '{}node_links/'.format(private_url) res = app.post_json_api(url, { 'data': { 'type': 'node_links', @@ -99,13 +102,13 @@ def test_exception_formatting(self, app, user, non_contrib, public_project, priv } }, auth=user.auth, expect_errors=True) errors = res.json['errors'] - assert(isinstance(errors, list)) + assert isinstance(errors, list) assert res.status_code == 400 assert res.json['errors'][0]['source'] == {'pointer': '/data/id'} - assert res.json['errors'][0]['detail'] == 'This field may not be blank.' + assert res.json['errors'][0]['detail'] == error_blank_field # test_node_link_already_exists - url = private_url + 'node_links/' + url = '{}node_links/'.format(private_url) res = app.post_json_api(url, { 'data': { 'type': 'node_links', @@ -133,6 +136,6 @@ def test_exception_formatting(self, app, user, non_contrib, public_project, priv } }}, auth=user.auth, expect_errors=True) errors = res.json['errors'] - assert(isinstance(errors, list)) + assert isinstance(errors, list) assert res.status_code == 400 - assert(public_project._id in res.json['errors'][0]['detail']) + assert public_project._id in res.json['errors'][0]['detail'] diff --git a/api_tests/nodes/views/test_node_links_detail.py b/api_tests/nodes/views/test_node_links_detail.py index dc10d41dbbf..739c561081a 100644 --- a/api_tests/nodes/views/test_node_links_detail.py +++ b/api_tests/nodes/views/test_node_links_detail.py @@ -1,16 +1,16 @@ import pytest from urlparse import urlparse +from api.base.settings.defaults import API_BASE from framework.auth.core import Auth from osf.models import NodeLog -from api.base.settings.defaults import API_BASE -from tests.base import ApiTestCase -from tests.utils import assert_latest_log from osf_tests.factories import ( ProjectFactory, RegistrationFactory, AuthUserFactory, ) +from rest_framework import exceptions +from tests.utils import assert_latest_log node_url_for = lambda n_id: '/{}nodes/{}/'.format(API_BASE, n_id) @@ -22,7 +22,7 @@ def user(): class TestNodeLinkDetail: @pytest.fixture() - def non_contributor(self): + def non_contrib(self): return AuthUserFactory() @pytest.fixture() @@ -57,7 +57,7 @@ def public_pointer(self, user, public_project, public_pointer_project): def public_url(self, public_project, public_pointer): return '/{}nodes/{}/node_links/{}/'.format(API_BASE, public_project._id, public_pointer._id) - def test_node_link_detail(self, app, user, non_contributor, private_pointer_project, public_pointer_project, public_url, private_url): + def test_node_link_detail(self, app, user, non_contrib, private_pointer_project, public_pointer_project, public_url, private_url): # test_returns_embedded_public_node_pointer_detail_logged_out res = app.get(public_url) @@ -80,7 +80,7 @@ def test_node_link_detail(self, app, user, non_contributor, private_pointer_proj assert res.status_code == 200 target_node = res.json['data']['embeds']['target_node'] assert 'errors' in target_node - assert target_node['errors'][0]['detail'] == 'You do not have permission to perform this action.' + assert target_node['errors'][0]['detail'] == exceptions.PermissionDenied.default_detail # test_returns_private_node_pointer_detail_logged_in_contributor res = app.get(private_url, auth=user.auth) @@ -90,12 +90,12 @@ def test_node_link_detail(self, app, user, non_contributor, private_pointer_proj embedded = res_json['embeds']['target_node']['data']['id'] assert embedded == private_pointer_project._id - # test_returns_private_node_pointer_detail_logged_in_non_contributor - res = app.get(private_url, auth=non_contributor.auth, expect_errors=True) + # test_returns_private_node_pointer_detail_logged_in_non_contrib + res = app.get(private_url, auth=non_contrib.auth, expect_errors=True) assert res.status_code == 200 target_node = res.json['data']['embeds']['target_node'] assert 'errors' in target_node - assert target_node['errors'][0]['detail'] == 'You do not have permission to perform this action.' + assert target_node['errors'][0]['detail'] == exceptions.PermissionDenied.default_detail # test_self_link_points_to_node_link_detail_url res = app.get(public_url, auth=user.auth) @@ -212,7 +212,7 @@ def test_deletes_private_node_pointer_logged_in_contributor(self, app, user, pri assert res.status_code == 204 assert len(private_project.nodes_pointer) == 0 - def test_deletes_private_node_pointer_logged_in_non_contributor(self, app, user_two, private_url): + def test_deletes_private_node_pointer_logged_in_non_contrib(self, app, user_two, private_url): res = app.delete(private_url, auth=user_two.auth, expect_errors=True) assert res.status_code == 403 assert 'detail' in res.json['errors'][0] @@ -249,4 +249,4 @@ def test_delete_link_that_is_not_linked_to_correct_node(self, app, user, public_ assert res.status_code == 404 errors = res.json['errors'] assert len(errors) == 1 - assert errors[0]['detail'] == 'Not found.' + assert errors[0]['detail'] == exceptions.NotFound.default_detail diff --git a/api_tests/nodes/views/test_node_links_list.py b/api_tests/nodes/views/test_node_links_list.py index 5f014962050..fbabe087f2d 100644 --- a/api_tests/nodes/views/test_node_links_list.py +++ b/api_tests/nodes/views/test_node_links_list.py @@ -1,16 +1,16 @@ import pytest from urlparse import urlparse +from api.base.settings.defaults import API_BASE from framework.auth.core import Auth from osf.models import NodeLog -from api.base.settings.defaults import API_BASE -from tests.base import ApiTestCase -from tests.utils import assert_latest_log from osf_tests.factories import ( ProjectFactory, RegistrationFactory, AuthUserFactory ) +from rest_framework import exceptions +from tests.utils import assert_latest_log node_url_for = lambda n_id: '/{}nodes/{}/'.format(API_BASE, n_id) @@ -187,7 +187,7 @@ def test_add_node_link(self, app, user, public_pointer_project, public_url): } res = app.post_json_api(public_url, data, auth=user.auth, expect_errors=True) assert res.status_code == 400 - assert res.json['errors'][0]['detail'] == 'Malformed request.' + assert res.json['errors'][0]['detail'] == exceptions.ParseError.default_detail # test_add_node_link_no_relationships data = { @@ -226,7 +226,7 @@ def test_add_node_link(self, app, user, public_pointer_project, public_url): } res = app.post_json_api(public_url, data, auth=user.auth, expect_errors=True) assert res.status_code == 400 - assert res.json['errors'][0]['detail'] == 'Malformed request.' + assert res.json['errors'][0]['detail'] == exceptions.ParseError.default_detail # test_add_node_links_no_data_in_relationships data = { @@ -315,7 +315,7 @@ def test_add_node_link(self, app, user, public_pointer_project, public_url): def test_create_node_link_invalid_data(self, app, user, public_url): res = app.post_json_api(public_url, 'Incorrect data', auth=user.auth, expect_errors=True) assert res.status_code == 400 - assert res.json['errors'][0]['detail'] == 'Malformed request.' + assert res.json['errors'][0]['detail'] == exceptions.ParseError.default_detail def test_creates_node_link_target_not_nested(self, app, user_two, private_pointer_project, public_url): payload = { @@ -633,8 +633,7 @@ def test_bulk_create_errors(self, app, user, user_two, public_project, user_two_ assert res.json['data'] == [] # test_bulk_creates_public_node_pointer_logged_in_non_contrib - res = app.post_json_api(public_url, public_payload, - auth=user_two.auth, expect_errors=True, bulk=True) + res = app.post_json_api(public_url, public_payload, auth=user_two.auth, expect_errors=True, bulk=True) assert res.status_code == 403 # test_bulk_creates_private_node_pointers_logged_out @@ -646,8 +645,7 @@ def test_bulk_create_errors(self, app, user, user_two, public_project, user_two_ assert res.json['data'] == [] # test_bulk_creates_private_node_pointers_logged_in_non_contributor - res = app.post_json_api(private_url, private_payload, - auth=user_two.auth, expect_errors=True, bulk=True) + res = app.post_json_api(private_url, private_payload, auth=user_two.auth, expect_errors=True, bulk=True) assert res.status_code == 403 assert 'detail' in res.json['errors'][0] @@ -663,16 +661,14 @@ def test_bulk_create_errors(self, app, user, user_two, public_project, user_two_ # test_bulk_creates_pointers_non_contributing_node_to_fake_node fake_payload = {'data': [{'type': 'node_links', 'relationships': {'nodes': {'data': {'id': 'rheis', 'type': 'nodes'}}}}]} - res = app.post_json_api(private_url, fake_payload, - auth=user_two.auth, expect_errors=True, bulk=True) + res = app.post_json_api(private_url, fake_payload, auth=user_two.auth, expect_errors=True, bulk=True) assert res.status_code == 403 assert 'detail' in res.json['errors'][0] # test_bulk_creates_pointers_contributing_node_to_fake_node fake_payload = {'data': [{'type': 'node_links', 'relationships': {'nodes': {'data': {'id': 'rheis', 'type': 'nodes'}}}}]} - res = app.post_json_api(private_url, fake_payload, - auth=user.auth, expect_errors=True, bulk=True) + res = app.post_json_api(private_url, fake_payload, auth=user.auth, expect_errors=True, bulk=True) assert res.status_code == 400 assert 'detail' in res.json['errors'][0] @@ -690,8 +686,7 @@ def test_bulk_create_errors(self, app, user, user_two, public_project, user_two_ # test_bulk_creates_node_pointer_to_itself_unauthorized point_to_itself_payload = {'data': [{'type': 'node_links', 'relationships': {'nodes': {'data': {'type': 'nodes', 'id': public_project._id}}}}]} - res = app.post_json_api(public_url, point_to_itself_payload, bulk=True, auth=user_two.auth, - expect_errors=True) + res = app.post_json_api(public_url, point_to_itself_payload, bulk=True, auth=user_two.auth, expect_errors=True) assert res.status_code == 403 assert 'detail' in res.json['errors'][0] @@ -861,15 +856,13 @@ def test_bulk_delete_errors(self, app, user, non_contrib, public_project, public assert res.status_code == 400 # test_bulk_delete_pointer_limits - res = app.delete_json_api(public_url, {'data': [public_payload['data'][0]] * 101}, - auth=user.auth, expect_errors=True, bulk=True) + res = app.delete_json_api(public_url, {'data': [public_payload['data'][0]] * 101}, auth=user.auth, expect_errors=True, bulk=True) assert res.status_code == 400 assert res.json['errors'][0]['detail'] == 'Bulk operation limit is 100, got 101.' assert res.json['errors'][0]['source']['pointer'] == '/data' # test_bulk_delete_dict_inside_data - res = app.delete_json_api(public_url, {'data': {'id': public_project._id, 'type': 'node_links'}}, - auth=user.auth, expect_errors=True, bulk=True) + res = app.delete_json_api(public_url, {'data': {'id': public_project._id, 'type': 'node_links'}}, auth=user.auth, expect_errors=True, bulk=True) assert res.status_code == 400 assert res.json['errors'][0]['detail'] == 'Expected a list of items but got type "dict".' @@ -916,8 +909,7 @@ def test_bulk_delete_errors(self, app, user, non_contrib, public_project, public # test_bulk_deletes_public_node_pointers_fails_if_bad_auth node_count_before = len(public_project.nodes_pointer) - res = app.delete_json_api(public_url, public_payload, - auth=non_contrib.auth, expect_errors=True, bulk=True) + res = app.delete_json_api(public_url, public_payload, auth=non_contrib.auth, expect_errors=True, bulk=True) # This is could arguably be a 405, but we don't need to go crazy with status codes assert res.status_code == 403 assert 'detail' in res.json['errors'][0] @@ -925,8 +917,7 @@ def test_bulk_delete_errors(self, app, user, non_contrib, public_project, public assert node_count_before == len(public_project.nodes_pointer) # test_bulk_deletes_private_node_pointers_logged_in_non_contributor - res = app.delete_json_api(private_url, private_payload, - auth=non_contrib.auth, expect_errors=True, bulk=True) + res = app.delete_json_api(private_url, private_payload, auth=non_contrib.auth, expect_errors=True, bulk=True) assert res.status_code == 403 assert 'detail' in res.json['errors'][0] diff --git a/api_tests/nodes/views/test_node_logs.py b/api_tests/nodes/views/test_node_logs.py index 1ab4904085f..c756bb9cc1f 100644 --- a/api_tests/nodes/views/test_node_logs.py +++ b/api_tests/nodes/views/test_node_logs.py @@ -1,20 +1,20 @@ +import datetime import pytest -import urlparse import pytz -import datetime +import urlparse from dateutil.parser import parse as parse_date +from api.base.settings.defaults import API_BASE from framework.auth.core import Auth from osf.models import NodeLog -from website.util import disconnected_from_listeners -from website.project.signals import contributor_removed -from api.base.settings.defaults import API_BASE -from tests.base import ApiTestCase, assert_datetime_equal from osf_tests.factories import ( ProjectFactory, AuthUserFactory, ) +from tests.base import assert_datetime_equal +from website.util import disconnected_from_listeners +from website.project.signals import contributor_removed API_LATEST = 0 API_FIRST = -1 @@ -64,7 +64,7 @@ def public_url(self, public_project): def test_add_tag(self, app, user, user_auth, public_project, public_url): public_project.add_tag('Rheisen', auth=user_auth) - assert 'tag_added' == public_project.logs.latest().action + assert public_project.logs.latest().action == 'tag_added' res = app.get(public_url, auth=user.auth) assert res.status_code == 200 assert len(res.json['data']) == public_project.logs.count() @@ -73,14 +73,14 @@ def test_add_tag(self, app, user, user_auth, public_project, public_url): def test_remove_tag(self, app, user, user_auth, public_project, public_url): public_project.add_tag('Rheisen', auth=user_auth) - assert 'tag_added' == public_project.logs.latest().action + assert public_project.logs.latest().action == 'tag_added' public_project.remove_tag('Rheisen', auth=user_auth) - assert 'tag_removed' == public_project.logs.latest().action + assert public_project.logs.latest().action == 'tag_removed' res = app.get(public_url, auth=user) assert res.status_code == 200 assert len(res.json['data']) == public_project.logs.count() assert res.json['data'][API_LATEST]['attributes']['action'] == 'tag_removed' - assert 'Rheisen' == public_project.logs.latest().params['tag'] + assert public_project.logs.latest().params['tag'] == 'Rheisen' def test_project_creation(self, app, user, public_project, private_project, public_url, private_url): @@ -109,7 +109,7 @@ def test_project_creation(self, app, user, public_project, private_project, publ def test_add_addon(self, app, user, user_auth, public_project, public_url): public_project.add_addon('github', auth=user_auth) - assert 'addon_added' == public_project.logs.latest().action + assert public_project.logs.latest().action == 'addon_added' res = app.get(public_url, auth=user.auth) assert res.status_code == 200 assert len(res.json['data']) == public_project.logs.count() @@ -117,12 +117,12 @@ def test_add_addon(self, app, user, user_auth, public_project, public_url): def test_project_add_remove_contributor(self, app, user, contrib, user_auth, public_project, public_url): public_project.add_contributor(contrib, auth=user_auth) - assert 'contributor_added' == public_project.logs.latest().action + assert public_project.logs.latest().action == 'contributor_added' # Disconnect contributor_removed so that we don't check in files # We can remove this when StoredFileNode is implemented in osf-models with disconnected_from_listeners(contributor_removed): public_project.remove_contributor(contrib, auth=user_auth) - assert 'contributor_removed' == public_project.logs.latest().action + assert public_project.logs.latest().action == 'contributor_removed' res = app.get(public_url, auth=user.auth) assert res.status_code == 200 assert len(res.json['data']) == public_project.logs.count() @@ -131,10 +131,10 @@ def test_project_add_remove_contributor(self, app, user, contrib, user_auth, pub def test_remove_addon(self, app, user, user_auth, public_project, public_url): public_project.add_addon('github', auth=user_auth) - assert 'addon_added' == public_project.logs.latest().action + assert public_project.logs.latest().action == 'addon_added' old_log_length = len(list(public_project.logs.all())) public_project.delete_addon('github', auth=user_auth) - assert 'addon_removed' == public_project.logs.latest().action + assert public_project.logs.latest().action == 'addon_removed' assert (public_project.logs.count() - 1) == old_log_length res = app.get(public_url, auth=user.auth) assert res.status_code == 200 @@ -143,7 +143,7 @@ def test_remove_addon(self, app, user, user_auth, public_project, public_url): def test_add_pointer(self, app, user_auth, public_project, pointer, public_url): public_project.add_pointer(pointer, auth=user_auth, save=True) - assert 'pointer_created' == public_project.logs.latest().action + assert public_project.logs.latest().action == 'pointer_created' res = app.get(public_url, auth=user_auth) assert res.status_code == 200 assert len(res.json['data']) == public_project.logs.count() @@ -154,15 +154,15 @@ class TestNodeLogFiltering(TestNodeLogList): def test_filter_action_not_equal(self, app, user, user_auth, public_project): public_project.add_tag('Rheisen', auth=user_auth) - assert 'tag_added' == public_project.logs.latest().action + assert public_project.logs.latest().action == 'tag_added' url = '/{}nodes/{}/logs/?filter[action][ne]=tag_added'.format(API_BASE, public_project._id) res = app.get(url, auth=user.auth) assert len(res.json['data']) == 1 - assert res.json['data'][0]['attributes']['action'] == 'project_created' + assert res.json['data'][API_LATEST]['attributes']['action'] == 'project_created' def test_filter_date_not_equal(self, app, user, public_project, pointer): public_project.add_pointer(pointer, auth=Auth(user), save=True) - assert 'pointer_created' == public_project.logs.latest().action + assert public_project.logs.latest().action == 'pointer_created' assert public_project.logs.count() == 2 pointer_added_log = public_project.logs.get(action='pointer_created') @@ -172,4 +172,4 @@ def test_filter_date_not_equal(self, app, user, public_project, pointer): res = app.get(url, auth=user.auth) assert res.status_code == 200 assert len(res.json['data']) == 1 - assert res.json['data'][0]['attributes']['action'] == 'project_created' + assert res.json['data'][API_LATEST]['attributes']['action'] == 'project_created' diff --git a/api_tests/nodes/views/test_node_registrations_list.py b/api_tests/nodes/views/test_node_registrations_list.py index 69d25d7842b..1984ce9a73a 100644 --- a/api_tests/nodes/views/test_node_registrations_list.py +++ b/api_tests/nodes/views/test_node_registrations_list.py @@ -2,7 +2,6 @@ from urlparse import urlparse from api.base.settings.defaults import API_BASE -from tests.base import ApiTestCase from osf_tests.factories import ( ProjectFactory, RegistrationFactory, @@ -48,7 +47,7 @@ def test_node_registration_list(self, app, user, public_project, private_project res = app.get(public_url) assert res.status_code == 200 assert res.content_type == 'application/vnd.api+json' - assert res.json['data'][0]['attributes']['registration'] == True + assert res.json['data'][0]['attributes']['registration'] is True url = res.json['data'][0]['relationships']['registered_from']['links']['related']['href'] assert urlparse(url).path == '/{}nodes/{}/'.format(API_BASE, public_project._id) assert res.json['data'][0]['type'] == 'registrations' @@ -56,7 +55,7 @@ def test_node_registration_list(self, app, user, public_project, private_project # test_return_public_registrations_logged_in res = app.get(public_url, auth=user.auth) assert res.status_code == 200 - assert res.json['data'][0]['attributes']['registration'] == True + assert res.json['data'][0]['attributes']['registration'] is True url = res.json['data'][0]['relationships']['registered_from']['links']['related']['href'] assert urlparse(url).path == '/{}nodes/{}/'.format(API_BASE, public_project._id) assert res.content_type == 'application/vnd.api+json' @@ -70,7 +69,7 @@ def test_node_registration_list(self, app, user, public_project, private_project # test_return_private_registrations_logged_in_contributor res = app.get(private_url, auth=user.auth) assert res.status_code == 200 - assert res.json['data'][0]['attributes']['registration'] == True + assert res.json['data'][0]['attributes']['registration'] is True url = res.json['data'][0]['relationships']['registered_from']['links']['related']['href'] assert urlparse(url).path == '/{}nodes/{}/'.format(API_BASE, private_project._id) assert res.content_type == 'application/vnd.api+json' diff --git a/api_tests/nodes/views/test_node_sparse_fieldsets.py b/api_tests/nodes/views/test_node_sparse_fieldsets.py index ae56e34f189..134873f12b7 100644 --- a/api_tests/nodes/views/test_node_sparse_fieldsets.py +++ b/api_tests/nodes/views/test_node_sparse_fieldsets.py @@ -1,13 +1,13 @@ import pytest from api.base.settings.defaults import API_BASE -from tests.base import ApiTestCase -from website.util import permissions from osf_tests.factories import ( ProjectFactory, AuthUserFactory, PrivateLinkFactory, ) +from tests.base import ApiTestCase +from website.util import permissions @pytest.fixture() def user(): @@ -51,15 +51,15 @@ def test_node_sparse_fields_list(self, app, user, deleted_project, private_proje # test_returns_expected_nodes res = app.get(url + 'title') - node_json = res.json['data'] + data = res.json['data'] - ids = [each['id'] for each in node_json] + ids = [each['id'] for each in data] assert public_project._id in ids assert deleted_project._id not in ids assert private_project._id not in ids - assert len(node_json) == 1 - node_json = node_json[0] + assert len(data) == 1 + node_json = data[0] assert node_json['attributes']['title'] == public_project.title assert len(node_json['attributes']) == 1 assert set(node_json.keys()) == set(['links', 'type', 'id', 'attributes']) @@ -180,6 +180,7 @@ def test_update_with_sparse_fields(self, app, user, node, url): assert res.json['data']['attributes'] == {} node.reload() assert node.title != old_title + assert node.title == 'new title' @pytest.mark.django_db class TestSparseViewOnlyLinks: @@ -204,7 +205,7 @@ def contributing_write_user(self): def private_node_one(self, creation_user, contributing_read_user, contributing_write_user): private_node_one = ProjectFactory(is_public=False, creator=creation_user, title='Private One') private_node_one.add_contributor(contributing_read_user, permissions=[permissions.READ], save=True) - private_node_one.add_contributor(contributing_write_user, permissions=[permissions.WRITE], save=True) + private_node_one.add_contributor(contributing_write_user, permissions=[permissions.READ, permissions.WRITE], save=True) return private_node_one @pytest.fixture() diff --git a/api_tests/nodes/views/test_node_view_only_links_detail.py b/api_tests/nodes/views/test_node_view_only_links_detail.py index e583bb8ccf5..f1be08d6351 100644 --- a/api_tests/nodes/views/test_node_view_only_links_detail.py +++ b/api_tests/nodes/views/test_node_view_only_links_detail.py @@ -1,39 +1,38 @@ import pytest from api.base.settings.defaults import API_BASE -from tests.base import ApiTestCase -from website.util import permissions from osf_tests.factories import ( ProjectFactory, AuthUserFactory, - PrivateLinkFactory + PrivateLinkFactory, ) +from website.util import permissions -@pytest.fixture(scope='function') +@pytest.fixture() def user(): return AuthUserFactory() -@pytest.fixture(scope='function') -def read_only_user(): +@pytest.fixture() +def read_contrib(): return AuthUserFactory() -@pytest.fixture(scope='function') -def read_write_user(): +@pytest.fixture() +def write_contrib(): return AuthUserFactory() -@pytest.fixture(scope='function') -def non_contributor(): +@pytest.fixture() +def non_contrib(): return AuthUserFactory() -@pytest.fixture(scope='function') -def public_project(user, read_only_user, read_write_user): +@pytest.fixture() +def public_project(user, read_contrib, write_contrib): public_project = ProjectFactory(is_public=True, creator=user) - public_project.add_contributor(read_only_user, permissions=[permissions.READ]) - public_project.add_contributor(read_write_user, permissions=[permissions.WRITE]) + public_project.add_contributor(read_contrib, permissions=[permissions.READ]) + public_project.add_contributor(write_contrib, permissions=[permissions.READ, permissions.WRITE]) public_project.save() return public_project -@pytest.fixture(scope='function') +@pytest.fixture() def view_only_link(public_project): view_only_link = PrivateLinkFactory(name='testlink') view_only_link.nodes.add(public_project) @@ -41,14 +40,13 @@ def view_only_link(public_project): return view_only_link @pytest.mark.django_db -@pytest.mark.usefixtures('user', 'read_only_user', 'read_write_user', 'non_contributor', 'public_project', 'view_only_link') class TestViewOnlyLinksDetail: @pytest.fixture() def url(self, public_project, view_only_link): return '/{}nodes/{}/view_only_links/{}/'.format(API_BASE, public_project._id, view_only_link._id) - def test_non_mutating_view_only_links_detail_tests(self, app, user, read_write_user, read_only_user, non_contributor, url, public_project, view_only_link): + def test_non_mutating_view_only_links_detail_tests(self, app, user, write_contrib, read_contrib, non_contrib, url, public_project, view_only_link): # test_admin_can_view_vol_detail res = app.get(url, auth=user.auth) @@ -56,15 +54,15 @@ def test_non_mutating_view_only_links_detail_tests(self, app, user, read_write_u assert res.json['data']['attributes']['name'] == 'testlink' # test_read_write_cannot_view_vol_detail - res = app.get(url, auth=read_write_user.auth, expect_errors=True) + res = app.get(url, auth=write_contrib.auth, expect_errors=True) assert res.status_code == 403 # test_read_only_cannot_view_vol_detail - res = app.get(url, auth=read_only_user.auth, expect_errors=True) + res = app.get(url, auth=read_contrib.auth, expect_errors=True) assert res.status_code == 403 # test_logged_in_user_cannot_view_vol_detail - res = app.get(url, auth=non_contributor.auth, expect_errors=True) + res = app.get(url, auth=non_contrib.auth, expect_errors=True) assert res.status_code == 403 # test_unauthenticated_user_cannot_view_vol_detail @@ -83,7 +81,6 @@ def test_deleted_vol_not_returned(self, app, user, public_project, view_only_lin assert res.status_code == 404 @pytest.mark.django_db -@pytest.mark.usefixtures('user', 'read_only_user', 'read_write_user', 'non_contributor', 'public_project', 'view_only_link') class TestViewOnlyLinksUpdate: @pytest.fixture() @@ -133,7 +130,7 @@ def test_admin_can_update_vol_anonymous(self, app, user, view_only_link, url): assert res.json['data']['attributes']['name'] == 'testlink' assert res.json['data']['attributes']['anonymous'] == True - def test_cannot_update_vol(self, app, read_write_user, read_only_user, non_contributor, url): + def test_cannot_update_vol(self, app, write_contrib, read_contrib, non_contrib, url): # test_read_write_cannot_update_vol payload = { @@ -142,7 +139,7 @@ def test_cannot_update_vol(self, app, read_write_user, read_only_user, non_contr 'anonymous': True, } } - res = app.put_json_api(url, {'data': payload}, auth=read_write_user.auth, expect_errors=True) + res = app.put_json_api(url, {'data': payload}, auth=write_contrib.auth, expect_errors=True) assert res.status_code == 403 # test_read_only_cannot_update_vol @@ -152,7 +149,7 @@ def test_cannot_update_vol(self, app, read_write_user, read_only_user, non_contr 'anonymous': True, } } - res = app.put_json_api(url, {'data': payload}, auth=read_only_user.auth, expect_errors=True) + res = app.put_json_api(url, {'data': payload}, auth=read_contrib.auth, expect_errors=True) assert res.status_code == 403 # test_logged_in_user_cannot_update_vol @@ -162,7 +159,7 @@ def test_cannot_update_vol(self, app, read_write_user, read_only_user, non_contr 'anonymous': True, } } - res = app.put_json_api(url, {'data': payload}, auth=non_contributor.auth, expect_errors=True) + res = app.put_json_api(url, {'data': payload}, auth=non_contrib.auth, expect_errors=True) assert res.status_code == 403 # test_unauthenticated_user_cannot_update_vol @@ -176,7 +173,6 @@ def test_cannot_update_vol(self, app, read_write_user, read_only_user, non_contr assert res.status_code == 401 @pytest.mark.django_db -@pytest.mark.usefixtures('user', 'read_only_user', 'read_write_user', 'non_contributor', 'public_project', 'view_only_link') class TestViewOnlyLinksDelete: @pytest.fixture() @@ -189,18 +185,18 @@ def test_admin_can_delete_vol(self, app, user, url, view_only_link): assert res.status_code == 204 assert view_only_link.is_deleted == True - def test_vol_delete(self, app, read_write_user, read_only_user, non_contributor, url): + def test_vol_delete(self, app, write_contrib, read_contrib, non_contrib, url): # test_read_write_cannot_delete_vol - res = app.delete(url, auth=read_write_user.auth, expect_errors=True) + res = app.delete(url, auth=write_contrib.auth, expect_errors=True) assert res.status_code == 403 # test_read_only_cannot_delete_vol - res = app.delete(url, auth=read_only_user.auth, expect_errors=True) + res = app.delete(url, auth=read_contrib.auth, expect_errors=True) assert res.status_code == 403 # test_logged_in_user_cannot_delete_vol - res = app.delete(url, auth=non_contributor.auth, expect_errors=True) + res = app.delete(url, auth=non_contrib.auth, expect_errors=True) assert res.status_code == 403 # test_unauthenticated_user_cannot_delete_vol diff --git a/api_tests/nodes/views/test_node_view_only_links_list.py b/api_tests/nodes/views/test_node_view_only_links_list.py index f9c991a3051..8832102b2c5 100644 --- a/api_tests/nodes/views/test_node_view_only_links_list.py +++ b/api_tests/nodes/views/test_node_view_only_links_list.py @@ -2,38 +2,37 @@ from website.util import permissions from api.base.settings.defaults import API_BASE -from tests.base import ApiTestCase from osf_tests.factories import ( ProjectFactory, AuthUserFactory, PrivateLinkFactory ) -@pytest.fixture(scope='function') +@pytest.fixture() def user(): return AuthUserFactory() -@pytest.fixture(scope='function') -def read_only_user(): +@pytest.fixture() +def read_contrib(): return AuthUserFactory() -@pytest.fixture(scope='function') -def read_write_user(): +@pytest.fixture() +def write_contrib(): return AuthUserFactory() -@pytest.fixture(scope='function') -def non_contributor(): +@pytest.fixture() +def non_contrib(): return AuthUserFactory() -@pytest.fixture(scope='function') -def public_project(user, read_only_user, read_write_user): +@pytest.fixture() +def public_project(user, read_contrib, write_contrib): public_project = ProjectFactory(is_public=True, creator=user) - public_project.add_contributor(read_only_user, permissions=[permissions.READ]) - public_project.add_contributor(read_write_user, permissions=[permissions.WRITE]) + public_project.add_contributor(read_contrib, permissions=[permissions.READ]) + public_project.add_contributor(write_contrib, permissions=[permissions.READ, permissions.WRITE]) public_project.save() return public_project -@pytest.fixture(scope='function') +@pytest.fixture() def view_only_link(public_project): view_only_link = PrivateLinkFactory(name='testlink') view_only_link.nodes.add(public_project) @@ -41,14 +40,13 @@ def view_only_link(public_project): return view_only_link @pytest.mark.django_db -@pytest.mark.usefixtures('user', 'read_only_user', 'read_write_user', 'non_contributor', 'public_project', 'view_only_link') class TestViewOnlyLinksList: @pytest.fixture() - def url(self, public_project): + def url(self, public_project, view_only_link): return '/{}nodes/{}/view_only_links/'.format(API_BASE, public_project._id) - def test_non_mutating_view_only_links_list_tests(self, app, user, read_write_user, read_only_user, non_contributor, public_project, url): + def test_non_mutating_view_only_links_list_tests(self, app, user, write_contrib, read_contrib, non_contrib, public_project, url): # test_admin_can_view_vols_list res = app.get(url, auth=user.auth) @@ -58,15 +56,15 @@ def test_non_mutating_view_only_links_list_tests(self, app, user, read_write_use assert data[0]['attributes']['name'] == 'testlink' # test_read_write_cannot_view_vols_list - res = app.get(url, auth=read_write_user.auth, expect_errors=True) + res = app.get(url, auth=write_contrib.auth, expect_errors=True) assert res.status_code == 403 # test_read_only_cannot_view_vols_list - res = app.get(url, auth=read_only_user.auth, expect_errors=True) + res = app.get(url, auth=read_contrib.auth, expect_errors=True) assert res.status_code == 403 # test_logged_in_user_cannot_view_vols_list - res = app.get(url, auth=non_contributor.auth, expect_errors=True) + res = app.get(url, auth=non_contrib.auth, expect_errors=True) assert res.status_code == 403 # test_unauthenticated_user_cannot_view_vols_list @@ -92,7 +90,6 @@ def test_deleted_vols_not_returned(self, app, user, url, public_project): assert len(data) == 1 @pytest.mark.django_db -@pytest.mark.usefixtures('user', 'read_only_user', 'read_write_user', 'non_contributor', 'public_project', 'view_only_link') class TestViewOnlyLinksCreate: @pytest.fixture() @@ -138,7 +135,7 @@ def test_default_name_not_in_payload(self, app, user, public_project): assert data['attributes']['anonymous'] == False assert data['embeds']['creator']['data']['id'] == user._id - def test_admin_can_create_vol(self, app, user, public_project): + def test_admin_can_create_vol(self, app, user, public_project, view_only_link): url = '/{}nodes/{}/view_only_links/?embed=creator'.format(API_BASE, public_project._id) payload = { 'attributes': { @@ -154,7 +151,7 @@ def test_admin_can_create_vol(self, app, user, public_project): assert data['attributes']['anonymous'] == True assert data['embeds']['creator']['data']['id'] == user._id - def test_cannot_create_vol(self, app, read_write_user, read_only_user, non_contributor, url): + def test_cannot_create_vol(self, app, write_contrib, read_contrib, non_contrib, url): # test_read_write_cannot_create_vol payload = { @@ -163,7 +160,7 @@ def test_cannot_create_vol(self, app, read_write_user, read_only_user, non_contr 'anonymous': True, } } - res = app.post_json_api(url, {'data': payload}, auth=read_write_user.auth, expect_errors=True) + res = app.post_json_api(url, {'data': payload}, auth=write_contrib.auth, expect_errors=True) assert res.status_code == 403 # test_read_only_cannot_create_vol @@ -173,7 +170,7 @@ def test_cannot_create_vol(self, app, read_write_user, read_only_user, non_contr 'anonymous': True, } } - res = app.post_json_api(url, {'data': payload}, auth=read_only_user.auth, expect_errors=True) + res = app.post_json_api(url, {'data': payload}, auth=read_contrib.auth, expect_errors=True) assert res.status_code == 403 # test_logged_in_user_cannot_create_vol @@ -183,7 +180,7 @@ def test_cannot_create_vol(self, app, read_write_user, read_only_user, non_contr 'anonymous': True, } } - res = app.post_json_api(url, {'data': payload}, auth=non_contributor.auth, expect_errors=True) + res = app.post_json_api(url, {'data': payload}, auth=non_contrib.auth, expect_errors=True) assert res.status_code == 403 # test_unauthenticated_user_cannot_create_vol diff --git a/api_tests/nodes/views/test_view_only_query_parameter.py b/api_tests/nodes/views/test_view_only_query_parameter.py index b56c99612b9..d8ede45e4dd 100644 --- a/api_tests/nodes/views/test_view_only_query_parameter.py +++ b/api_tests/nodes/views/test_view_only_query_parameter.py @@ -1,44 +1,39 @@ import pytest -from website.util import permissions from api.base.settings.defaults import API_BASE -from tests.base import ApiTestCase from osf.models import AbstractNode as Node from osf_tests.factories import ( ProjectFactory, AuthUserFactory, PrivateLinkFactory, ) +from website.util import permissions @pytest.fixture() -def creation_user(): - return AuthUserFactory() - -@pytest.fixture() -def viewing_user(): +def admin(): return AuthUserFactory() @pytest.fixture() -def contributing_read_user(): +def read_contrib(): return AuthUserFactory() @pytest.fixture() -def contributing_write_user(): +def write_contrib(): return AuthUserFactory() @pytest.fixture() -def valid_contributors(creation_user, contributing_read_user, contributing_write_user): +def valid_contributors(admin, read_contrib, write_contrib): return [ - creation_user._id, - contributing_read_user._id, - contributing_write_user._id, + admin._id, + read_contrib._id, + write_contrib._id, ] @pytest.fixture() -def private_node_one(creation_user, contributing_read_user, contributing_write_user): - private_node_one = ProjectFactory(is_public=False, creator=creation_user, title='Private One') - private_node_one.add_contributor(contributing_read_user, permissions=[permissions.READ], save=True) - private_node_one.add_contributor(contributing_write_user, permissions=[permissions.WRITE], save=True) +def private_node_one(admin, read_contrib, write_contrib): + private_node_one = ProjectFactory(is_public=False, creator=admin, title='Private One') + private_node_one.add_contributor(read_contrib, permissions=[permissions.READ], save=True) + private_node_one.add_contributor(write_contrib, permissions=[permissions.READ, permissions.WRITE], save=True) return private_node_one @pytest.fixture() @@ -60,10 +55,10 @@ def private_node_one_url(private_node_one): return '/{}nodes/{}/'.format(API_BASE, private_node_one._id) @pytest.fixture() -def private_node_two(creation_user, contributing_read_user, contributing_write_user): - private_node_two = ProjectFactory(is_public=False, creator=creation_user, title='Private Two') - private_node_two.add_contributor(contributing_read_user, permissions=[permissions.READ], save=True) - private_node_two.add_contributor(contributing_write_user, permissions=[permissions.WRITE], save=True) +def private_node_two(admin, read_contrib, write_contrib): + private_node_two = ProjectFactory(is_public=False, creator=admin, title='Private Two') + private_node_two.add_contributor(read_contrib, permissions=[permissions.READ], save=True) + private_node_two.add_contributor(write_contrib, permissions=[permissions.READ, permissions.WRITE], save=True) return private_node_two @pytest.fixture() @@ -71,10 +66,10 @@ def private_node_two_url(private_node_two): return '/{}nodes/{}/'.format(API_BASE, private_node_two._id) @pytest.fixture() -def public_node_one(creation_user, contributing_read_user, contributing_write_user): - public_node_one = ProjectFactory(is_public=True, creator=creation_user, title='Public One') - public_node_one.add_contributor(contributing_read_user, permissions=[permissions.READ], save=True) - public_node_one.add_contributor(contributing_write_user, permissions=[permissions.WRITE], save=True) +def public_node_one(admin, read_contrib, write_contrib): + public_node_one = ProjectFactory(is_public=True, creator=admin, title='Public One') + public_node_one.add_contributor(read_contrib, permissions=[permissions.READ], save=True) + public_node_one.add_contributor(write_contrib, permissions=[permissions.READ, permissions.WRITE], save=True) return public_node_one @pytest.fixture() @@ -96,10 +91,10 @@ def public_node_one_url(public_node_one): return '/{}nodes/{}/'.format(API_BASE, public_node_one._id) @pytest.fixture() -def public_node_two(creation_user, contributing_read_user, contributing_write_user): - public_node_two = ProjectFactory(is_public=True, creator=creation_user, title='Public Two') - public_node_two.add_contributor(contributing_read_user, permissions=[permissions.READ], save=True) - public_node_two.add_contributor(contributing_write_user, permissions=[permissions.WRITE], save=True) +def public_node_two(admin, read_contrib, write_contrib): + public_node_two = ProjectFactory(is_public=True, creator=admin, title='Public Two') + public_node_two.add_contributor(read_contrib, permissions=[permissions.READ], save=True) + public_node_two.add_contributor(write_contrib, permissions=[permissions.READ, permissions.WRITE], save=True) return public_node_two @pytest.fixture() @@ -107,16 +102,16 @@ def public_node_two_url(public_node_two): return '/{}nodes/{}/'.format(API_BASE, public_node_two._id) @pytest.mark.django_db -@pytest.mark.usefixtures('creation_user', 'viewing_user', 'contributing_read_user', 'contributing_write_user', 'valid_contributors', +@pytest.mark.usefixtures('admin', 'read_contrib', 'write_contrib', 'valid_contributors', 'private_node_one', 'private_node_one_anonymous_link', 'private_node_one_private_link', 'private_node_one_url', 'private_node_two', 'private_node_two_url', 'public_node_one', 'public_node_one_anonymous_link', 'public_node_one_private_link', 'public_node_one_url', 'public_node_two', 'public_node_two_url') class TestNodeDetailViewOnlyLinks: - def test_private_node(self, app, creation_user, contributing_read_user, valid_contributors, private_node_one, private_node_one_url, private_node_one_private_link, private_node_one_anonymous_link, public_node_one_url, public_node_one_private_link, public_node_one_anonymous_link): + def test_private_node(self, app, admin, read_contrib, valid_contributors, private_node_one, private_node_one_url, private_node_one_private_link, private_node_one_anonymous_link, public_node_one_url, public_node_one_private_link, public_node_one_anonymous_link): # test_private_node_with_link_works_when_using_link - res_normal = app.get(private_node_one_url, auth=contributing_read_user.auth) + res_normal = app.get(private_node_one_url, auth=read_contrib.auth) assert res_normal.status_code == 200 res_linked = app.get(private_node_one_url, {'view_only': private_node_one_private_link.key}) assert res_linked.status_code == 200 @@ -159,7 +154,7 @@ def test_private_node(self, app, creation_user, contributing_read_user, valid_co res = app.get(private_node_one_url, { 'view_only': private_node_one_private_link.key, 'embed': 'contributors', - }, auth=creation_user.auth) + }, auth=admin.auth) assert res.status_code == 200 contributors = res.json['data']['embeds']['contributors']['data'] for contributor in contributors: @@ -245,7 +240,7 @@ def test_private_node(self, app, creation_user, contributing_read_user, valid_co assert res.status_code == 401 res = app.get(private_node_one_url+'logs/', { 'view_only': 'thisisnotarealprivatekey', - }, auth=creation_user.auth) + }, auth=admin.auth) assert res.status_code == 200 # test_view_only_key_in_relationships_links @@ -266,7 +261,7 @@ def test_private_node(self, app, creation_user, contributing_read_user, valid_co assert private_node_one_private_link.key in links['html'] @pytest.mark.django_db -@pytest.mark.usefixtures('creation_user', 'viewing_user', 'contributing_read_user', 'contributing_write_user', 'valid_contributors', +@pytest.mark.usefixtures('admin', 'read_contrib', 'write_contrib', 'valid_contributors', 'private_node_one', 'private_node_one_anonymous_link', 'private_node_one_private_link', 'private_node_one_url', 'private_node_two', 'private_node_two_url', 'public_node_one', 'public_node_one_anonymous_link', 'public_node_one_private_link', 'public_node_one_url', 'public_node_two', 'public_node_two_url') diff --git a/api_tests/view_only_links/views/test_view_only_link_nodes.py b/api_tests/view_only_links/views/test_view_only_link_nodes.py index abee5276c33..ca36cd29e5e 100644 --- a/api_tests/view_only_links/views/test_view_only_link_nodes.py +++ b/api_tests/view_only_links/views/test_view_only_link_nodes.py @@ -1,34 +1,32 @@ import pytest -from nose.tools import * # flake8: noqa -from website.util import permissions from api.base.settings.defaults import API_BASE -from tests.base import ApiTestCase from osf_tests.factories import ( ProjectFactory, AuthUserFactory, PrivateLinkFactory, - NodeFactory + NodeFactory, ) +from website.util import permissions -@pytest.fixture(scope='function') +@pytest.fixture() def user(): return AuthUserFactory() -@pytest.fixture(scope='function') +@pytest.fixture() def read_only_user(): return AuthUserFactory() -@pytest.fixture(scope='function') +@pytest.fixture() def read_write_user(): return AuthUserFactory() -@pytest.fixture(scope='function') +@pytest.fixture() def non_contributor(): return AuthUserFactory() -@pytest.fixture(scope='function') +@pytest.fixture() def public_project(user, read_only_user, read_write_user): public_project = ProjectFactory(is_public=True, creator=user) public_project.add_contributor(read_only_user, permissions=[permissions.READ]) @@ -36,7 +34,7 @@ def public_project(user, read_only_user, read_write_user): public_project.save() return public_project -@pytest.fixture(scope='function') +@pytest.fixture() def view_only_link(public_project): view_only_link = PrivateLinkFactory(name='testlink') view_only_link.nodes.add(public_project) diff --git a/tests/utils.py b/tests/utils.py index 28fb5c87726..8c6387e4bd2 100644 --- a/tests/utils.py +++ b/tests/utils.py @@ -1,18 +1,19 @@ import contextlib +import datetime import functools import mock -import datetime from django.http import HttpRequest from django.utils import timezone from nose import SkipTest from nose.tools import assert_equal, assert_not_equal + from framework.auth import Auth from framework.celery_tasks.handlers import celery_teardown_request -from website.archiver import ARCHIVER_SUCCESS -from website.archiver import listeners as archiver_listeners from osf.models import Sanction from tests.base import get_default_metaschema +from website.archiver import ARCHIVER_SUCCESS +from website.archiver import listeners as archiver_listeners def requires_module(module): def decorator(fn): @@ -43,7 +44,7 @@ def test_update_node(self): def outer_wrapper(func): @functools.wraps(func) def wrapper(self, *args, **kwargs): - node = getattr(self, node_key) + node = getattr(self, node_key) last_log = node.logs.latest() func(self, *args, **kwargs) node.reload() @@ -70,12 +71,12 @@ def wrapper(self, *args, **kwargs): return outer_wrapper @contextlib.contextmanager -def assert_latest_log(log_action, node_key, index=-1): - node = node_key +def assert_latest_log(log_action, node_key, index=0): + node = node_key last_log = node.logs.latest() node.reload() yield - new_log = node.logs.order_by('-date')[-index - 1] + new_log = node.logs.order_by('-date')[index] assert last_log._id != new_log._id assert new_log.action == log_action From d47bf11a0a0606c0f9de48a1663917bbb546f42c Mon Sep 17 00:00:00 2001 From: John Tordoff Date: Thu, 8 Jun 2017 14:10:29 -0400 Subject: [PATCH 068/163] Fix bug in auto populating tags --- api/nodes/serializers.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/api/nodes/serializers.py b/api/nodes/serializers.py index 3f2d5a9ffcc..e37c47e9071 100644 --- a/api/nodes/serializers.py +++ b/api/nodes/serializers.py @@ -443,7 +443,8 @@ def create(self, validated_data): except ValidationError as e: raise InvalidModelValueError(detail=e.messages[0]) if len(tag_instances): - node.tags.add(*tag_instances) + for tag in tag_instances: + node.tags.add(tag) if is_truthy(request.GET.get('inherit_contributors')) and validated_data['parent'].has_permission(user, 'write'): auth = get_user_auth(request) parent = validated_data['parent'] From 3c25218bfbc330bf79560f1729b5549bbab5b37a Mon Sep 17 00:00:00 2001 From: John Tordoff Date: Thu, 8 Jun 2017 14:11:13 -0400 Subject: [PATCH 069/163] add test for auto-populating tags --- api_tests/nodes/views/test_node_list.py | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/api_tests/nodes/views/test_node_list.py b/api_tests/nodes/views/test_node_list.py index 4147182dd23..9491808a014 100644 --- a/api_tests/nodes/views/test_node_list.py +++ b/api_tests/nodes/views/test_node_list.py @@ -881,6 +881,31 @@ def test_create_component_inherit_contributors(self): assert_equal(len(new_component.contributors), 2) assert_equal(len(new_component.contributors), len(parent_project.contributors)) + def test_create_component_with_tags(self): + parent_project = ProjectFactory(creator=self.user_one) + url = '/{}nodes/{}/children/'.format(API_BASE, parent_project._id) + component_data = { + 'data': { + 'type': 'nodes', + 'attributes': { + 'title': self.title, + 'category': self.category, + 'tags': ['test tag 1', 'test tag 2'] + } + } + } + res = self.app.post_json_api(url, component_data, auth=self.user_one.auth) + assert_equal(res.status_code, 201) + json_data = res.json['data'] + + new_component_id = json_data['id'] + new_component = Node.load(new_component_id) + + assert_equal(len(new_component.tags.all()), 2) + tag1, tag2 = new_component.tags.all() + assert_equal(tag1.name, 'test tag 1') + assert_equal(tag2.name, 'test tag 2') + def test_create_component_inherit_contributors_with_unregistered_contributor(self): parent_project = ProjectFactory(creator=self.user_one) parent_project.add_unregistered_contributor( From 53c9445a895509cdd05283c80d4dbe3e0bbedb13 Mon Sep 17 00:00:00 2001 From: Rheisen Dennis Date: Thu, 8 Jun 2017 14:31:57 -0400 Subject: [PATCH 070/163] fix test_node_embeds error --- api_tests/nodes/views/test_node_embeds.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/api_tests/nodes/views/test_node_embeds.py b/api_tests/nodes/views/test_node_embeds.py index 533c7dd4b24..18e4da1450d 100644 --- a/api_tests/nodes/views/test_node_embeds.py +++ b/api_tests/nodes/views/test_node_embeds.py @@ -67,8 +67,8 @@ def test_node_embeds(self, app, user, write_contrib_one, write_contribs, subchil embeds = res.json['data']['embeds'] ids = [child_one._id, child_two._id] assert len(embeds['children']['data']) == len(ids) - children = [child._id for child in res.json['data']['embeds']['children']['data']] - assert set(child_one._id, child_two._id) == set(children) + children = [child['id'] for child in res.json['data']['embeds']['children']['data']] + assert set([child_one._id, child_two._id]) == set(children) # test_embed_parent url = '/{}nodes/{}/?embed=parent'.format(API_BASE, child_one._id) From 18d93c9671561705b36ddaa295d4c94a53d0bb3f Mon Sep 17 00:00:00 2001 From: Rheisen Dennis Date: Thu, 8 Jun 2017 16:20:23 -0400 Subject: [PATCH 071/163] convert mixin to use pytext fixtures and reorder imports --- api_tests/nodes/views/test_node_preprints.py | 70 ++++-- .../test_preprint_provider_preprints_list.py | 55 +++-- api_tests/preprints/filters/test_filters.py | 232 +++++++++++------- .../preprints/views/test_preprint_list.py | 66 +++-- .../users/views/test_user_preprints_list.py | 61 +++-- 5 files changed, 311 insertions(+), 173 deletions(-) diff --git a/api_tests/nodes/views/test_node_preprints.py b/api_tests/nodes/views/test_node_preprints.py index e7139ba3dec..1dc0134b851 100644 --- a/api_tests/nodes/views/test_node_preprints.py +++ b/api_tests/nodes/views/test_node_preprints.py @@ -1,33 +1,59 @@ -import pytest - from nose.tools import * # flake8: noqa +import pytest -from framework.auth.core import Auth -from tests.base import ApiTestCase +from addons.osfstorage.models import OsfStorageFile from api.base.settings.defaults import API_BASE +from api_tests import utils as test_utils from api_tests.preprints.filters.test_filters import PreprintsListFilteringMixin from api_tests.preprints.views.test_preprint_list_mixin import PreprintIsPublishedListMixin, PreprintIsValidListMixin +from framework.auth.core import Auth from osf.models import PreprintService -from addons.osfstorage.models import OsfStorageFile -from osf_tests.factories import PreprintFactory, AuthUserFactory, ProjectFactory, SubjectFactory, PreprintProviderFactory -from api_tests import utils as test_utils +from osf_tests.factories import ( + PreprintFactory, + AuthUserFactory, + ProjectFactory, + SubjectFactory, + PreprintProviderFactory +) +from tests.base import ApiTestCase class TestNodePreprintsListFiltering(PreprintsListFilteringMixin): - @pytest.fixture(autouse=True) - def setUp(self): - self.user = AuthUserFactory() - self.provider_one = PreprintProviderFactory(name='Sockarxiv') - self.provider_two = PreprintProviderFactory(name='Piratearxiv') - self.provider_three = PreprintProviderFactory(name='Mockarxiv') - self.project_one = ProjectFactory(creator=self.user) - self.project_two = self.project_one - self.project_three = self.project_one - self.url = '/{}nodes/{}/preprints/?version=2.2&'.format(API_BASE, self.project_one._id) - super(TestNodePreprintsListFiltering, self).setUp() - - def test_provider_filter_equals_returns_one(self): - expected = [self.preprint_two._id] - res = self.app.get('{}{}'.format(self.provider_url, self.provider_two._id), auth=self.user.auth) + + @pytest.fixture() + def user(self): + return AuthUserFactory() + + @pytest.fixture() + def provider_one(self): + return PreprintProviderFactory(name='Sockarxiv') + + @pytest.fixture() + def provider_two(self): + return PreprintProviderFactory(name='Piratearxiv') + + @pytest.fixture() + def provider_three(self): + return PreprintProviderFactory(name='Mockarxiv') + + @pytest.fixture() + def project_one(self, user): + return ProjectFactory(creator=user) + + @pytest.fixture() + def project_two(self, project_one): + return project_one + + @pytest.fixture() + def project_three(self, project_one): + return project_one + + @pytest.fixture() + def url(self, project_one): + return '/{}nodes/{}/preprints/?version=2.2&'.format(API_BASE, project_one._id) + + def test_provider_filter_equals_returns_one(self, app, user, provider_two, preprint_two, provider_url): + expected = [preprint_two._id] + res = app.get('{}{}'.format(provider_url, provider_two._id), auth=user.auth) actual = [preprint['id'] for preprint in res.json['data']] assert expected == actual diff --git a/api_tests/preprint_providers/views/test_preprint_provider_preprints_list.py b/api_tests/preprint_providers/views/test_preprint_provider_preprints_list.py index 6dbba149e57..cca5e93014e 100644 --- a/api_tests/preprint_providers/views/test_preprint_provider_preprints_list.py +++ b/api_tests/preprint_providers/views/test_preprint_provider_preprints_list.py @@ -1,12 +1,10 @@ -import pytest - from nose.tools import * # flake8: noqa +import pytest from api.base.settings.defaults import API_BASE from api_tests.preprints.filters.test_filters import PreprintsListFilteringMixin from api_tests.preprints.views.test_preprint_list_mixin import PreprintIsPublishedListMixin, PreprintIsValidListMixin from framework.auth.core import Auth -from tests.base import ApiTestCase from osf_tests.factories import ( ProjectFactory, PreprintFactory, @@ -14,27 +12,48 @@ SubjectFactory, PreprintProviderFactory ) +from tests.base import ApiTestCase class TestPreprintProviderPreprintsListFiltering(PreprintsListFilteringMixin): - @pytest.fixture(autouse=True) - def setUp(self): - self.user = AuthUserFactory() - self.provider_one = PreprintProviderFactory(name='Sockarxiv') - self.provider_two = self.provider_one - self.provider_three = self.provider_one - self.project_one = ProjectFactory(creator=self.user) - self.project_two = ProjectFactory(creator=self.user) - self.project_three = ProjectFactory(creator=self.user) - self.url = '/{}preprint_providers/{}/preprints/?version=2.2&'.format(API_BASE, self.provider_one._id) - super(TestPreprintProviderPreprintsListFiltering, self).setUp() - def test_provider_filter_equals_returns_multiple(self): - expected = set([self.preprint_one._id, self.preprint_two._id, self.preprint_three._id]) - res = self.app.get('{}{}'.format(self.provider_url, self.provider_one._id), auth=self.user.auth) + @pytest.fixture() + def user(self): + return AuthUserFactory() + + @pytest.fixture() + def provider_one(self): + return PreprintProviderFactory(name='Sockarxiv') + + @pytest.fixture() + def provider_two(self, provider_one): + return provider_one + + @pytest.fixture() + def provider_three(self, provider_one): + return provider_one + + @pytest.fixture() + def project_one(self, user): + return ProjectFactory(creator=user) + + @pytest.fixture() + def project_two(self, user): + return ProjectFactory(creator=user) + + @pytest.fixture() + def project_three(self, user): + return ProjectFactory(creator=user) + + @pytest.fixture() + def url(self, provider_one): + return '/{}preprint_providers/{}/preprints/?version=2.2&'.format(API_BASE, provider_one._id) + + def test_provider_filter_equals_returns_multiple(self, app, user, provider_one, preprint_one, preprint_two, preprint_three, provider_url): + expected = set([preprint_one._id, preprint_two._id, preprint_three._id]) + res = app.get('{}{}'.format(provider_url, provider_one._id), auth=user.auth) actual = set([preprint['id'] for preprint in res.json['data']]) assert expected == actual - class TestPreprintProviderPreprintIsPublishedList(PreprintIsPublishedListMixin, ApiTestCase): def setUp(self): diff --git a/api_tests/preprints/filters/test_filters.py b/api_tests/preprints/filters/test_filters.py index 20a699f1ee7..1871be9767d 100644 --- a/api_tests/preprints/filters/test_filters.py +++ b/api_tests/preprints/filters/test_filters.py @@ -1,7 +1,6 @@ import pytest from framework.auth.core import Auth -from tests.json_api_test_app import JSONAPITestApp from osf_tests.factories import ( PreprintFactory, AuthUserFactory, @@ -11,150 +10,207 @@ @pytest.mark.django_db class PreprintsListFilteringMixin(object): - def setUp(self): - assert self.user, 'Subclasses of PreprintsListFilteringMixin must define self.user' - assert self.provider_one, 'Subclasses of PreprintsListFilteringMixin must define self.provider_one' - assert self.provider_two, 'Subclasses of PreprintsListFilteringMixin must define self.provider_two' - assert self.provider_three, 'Subclasses of PreprintsListFilteringMixin must define self.provider_three' - assert self.project_one, 'Subclasses of PreprintsListFilteringMixin must define self.project_one' - assert self.project_two, 'Subclasses of PreprintsListFilteringMixin must define self.project_two' - assert self.project_three, 'Subclasses of PreprintsListFilteringMixin must define self.project_three' - assert self.url, 'Subclasses of PreprintsListFilteringMixin must define self.url' - - self.app = JSONAPITestApp() - self.subject_one = SubjectFactory(text='First Subject') - self.subject_two = SubjectFactory(text='Second Subject') - - self.preprint_one = PreprintFactory(creator=self.user, project=self.project_one, provider=self.provider_one, subjects=[[self.subject_one._id]]) - self.preprint_two = PreprintFactory(creator=self.user, project=self.project_two, filename='tough.txt', provider=self.provider_two, subjects=[[self.subject_two._id]]) - self.preprint_three = PreprintFactory(creator=self.user, project=self.project_three, filename='darn.txt', provider=self.provider_three, subjects=[[self.subject_one._id], [self.subject_two._id]]) - - self.preprint_two.date_created = '2013-12-11 10:09:08.070605+00:00' - self.preprint_two.date_published = '2013-12-11 10:09:08.070605+00:00' - self.preprint_two.save() - - self.preprint_three.date_created = '2013-12-11 10:09:08.070605+00:00' - self.preprint_three.date_published = '2013-12-11 10:09:08.070605+00:00' - self.preprint_three.is_published = False - self.preprint_three.save() - - self.provider_url = '{}filter[provider]='.format(self.url) - self.id_url = '{}filter[id]='.format(self.url) - self.date_created_url = '{}filter[date_created]='.format(self.url) - self.date_modified_url = '{}filter[date_modified]='.format(self.url) - self.date_published_url = '{}filter[date_published]='.format(self.url) - self.is_published_url = '{}filter[is_published]='.format(self.url) - - self.is_published_and_modified_url = '{}filter[is_published]=true&filter[date_created]=2013-12-11'.format(self.url) - - self.has_subject = '{}filter[subjects]='.format(self.url) - - def test_provider_filter_null(self): + + @pytest.fixture() + def user(self): + raise NotImplementedError + + @pytest.fixture() + def provider_one(self): + raise NotImplementedError + + @pytest.fixture() + def provider_two(self): + raise NotImplementedError + + @pytest.fixture() + def provider_three(self): + raise NotImplementedError + + @pytest.fixture() + def project_one(self): + raise NotImplementedError + + @pytest.fixture() + def project_two(self): + raise NotImplementedError + + @pytest.fixture() + def project_three(self): + raise NotImplementedError + + @pytest.fixture() + def url(self): + raise NotImplementedError + + @pytest.fixture() + def subject_one(self): + return SubjectFactory(text='First Subject') + + @pytest.fixture() + def subject_two(self): + return SubjectFactory(text='Second Subject') + + @pytest.fixture() + def preprint_one(self, user, project_one, provider_one, subject_one): + return PreprintFactory(creator=user, project=project_one, provider=provider_one, subjects=[[subject_one._id]]) + + @pytest.fixture() + def preprint_two(self, user, project_two, provider_two, subject_two): + preprint_two = PreprintFactory(creator=user, project=project_two, filename='howto_reason.txt', provider=provider_two, subjects=[[subject_two._id]]) + preprint_two.date_created = '2013-12-11 10:09:08.070605+00:00' + preprint_two.date_published = '2013-12-11 10:09:08.070605+00:00' + preprint_two.save() + return preprint_two + + @pytest.fixture() + def preprint_three(self, user, project_three, provider_three, subject_one, subject_two): + preprint_three = PreprintFactory(creator=user, project=project_three, filename='darn_reason.txt', provider=provider_three, subjects=[[subject_one._id], [subject_two._id]]) + preprint_three.date_created = '2013-12-11 10:09:08.070605+00:00' + preprint_three.date_published = '2013-12-11 10:09:08.070605+00:00' + preprint_three.is_published = False + preprint_three.save() + return preprint_three + + + @pytest.fixture() + def provider_url(self, url): + return '{}filter[provider]='.format(url) + + @pytest.fixture() + def id_url(self, url): + return '{}filter[id]='.format(url) + + @pytest.fixture() + def date_created_url(self, url): + return '{}filter[date_created]='.format(url) + + @pytest.fixture() + def date_modified_url(self, url): + return '{}filter[date_modified]='.format(url) + + @pytest.fixture() + def date_published_url(self, url): + return '{}filter[date_published]='.format(url) + + @pytest.fixture() + def is_published_url(self, url): + return '{}filter[is_published]='.format(url) + + @pytest.fixture() + def is_published_and_modified_url(self, url): + return '{}filter[is_published]=true&filter[date_created]=2013-12-11'.format(url) + + @pytest.fixture() + def has_subject(self, url): + return '{}filter[subjects]='.format(url) + + def test_provider_filter_null(self, app, user, provider_url): expected = [] - res = self.app.get('{}null'.format(self.provider_url), auth=self.user.auth) + res = app.get('{}null'.format(provider_url), auth=user.auth) actual = [preprint['id'] for preprint in res.json['data']] assert expected == actual - def test_id_filter_null(self): + def test_id_filter_null(self, app, user, id_url): expected = [] - res = self.app.get('{}null'.format(self.id_url), auth=self.user.auth) + res = app.get('{}null'.format(id_url), auth=user.auth) actual = [preprint['id'] for preprint in res.json['data']] assert expected == actual - def test_id_filter_equals_returns_one(self): - expected = [self.preprint_two._id] - res = self.app.get('{}{}'.format(self.id_url, self.preprint_two._id), auth=self.user.auth) + def test_id_filter_equals_returns_one(self, app, user, preprint_two, id_url): + expected = [preprint_two._id] + res = app.get('{}{}'.format(id_url, preprint_two._id), auth=user.auth) actual = [preprint['id'] for preprint in res.json['data']] assert expected == actual - def test_date_created_filter_equals_returns_none(self): + def test_date_created_filter_equals_returns_none(self, app, user, date_created_url): expected = [] - res = self.app.get('{}{}'.format(self.date_created_url, '2015-11-15 10:09:08.070605+00:00'), auth=self.user.auth) + res = app.get('{}{}'.format(date_created_url, '2015-11-15 10:09:08.070605+00:00'), auth=user.auth) actual = [preprint['id'] for preprint in res.json['data']] assert expected == actual - def test_date_created_filter_equals_returns_one(self): - expected = [self.preprint_one._id] - res = self.app.get('{}{}'.format(self.date_created_url, self.preprint_one.date_created), auth=self.user.auth) + def test_date_created_filter_equals_returns_one(self, app, user, preprint_one, date_created_url): + expected = [preprint_one._id] + res = app.get('{}{}'.format(date_created_url, preprint_one.date_created), auth=user.auth) actual = [preprint['id'] for preprint in res.json['data']] assert expected == actual - def test_date_created_filter_equals_returns_multiple(self): - expected = set([self.preprint_two._id, self.preprint_three._id]) - res = self.app.get('{}{}'.format(self.date_created_url, self.preprint_two.date_created), auth=self.user.auth) + def test_date_created_filter_equals_returns_multiple(self, app, user, preprint_two, preprint_three, date_created_url): + expected = set([preprint_two._id, preprint_three._id]) + res = app.get('{}{}'.format(date_created_url, preprint_two.date_created), auth=user.auth) actual = set([preprint['id'] for preprint in res.json['data']]) assert expected == actual - def test_date_modified_filter_equals_returns_none(self): + def test_date_modified_filter_equals_returns_none(self, app, user, date_modified_url): expected = [] - res = self.app.get('{}{}'.format(self.date_modified_url, '2015-11-15 10:09:08.070605+00:00'), auth=self.user.auth) + res = app.get('{}{}'.format(date_modified_url, '2015-11-15 10:09:08.070605+00:00'), auth=user.auth) actual = [preprint['id'] for preprint in res.json['data']] assert expected == actual # This test was causing problems because modifying anything caused set modified dates to update to current date # This test could hypothetically fail if the time between fixture creations splits a day (e.g., midnight) - def test_date_modified_filter_equals_returns_multiple(self): - expected = set([self.preprint_one._id, self.preprint_two._id, self.preprint_three._id]) - res = self.app.get('{}{}'.format(self.date_modified_url, self.preprint_one.date_modified), auth=self.user.auth) + def test_date_modified_filter_equals_returns_multiple(self, app, user, preprint_one, preprint_two, preprint_three, date_modified_url): + expected = set([preprint_one._id, preprint_two._id, preprint_three._id]) + res = app.get('{}{}'.format(date_modified_url, preprint_one.date_modified), auth=user.auth) actual = set([preprint['id'] for preprint in res.json['data']]) assert expected == actual - def test_date_published_filter_equals_returns_none(self): + def test_date_published_filter_equals_returns_none(self, app, user, date_published_url): expected = [] - res = self.app.get('{}{}'.format(self.date_published_url, '2015-11-15 10:09:08.070605+00:00'), auth=self.user.auth) + res = app.get('{}{}'.format(date_published_url, '2015-11-15 10:09:08.070605+00:00'), auth=user.auth) actual = [preprint['id'] for preprint in res.json['data']] assert expected == actual - def test_date_published_filter_equals_returns_one(self): - expected = [self.preprint_one._id] - res = self.app.get('{}{}'.format(self.date_published_url, self.preprint_one.date_published), auth=self.user.auth) + def test_date_published_filter_equals_returns_one(self, app, user, preprint_one, date_published_url): + expected = [preprint_one._id] + res = app.get('{}{}'.format(date_published_url, preprint_one.date_published), auth=user.auth) actual = [preprint['id'] for preprint in res.json['data']] assert expected == actual - def test_date_published_filter_equals_returns_multiple(self): - expected = set([self.preprint_two._id, self.preprint_three._id]) - res = self.app.get('{}{}'.format(self.date_published_url, self.preprint_two.date_published), auth=self.user.auth) + def test_date_published_filter_equals_returns_multiple(self, app, user, preprint_two, preprint_three, date_published_url): + expected = set([preprint_two._id, preprint_three._id]) + res = app.get('{}{}'.format(date_published_url, preprint_two.date_published), auth=user.auth) actual = set([preprint['id'] for preprint in res.json['data']]) assert expected == actual - def test_is_published_false_filter_equals_returns_one(self): - expected = [self.preprint_three._id] - res = self.app.get('{}{}'.format(self.is_published_url, 'false'), auth=self.user.auth) + def test_is_published_false_filter_equals_returns_one(self, app, user, preprint_three, is_published_url): + expected = [preprint_three._id] + res = app.get('{}{}'.format(is_published_url, 'false'), auth=user.auth) actual = [preprint['id'] for preprint in res.json['data']] assert expected == actual - def test_is_published_true_filter_equals_returns_multiple(self): - expected = set([self.preprint_one._id, self.preprint_two._id]) - res = self.app.get('{}{}'.format(self.is_published_url, 'true'), auth=self.user.auth) + def test_is_published_true_filter_equals_returns_multiple(self, app, user, preprint_one, preprint_two, is_published_url): + expected = set([preprint_one._id, preprint_two._id]) + res = app.get('{}{}'.format(is_published_url, 'true'), auth=user.auth) actual = set([preprint['id'] for preprint in res.json['data']]) assert expected == actual - def test_multiple_filters_returns_one(self): - expected = set([self.preprint_two._id]) - res = self.app.get(self.is_published_and_modified_url, - auth=self.user.auth + def test_multiple_filters_returns_one(self, app, user, preprint_two, is_published_and_modified_url): + expected = set([preprint_two._id]) + res = app.get(is_published_and_modified_url, + auth=user.auth ) actual = set([preprint['id'] for preprint in res.json['data']]) assert expected == actual - def test_subject_filter_using_id(self): - expected = set([self.preprint_one._id, self.preprint_three._id]) - res = self.app.get('{}{}'.format(self.has_subject, self.subject_one._id), - auth=self.user.auth + def test_subject_filter_using_id(self, app, user, subject_one, preprint_one, preprint_three, has_subject): + expected = set([preprint_one._id, preprint_three._id]) + res = app.get('{}{}'.format(has_subject, subject_one._id), + auth=user.auth ) actual = set([preprint['id'] for preprint in res.json['data']]) assert expected == actual - def test_subject_filter_using_text(self): - expected = set([self.preprint_one._id, self.preprint_three._id]) - res = self.app.get('{}{}'.format(self.has_subject, self.subject_one.text), - auth=self.user.auth + def test_subject_filter_using_text(self, app, user, subject_one, preprint_one, preprint_three, has_subject): + expected = set([preprint_one._id, preprint_three._id]) + res = app.get('{}{}'.format(has_subject, subject_one.text), + auth=user.auth ) actual = set([preprint['id'] for preprint in res.json['data']]) assert expected == actual - def test_unknows_subject_filter(self): - res = self.app.get('{}notActuallyASubjectIdOrTestMostLikely'.format(self.has_subject), - auth=self.user.auth + def test_unknows_subject_filter(self, app, user, has_subject): + res = app.get('{}notActuallyASubjectIdOrTestMostLikely'.format(has_subject), + auth=user.auth ) assert len(res.json['data']) == 0 diff --git a/api_tests/preprints/views/test_preprint_list.py b/api_tests/preprints/views/test_preprint_list.py index 2f6cf48178b..a30826bf428 100644 --- a/api_tests/preprints/views/test_preprint_list.py +++ b/api_tests/preprints/views/test_preprint_list.py @@ -1,18 +1,14 @@ -import pytest import mock - from nose.tools import * # flake8: noqa +import pytest from addons.github.models import GithubFile -from framework.auth.core import Auth from api.base.settings.defaults import API_BASE +from api_tests import utils as test_utils from api_tests.preprints.filters.test_filters import PreprintsListFilteringMixin from api_tests.preprints.views.test_preprint_list_mixin import PreprintIsPublishedListMixin, PreprintIsValidListMixin -from website.util import permissions +from framework.auth.core import Auth from osf.models import PreprintService, Node -from website.project import signals as project_signals -from tests.base import ApiTestCase, capture_signals -from api_tests import utils as test_utils from osf_tests.factories import ( ProjectFactory, PreprintFactory, @@ -20,6 +16,9 @@ SubjectFactory, PreprintProviderFactory ) +from tests.base import ApiTestCase, capture_signals +from website.project import signals as project_signals +from website.util import permissions def build_preprint_create_payload(node_id=None, provider_id=None, file_id=None, attrs={}): payload = { @@ -77,27 +76,46 @@ def test_exclude_nodes_from_preprints_endpoint(self): assert_not_in(self.project._id, ids) class TestPreprintsListFiltering(PreprintsListFilteringMixin): - @pytest.fixture(autouse=True) - def setUp(self): - self.mock_change_identifier = mock.patch('website.identifiers.client.EzidClient.change_status_identifier') - self.mock_change_identifier.start() - self.user = AuthUserFactory() - self.provider_one = PreprintProviderFactory(name='Sockarxiv') - self.provider_two = PreprintProviderFactory(name='Piratearxiv') - self.provider_three = self.provider_one - self.project_one = ProjectFactory(creator=self.user) - self.project_two = ProjectFactory(creator=self.user) - self.project_three = ProjectFactory(creator=self.user) - self.url = '/{}preprints/?version=2.2&'.format(API_BASE) - super(TestPreprintsListFiltering, self).setUp() - def test_provider_filter_equals_returns_one(self): - expected = [self.preprint_two._id] - res = self.app.get('{}{}'.format(self.provider_url, self.provider_two._id), auth=self.user.auth) + @pytest.fixture() + def user(self): + return AuthUserFactory() + + @pytest.fixture() + def provider_one(self): + return PreprintProviderFactory(name='Sockarxiv') + + @pytest.fixture() + def provider_two(self): + return PreprintProviderFactory(name='Piratearxiv') + + @pytest.fixture() + def provider_three(self, provider_one): + return provider_one + + @pytest.fixture() + def project_one(self, user): + return ProjectFactory(creator=user) + + @pytest.fixture() + def project_two(self, user): + return ProjectFactory(creator=user) + + @pytest.fixture() + def project_three(self, user): + return ProjectFactory(creator=user) + + @pytest.fixture() + def url(self): + return '/{}preprints/?version=2.2&'.format(API_BASE) + + @mock.patch('website.identifiers.client.EzidClient.change_status_identifier') + def test_provider_filter_equals_returns_one(self, mock_change_identifier, app, user, provider_two, preprint_two, provider_url): + expected = [preprint_two._id] + res = app.get('{}{}'.format(provider_url, provider_two._id), auth=user.auth) actual = [preprint['id'] for preprint in res.json['data']] assert expected == actual - class TestPreprintCreate(ApiTestCase): def setUp(self): super(TestPreprintCreate, self).setUp() diff --git a/api_tests/users/views/test_user_preprints_list.py b/api_tests/users/views/test_user_preprints_list.py index 850897618dd..3c9ca3bb863 100644 --- a/api_tests/users/views/test_user_preprints_list.py +++ b/api_tests/users/views/test_user_preprints_list.py @@ -1,13 +1,10 @@ -import pytest - from nose.tools import * # flake8: noqa +import pytest -from tests.base import ApiTestCase -from osf.models import PreprintService, Node -from website.util import permissions from api.base.settings.defaults import API_BASE from api_tests.preprints.filters.test_filters import PreprintsListFilteringMixin from api_tests.preprints.views.test_preprint_list_mixin import PreprintIsPublishedListMixin, PreprintIsValidListMixin +from osf.models import PreprintService, Node from osf_tests.factories import ( ProjectFactory, PreprintFactory, @@ -15,6 +12,8 @@ SubjectFactory, PreprintProviderFactory ) +from tests.base import ApiTestCase +from website.util import permissions class TestUserPreprints(ApiTestCase): @@ -72,25 +71,45 @@ def test_get_projects_logged_in_as_different_user(self): assert_not_in(self.private_project._id, ids) class TestUserPreprintsListFiltering(PreprintsListFilteringMixin): - @pytest.fixture(autouse=True) - def setUp(self): - self.user = AuthUserFactory() - self.provider_one = PreprintProviderFactory(name='Sockarxiv') - self.provider_two = PreprintProviderFactory(name='Piratearxiv') - self.provider_three = self.provider_one - self.project_one = ProjectFactory(creator=self.user) - self.project_two = ProjectFactory(creator=self.user) - self.project_three = ProjectFactory(creator=self.user) - self.url = '/{}users/{}/preprints/?version=2.2&'.format(API_BASE, self.user._id) - super(TestUserPreprintsListFiltering, self).setUp() - - def test_provider_filter_equals_returns_one(self): - expected = [self.preprint_two._id] - res = self.app.get('{}{}'.format(self.provider_url, self.provider_two._id), auth=self.user.auth) + + @pytest.fixture() + def user(self): + return AuthUserFactory() + + @pytest.fixture() + def provider_one(self): + return PreprintProviderFactory(name='Sockarxiv') + + @pytest.fixture() + def provider_two(self): + return PreprintProviderFactory(name='Piratearxiv') + + @pytest.fixture() + def provider_three(self, provider_one): + return provider_one + + @pytest.fixture() + def project_one(self, user): + return ProjectFactory(creator=user) + + @pytest.fixture() + def project_two(self, user): + return ProjectFactory(creator=user) + + @pytest.fixture() + def project_three(self, user): + return ProjectFactory(creator=user) + + @pytest.fixture() + def url(self, user): + return '/{}users/{}/preprints/?version=2.2&'.format(API_BASE, user._id) + + def test_provider_filter_equals_returns_one(self, app, user, provider_two, preprint_two, provider_url): + expected = [preprint_two._id] + res = app.get('{}{}'.format(provider_url, provider_two._id), auth=user.auth) actual = [preprint['id'] for preprint in res.json['data']] assert expected == actual - class TestUserPreprintIsPublishedList(PreprintIsPublishedListMixin, ApiTestCase): def setUp(self): self.admin = AuthUserFactory() From fbdc81f5d27276e77d06793caa9e3bbb51fb169a Mon Sep 17 00:00:00 2001 From: Alex Schiller Date: Fri, 9 Jun 2017 15:16:58 -0400 Subject: [PATCH 072/163] Special case checkout banner for preregistration checkouts --- addons/base/views.py | 13 ++++++- website/static/js/filepage/index.js | 44 +++++++++--------------- website/templates/project/view_file.mako | 2 ++ 3 files changed, 30 insertions(+), 29 deletions(-) diff --git a/addons/base/views.py b/addons/base/views.py index 761a76f0c86..94f3a76fbf0 100644 --- a/addons/base/views.py +++ b/addons/base/views.py @@ -748,12 +748,23 @@ def addon_view_file(auth, node, file_node, version): 'file_tags': list(file_node.tags.filter(system=False).values_list('name', flat=True)) if not file_node._state.adding else [], # Only access ManyRelatedManager if saved 'file_guid': file_node.get_guid()._id, 'file_id': file_node._id, - 'allow_comments': file_node.provider in settings.ADDONS_COMMENTABLE + 'allow_comments': file_node.provider in settings.ADDONS_COMMENTABLE, + 'checkout_user': file_node.checkout._id if file_node.checkout else None, + 'pre_reg_checkout': is_pre_reg_checkout(node, file_node), }) ret.update(rubeus.collect_addon_assets(node)) return ret +def is_pre_reg_checkout(node, file_node): + checkout_user = file_node.checkout + if not checkout_user: + return False + if checkout_user in node.contributors: + return False + if checkout_user.has_perm('osf.prereg_view'): + return node.draft_registrations_active.filter(registration_schema__name='Prereg Challenge').exists() + return False def get_archived_from_url(node, file_node): if file_node.copied_from: diff --git a/website/static/js/filepage/index.js b/website/static/js/filepage/index.js index eb683aa9be9..cc0a4b0bae0 100644 --- a/website/static/js/filepage/index.js +++ b/website/static/js/filepage/index.js @@ -114,42 +114,29 @@ var FileViewPage = { self.file = self.context.file; self.node = self.context.node; self.editorMeta = self.context.editor; - self.file.checkoutUser = null; self.requestDone = false; self.isLatestVersion = false; self.selectLatest = function() { self.isLatestVersion = true; }; - - self.isCheckoutUser = function() { - $.ajax({ - headers: { - 'Accept': 'application/json', - 'Content-Type': 'application/vnd.api+json' - }, - method: 'get', - url: window.contextVars.apiV2Prefix + 'files' + self.file.path + '/', - beforeSend: $osf.setXHRAuthorization - }).done(function(resp) { - self.requestDone = true; - self.file.checkoutUser = resp.data.relationships.checkout ? ((resp.data.relationships.checkout.links.related.href).split('users/')[1]).replace('/', ''): null; - if ((self.file.checkoutUser) && (self.file.checkoutUser !== self.context.currentUser.id)) { - m.render(document.getElementById('alertBar'), m('.alert.alert-warning[role="alert"]', m('span', [ - m('strong', 'File is checked out.'), - ' This file has been checked out by a ', - m('a[href="/' + self.file.checkoutUser + '"]', 'collaborator'), - '. It needs to be checked in before any changes can be made.' - ]))); - } - self.enableEditing(); - }); - }; - if (self.file.provider === 'osfstorage'){ + if (self.file.provider === 'osfstorage') { self.canEdit = function() { - return (self.requestDone && ((!self.file.checkoutUser) || (self.file.checkoutUser === self.context.currentUser.id))) ? self.context.currentUser.canEdit : false; + return ((!self.file.checkoutUser) || (self.file.checkoutUser === self.context.currentUser.id)) ? self.context.currentUser.canEdit : false; }; - self.isCheckoutUser(); + if (self.file.isPreregCheckout){ + m.render(document.getElementById('alertBar'), m('.alert.alert-warning[role="alert"]', m('span', [ + m('strong', 'File is checked out.'), + ' This file has been checked out by a COS Preregistration Challenge Reviewer. It needs to be checked in before any changes can be made.', + ]))); + } else if ((self.file.checkoutUser) && (self.file.checkoutUser !== self.context.currentUser.id)) { + m.render(document.getElementById('alertBar'), m('.alert.alert-warning[role="alert"]', m('span', [ + m('strong', 'File is checked out.'), + ' This file has been checked out by a ', + m('a[href="/' + self.file.checkoutUser + '"]', 'collaborator'), + '. It needs to be checked in before any changes can be made.' + ]))); + } } else { self.requestDone = true; self.canEdit = function() { @@ -378,6 +365,7 @@ var FileViewPage = { } m.redraw(true); }; + self.enableEditing(); //Hack to polyfill the Panel interface //Ran into problems with mithrils caching messing up with multiple "Panels" diff --git a/website/templates/project/view_file.mako b/website/templates/project/view_file.mako index 8149c42efe2..bba0e5fbe54 100644 --- a/website/templates/project/view_file.mako +++ b/website/templates/project/view_file.mako @@ -203,6 +203,8 @@ file_tags: ${file_tags if file_tags else False| sjson, n}, guid: ${file_guid | sjson, n}, id: ${file_id | sjson, n}, + checkoutUser: ${checkout_user | sjson, n}, + isPreregCheckout: ${pre_reg_checkout | sjson, n}, urls: { %if error is None: render: ${ urls['render'] | sjson, n }, From b834b6431ae678928dd867762aec35025e6d4bab Mon Sep 17 00:00:00 2001 From: Fabrice Mizero Date: Fri, 9 Jun 2017 16:34:48 -0400 Subject: [PATCH 073/163] Show error msg on signup unchecked recaptcha --- website/static/js/passwordForms.js | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/website/static/js/passwordForms.js b/website/static/js/passwordForms.js index 934d5db27db..6a1b2d29875 100644 --- a/website/static/js/passwordForms.js +++ b/website/static/js/passwordForms.js @@ -295,11 +295,10 @@ var SignUpViewModel = oop.extend(BaseViewModel, { if ($('.g-recaptcha').length !== 0) { var captchaResponse = $('#g-recaptcha-response').val(); if (captchaResponse.length === 0) { - $osf.growl('Error','Please complete reCAPTCHA.'); - // self.changeMessage( - // 'Please complete reCAPTCHA', - // 'text-danger p-xs' - // ); + self.changeMessage( + 'Please complete reCAPTCHA', + 'text-danger p-xs' + ); return false; } $.extend(payload, {'g-recaptcha-response': captchaResponse}); From 8459ea91691e327f635ea2ab90e7a5a0e2c8b8e4 Mon Sep 17 00:00:00 2001 From: Rheisen Dennis Date: Mon, 12 Jun 2017 13:06:05 -0400 Subject: [PATCH 074/163] pytest conversion of test_node_wiki_list.py --- api_tests/nodes/views/test_node_wiki_list.py | 391 ++++++++++--------- 1 file changed, 215 insertions(+), 176 deletions(-) diff --git a/api_tests/nodes/views/test_node_wiki_list.py b/api_tests/nodes/views/test_node_wiki_list.py index fe8c865134a..8ad6c785b80 100644 --- a/api_tests/nodes/views/test_node_wiki_list.py +++ b/api_tests/nodes/views/test_node_wiki_list.py @@ -1,205 +1,244 @@ -# -*- coding: utf-8 -*- import mock -from nose.tools import * # flake8: noqa +import pytest -from api.base.settings.defaults import API_BASE - -from tests.base import ApiWikiTestCase, ApiTestCase -from osf_tests.factories import AuthUserFactory, ProjectFactory, RegistrationFactory from addons.wiki.tests.factories import NodeWikiFactory - - -class TestNodeWikiList(ApiWikiTestCase): - - def _set_up_public_project_with_wiki_page(self): - self.public_project = ProjectFactory(is_public=True, creator=self.user) - self.public_wiki = self._add_project_wiki_page(self.public_project, self.user) - self.public_url = '/{}nodes/{}/wikis/'.format(API_BASE, self.public_project._id) - - def _set_up_private_project_with_wiki_page(self): - self.private_project = ProjectFactory(creator=self.user) - self.private_wiki = self._add_project_wiki_page(self.private_project, self.user) - self.private_url = '/{}nodes/{}/wikis/'.format(API_BASE, self.private_project._id) - - def _set_up_public_registration_with_wiki_page(self): - self._set_up_public_project_with_wiki_page() - self.public_registration = RegistrationFactory(project=self.public_project, user=self.user, is_public=True) - self.public_registration_wiki_id = self.public_registration.wiki_pages_versions['home'][0] - self.public_registration.wiki_pages_current = {'home': self.public_registration_wiki_id} - self.public_registration.save() - self.public_registration_url = '/{}registrations/{}/wikis/'.format(API_BASE, self.public_registration._id) - - def _set_up_registration_with_wiki_page(self): - self._set_up_private_project_with_wiki_page() - self.registration = RegistrationFactory(project=self.private_project, user=self.user) - self.registration_wiki_id = self.registration.wiki_pages_versions['home'][0] - self.registration.wiki_pages_current = {'home': self.registration_wiki_id} - self.registration.save() - self.registration_url = '/{}registrations/{}/wikis/'.format(API_BASE, self.registration._id) - - def test_return_public_node_wikis_logged_out_user(self): - self._set_up_public_project_with_wiki_page() - res = self.app.get(self.public_url) - assert_equal(res.status_code, 200) +from api.base.settings.defaults import API_BASE +from osf_tests.factories import ( + AuthUserFactory, + ProjectFactory, + RegistrationFactory, +) +from rest_framework import exceptions + +@pytest.fixture() +def user(): + return AuthUserFactory() + +@pytest.mark.django_db +class TestNodeWikiList: + + @pytest.fixture() + def add_project_wiki_page(self): + def add_page(node, user): + with mock.patch('osf.models.AbstractNode.update_search'): + return NodeWikiFactory(node=node, user=user) + return add_page + + @pytest.fixture() + def non_contrib(self): + return AuthUserFactory() + + @pytest.fixture() + def public_project(self, user): + return ProjectFactory(is_public=True, creator=user) + + @pytest.fixture() + def public_wiki(self, add_project_wiki_page, user, public_project): + return add_project_wiki_page(public_project, user) + + @pytest.fixture() + def public_url(self, public_project, public_wiki): + return '/{}nodes/{}/wikis/'.format(API_BASE, public_project._id) + + @pytest.fixture() + def private_project(self, user): + return ProjectFactory(creator=user) + + @pytest.fixture() + def private_wiki(self, add_project_wiki_page, user, private_project): + return add_project_wiki_page(private_project, user) + + @pytest.fixture() + def private_url(self, private_project, private_wiki): + return '/{}nodes/{}/wikis/'.format(API_BASE, private_project._id) + + @pytest.fixture() + def public_registration(self, user, public_project, public_wiki): + public_registration = RegistrationFactory(project=public_project, user=user, is_public=True) + wiki_id = public_registration.wiki_pages_versions['home'][0] + public_registration.wiki_pages_current = {'home': wiki_id} + public_registration.save() + return public_registration + + @pytest.fixture() + def public_registration_url(self, public_registration): + return '/{}registrations/{}/wikis/'.format(API_BASE, public_registration._id) + + @pytest.fixture() + def private_registration(self, user, private_project, private_wiki): + private_registration = RegistrationFactory(project=private_project, user=user) + wiki_id = private_registration.wiki_pages_versions['home'][0] + private_registration.wiki_pages_current = {'home': wiki_id} + private_registration.save() + return private_registration + + @pytest.fixture() + def private_registration_url(self, private_registration): + return '/{}registrations/{}/wikis/'.format(API_BASE, private_registration._id) + + def test_return_wikis(self, app, user, non_contrib, private_registration, public_wiki, private_wiki, public_url, private_url, private_registration_url): + + # test_return_public_node_wikis_logged_out_user + res = app.get(public_url) + assert res.status_code == 200 wiki_ids = [wiki['id'] for wiki in res.json['data']] - assert_in(self.public_wiki._id, wiki_ids) + assert public_wiki._id in wiki_ids - def test_return_public_node_wikis_logged_in_non_contributor(self): - self._set_up_public_project_with_wiki_page() - res = self.app.get(self.public_url, auth=self.non_contributor.auth) - assert_equal(res.status_code, 200) + # test_return_public_node_wikis_logged_in_non_contributor + res = app.get(public_url, auth=non_contrib.auth) + assert res.status_code == 200 wiki_ids = [wiki['id'] for wiki in res.json['data']] - assert_in(self.public_wiki._id, wiki_ids) + assert public_wiki._id in wiki_ids - def test_return_public_node_wikis_logged_in_contributor(self): - self._set_up_public_project_with_wiki_page() - res = self.app.get(self.public_url, auth=self.user.auth) - assert_equal(res.status_code, 200) + # test_return_public_node_wikis_logged_in_contributor + res = app.get(public_url, auth=user.auth) + assert res.status_code == 200 wiki_ids = [wiki['id'] for wiki in res.json['data']] - assert_in(self.public_wiki._id, wiki_ids) - - def test_return_private_node_wikis_logged_out_user(self): - self._set_up_private_project_with_wiki_page() - res = self.app.get(self.private_url, expect_errors=True) - assert_equal(res.status_code, 401) - assert_equal(res.json['errors'][0]['detail'], 'Authentication credentials were not provided.') - - def test_return_private_node_wikis_logged_in_non_contributor(self): - self._set_up_private_project_with_wiki_page() - res = self.app.get(self.private_url, auth=self.non_contributor.auth, expect_errors=True) - assert_equal(res.status_code, 403) - assert_equal(res.json['errors'][0]['detail'], 'You do not have permission to perform this action.') - - def test_return_private_node_wikis_logged_in_contributor(self): - self._set_up_private_project_with_wiki_page() - res = self.app.get(self.private_url, auth=self.user.auth) - assert_equal(res.status_code, 200) + assert public_wiki._id in wiki_ids + + # test_return_private_node_wikis_logged_out_user + res = app.get(private_url, expect_errors=True) + assert res.status_code == 401 + assert res.json['errors'][0]['detail'] == exceptions.NotAuthenticated.default_detail + + # test_return_private_node_wikis_logged_in_non_contributor + res = app.get(private_url, auth=non_contrib.auth, expect_errors=True) + assert res.status_code == 403 + assert res.json['errors'][0]['detail'] == exceptions.PermissionDenied.default_detail + + # test_return_private_node_wikis_logged_in_contributor + res = app.get(private_url, auth=user.auth) + assert res.status_code == 200 wiki_ids = [wiki['id'] for wiki in res.json['data']] - assert_in(self.private_wiki._id, wiki_ids) - - def test_return_registration_wikis_logged_out_user(self): - self._set_up_registration_with_wiki_page() - res = self.app.get(self.registration_url, expect_errors=True) - assert_equal(res.status_code, 401) - assert_equal(res.json['errors'][0]['detail'], 'Authentication credentials were not provided.') - - def test_return_registration_wikis_logged_in_non_contributor(self): - self._set_up_registration_with_wiki_page() - res = self.app.get(self.registration_url, auth=self.non_contributor.auth, expect_errors=True) - assert_equal(res.status_code, 403) - assert_equal(res.json['errors'][0]['detail'], 'You do not have permission to perform this action.') - - def test_return_registration_wikis_logged_in_contributor(self): - self._set_up_registration_with_wiki_page() - res = self.app.get(self.registration_url, auth=self.user.auth) - assert_equal(res.status_code, 200) + assert private_wiki._id in wiki_ids + + # test_return_registration_wikis_logged_out_user + res = app.get(private_registration_url, expect_errors=True) + assert res.status_code == 401 + assert res.json['errors'][0]['detail'] == exceptions.NotAuthenticated.default_detail + + # test_return_registration_wikis_logged_in_non_contributor + res = app.get(private_registration_url, auth=non_contrib.auth, expect_errors=True) + assert res.status_code == 403 + assert res.json['errors'][0]['detail'] == exceptions.PermissionDenied.default_detail + + # test_return_registration_wikis_logged_in_contributor + res = app.get(private_registration_url, auth=user.auth) + assert res.status_code == 200 wiki_ids = [wiki['id'] for wiki in res.json['data']] - assert_in(self.registration_wiki_id, wiki_ids) + assert private_registration.wiki_pages_versions['home'][0] in wiki_ids - def test_wikis_not_returned_for_withdrawn_registration(self): - self._set_up_registration_with_wiki_page() - self.registration.is_public = True - withdrawal = self.registration.retract_registration(user=self.user, save=True) + def test_wikis_not_returned_for_withdrawn_registration(self, app, user, private_registration, private_registration_url): + private_registration.is_public = True + withdrawal = private_registration.retract_registration(user=user, save=True) token = withdrawal.approval_state.values()[0]['approval_token'] # TODO: Remove mocking when StoredFileNode is implemented with mock.patch('osf.models.AbstractNode.update_search'): - withdrawal.approve_retraction(self.user, token) + withdrawal.approve_retraction(user, token) withdrawal.save() - res = self.app.get(self.registration_url, auth=self.user.auth, expect_errors=True) - assert_equal(res.status_code, 403) - assert_equal(res.json['errors'][0]['detail'], 'You do not have permission to perform this action.') - - def test_public_node_wikis_relationship_links(self): - self._set_up_public_project_with_wiki_page() - res = self.app.get(self.public_url) - expected_nodes_relationship_url = '{}nodes/{}/'.format(API_BASE, self.public_project._id) - expected_comments_relationship_url = '{}nodes/{}/comments/'.format(API_BASE, self.public_project._id) - assert_in(expected_nodes_relationship_url, res.json['data'][0]['relationships']['node']['links']['related']['href']) - assert_in(expected_comments_relationship_url, res.json['data'][0]['relationships']['comments']['links']['related']['href']) - - def test_private_node_wikis_relationship_links(self): - self._set_up_private_project_with_wiki_page() - res = self.app.get(self.private_url, auth=self.user.auth) - expected_nodes_relationship_url = '{}nodes/{}/'.format(API_BASE, self.private_project._id) - expected_comments_relationship_url = '{}nodes/{}/comments/'.format(API_BASE, self.private_project._id) - assert_in(expected_nodes_relationship_url, res.json['data'][0]['relationships']['node']['links']['related']['href']) - assert_in(expected_comments_relationship_url, res.json['data'][0]['relationships']['comments']['links']['related']['href']) - - def test_public_registration_wikis_relationship_links(self): - self._set_up_public_registration_with_wiki_page() - res = self.app.get(self.public_registration_url) - expected_nodes_relationship_url = '{}registrations/{}/'.format(API_BASE, self.public_registration._id) - expected_comments_relationship_url = '{}registrations/{}/comments/'.format(API_BASE, self.public_registration._id) - assert_in(expected_nodes_relationship_url, res.json['data'][0]['relationships']['node']['links']['related']['href']) - assert_in(expected_comments_relationship_url, res.json['data'][0]['relationships']['comments']['links']['related']['href']) - - def test_private_registration_wikis_relationship_links(self): - self._set_up_registration_with_wiki_page() - res = self.app.get(self.registration_url, auth=self.user.auth) - expected_nodes_relationship_url = '{}registrations/{}/'.format(API_BASE, self.registration._id) - expected_comments_relationship_url = '{}registrations/{}/comments/'.format(API_BASE, self.registration._id) - assert_in(expected_nodes_relationship_url, res.json['data'][0]['relationships']['node']['links']['related']['href']) - assert_in(expected_comments_relationship_url, res.json['data'][0]['relationships']['comments']['links']['related']['href']) - - def test_registration_wikis_not_returned_from_nodes_endpoint(self): - self._set_up_public_project_with_wiki_page() - self._set_up_public_registration_with_wiki_page() - res = self.app.get(self.public_url) + res = app.get(private_registration_url, auth=user.auth, expect_errors=True) + assert res.status_code == 403 + assert res.json['errors'][0]['detail'] == exceptions.PermissionDenied.default_detail + + def test_relationship_links(self, app, user, public_project, private_project, public_registration, private_registration, public_url, private_url, public_registration_url, private_registration_url): + + # test_public_node_wikis_relationship_links + res = app.get(public_url) + expected_nodes_relationship_url = '{}nodes/{}/'.format(API_BASE, public_project._id) + expected_comments_relationship_url = '{}nodes/{}/comments/'.format(API_BASE, public_project._id) + assert expected_nodes_relationship_url in res.json['data'][0]['relationships']['node']['links']['related']['href'] + assert expected_comments_relationship_url in res.json['data'][0]['relationships']['comments']['links']['related']['href'] + + # test_private_node_wikis_relationship_links + res = app.get(private_url, auth=user.auth) + expected_nodes_relationship_url = '{}nodes/{}/'.format(API_BASE, private_project._id) + expected_comments_relationship_url = '{}nodes/{}/comments/'.format(API_BASE, private_project._id) + assert expected_nodes_relationship_url in res.json['data'][0]['relationships']['node']['links']['related']['href'] + assert expected_comments_relationship_url in res.json['data'][0]['relationships']['comments']['links']['related']['href'] + + # test_public_registration_wikis_relationship_links + res = app.get(public_registration_url) + expected_nodes_relationship_url = '{}registrations/{}/'.format(API_BASE, public_registration._id) + expected_comments_relationship_url = '{}registrations/{}/comments/'.format(API_BASE, public_registration._id) + assert expected_nodes_relationship_url in res.json['data'][0]['relationships']['node']['links']['related']['href'] + assert expected_comments_relationship_url in res.json['data'][0]['relationships']['comments']['links']['related']['href'] + + # test_private_registration_wikis_relationship_links + res = app.get(private_registration_url, auth=user.auth) + expected_nodes_relationship_url = '{}registrations/{}/'.format(API_BASE, private_registration._id) + expected_comments_relationship_url = '{}registrations/{}/comments/'.format(API_BASE, private_registration._id) + assert expected_nodes_relationship_url in res.json['data'][0]['relationships']['node']['links']['related']['href'] + assert expected_comments_relationship_url in res.json['data'][0]['relationships']['comments']['links']['related']['href'] + + def test_not_returned(self, app, public_project, public_registration, public_url, public_registration_url): + + # test_registration_wikis_not_returned_from_nodes_endpoint + res = app.get(public_url) node_relationships = [ node_wiki['relationships']['node']['links']['related']['href'] for node_wiki in res.json['data'] ] - assert_equal(res.status_code, 200) - assert_equal(len(node_relationships), 1) - assert_in(self.public_project._id, node_relationships[0]) - - def test_node_wikis_not_returned_from_registrations_endpoint(self): - self._set_up_public_project_with_wiki_page() - self._set_up_public_registration_with_wiki_page() - res = self.app.get(self.public_registration_url) + assert res.status_code == 200 + assert len(node_relationships) == 1 + assert public_project._id in node_relationships[0] + + # test_node_wikis_not_returned_from_registrations_endpoint + res = app.get(public_registration_url) node_relationships = [ node_wiki['relationships']['node']['links']['related']['href'] for node_wiki in res.json['data'] ] - assert_equal(res.status_code, 200) - assert_equal(len(node_relationships), 1) - assert_in(self.public_registration._id, node_relationships[0]) + assert res.status_code == 200 + assert len(node_relationships) == 1 + assert public_registration._id in node_relationships[0] + + +@pytest.mark.django_db +class TestFilterNodeWikiList: + @pytest.fixture() + def private_project(self, user): + return ProjectFactory(creator=user) -class TestFilterNodeWikiList(ApiTestCase): + @pytest.fixture() + def base_url(self, private_project): + return '/{}nodes/{}/wikis/'.format(API_BASE, private_project._id) - def setUp(self): - super(TestFilterNodeWikiList, self).setUp() - self.user = AuthUserFactory() - self.project = ProjectFactory(creator=self.user) - self.base_url = '/{}nodes/{}/wikis/'.format(API_BASE, self.project._id) + @pytest.fixture() + def wiki(self, user, private_project): # TODO: Remove mocking when StoredFileNode is implemented with mock.patch('osf.models.AbstractNode.update_search'): - self.wiki = NodeWikiFactory(node=self.project, user=self.user) - self.date = self.wiki.date.strftime('%Y-%m-%dT%H:%M:%S.%f') + return NodeWikiFactory(node=private_project, user=user) - def test_node_wikis_with_no_filter_returns_all(self): - res = self.app.get(self.base_url, auth=self.user.auth) - wiki_ids = [wiki['id'] for wiki in res.json['data']] - assert_in(self.wiki._id, wiki_ids) - - def test_filter_wikis_by_page_name(self): - url = self.base_url + '?filter[name]=home' - res = self.app.get(url, auth=self.user.auth) - assert_equal(len(res.json['data']), 1) - assert_equal(res.json['data'][0]['attributes']['name'], 'home') - - def test_filter_wikis_modified_on_date(self): - url = self.base_url + '?filter[date_modified][eq]={}'.format(self.date) - res = self.app.get(url, auth=self.user.auth) - assert_equal(len(res.json['data']), 1) - - def test_filter_wikis_modified_before_date(self): - url = self.base_url + '?filter[date_modified][lt]={}'.format(self.date) - res = self.app.get(url, auth=self.user.auth) - assert_equal(len(res.json['data']), 0) - - def test_filter_wikis_modified_after_date(self): - url = self.base_url + '?filter[date_modified][gt]={}'.format(self.date) - res = self.app.get(url, auth=self.user.auth) - assert_equal(len(res.json['data']), 0) + @pytest.fixture() + def date(self, wiki): + return wiki.date.strftime('%Y-%m-%dT%H:%M:%S.%f') + + def test_filter_node_wiki_list(self, app, user, wiki, date, base_url): + + # test_node_wikis_with_no_filter_returns_all + res = app.get(base_url, auth=user.auth) + wiki_ids = [item['id'] for item in res.json['data']] + + assert wiki._id in wiki_ids + + # test_filter_wikis_by_page_name + url = base_url + '?filter[name]=home' + res = app.get(url, auth=user.auth) + assert len(res.json['data']) == 1 + assert res.json['data'][0]['attributes']['name'] == 'home' + + # test_filter_wikis_modified_on_date + url = base_url + '?filter[date_modified][eq]={}'.format(date) + res = app.get(url, auth=user.auth) + assert len(res.json['data']) == 1 + + # test_filter_wikis_modified_before_date + url = base_url + '?filter[date_modified][lt]={}'.format(date) + res = app.get(url, auth=user.auth) + assert len(res.json['data']) == 0 + + # test_filter_wikis_modified_after_date + url = base_url + '?filter[date_modified][gt]={}'.format(date) + res = app.get(url, auth=user.auth) + assert len(res.json['data']) == 0 From 83c060f621d576526c292f5761e85b32ff9f9f4e Mon Sep 17 00:00:00 2001 From: Alex Schiller Date: Mon, 12 Jun 2017 14:03:14 -0400 Subject: [PATCH 075/163] Move enableEditing button, remove requestDone --- website/static/js/filepage/index.js | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/website/static/js/filepage/index.js b/website/static/js/filepage/index.js index cc0a4b0bae0..1df2c6c354d 100644 --- a/website/static/js/filepage/index.js +++ b/website/static/js/filepage/index.js @@ -114,7 +114,6 @@ var FileViewPage = { self.file = self.context.file; self.node = self.context.node; self.editorMeta = self.context.editor; - self.requestDone = false; self.isLatestVersion = false; self.selectLatest = function() { @@ -138,7 +137,6 @@ var FileViewPage = { ]))); } } else { - self.requestDone = true; self.canEdit = function() { return self.context.currentUser.canEdit; }; @@ -365,7 +363,6 @@ var FileViewPage = { } m.redraw(true); }; - self.enableEditing(); //Hack to polyfill the Panel interface //Ran into problems with mithrils caching messing up with multiple "Panels" @@ -421,6 +418,7 @@ var FileViewPage = { changeVersionHeader(); } + self.enableEditing() }, view: function(ctrl) { //This code was abstracted into a panel toggler at one point @@ -497,18 +495,17 @@ var FileViewPage = { (ctrl.node.preprintFileId !== ctrl.file.id) && !(ctrl.file.provider === 'figshare' && ctrl.file.extra.status === 'public') && (ctrl.file.provider !== 'osfstorage' || !ctrl.file.checkoutUser) && - ctrl.requestDone && ($(document).context.URL.indexOf('version=latest-published') < 0) ) ? m('.btn-group.m-l-xs.m-t-xs', [ ctrl.isLatestVersion ? m('button.btn.btn-sm.btn-danger.file-delete', {onclick: $(document).trigger.bind($(document), 'fileviewpage:delete') }, 'Delete') : null ]) : '', - ctrl.context.currentUser.canEdit && (!ctrl.canEdit()) && ctrl.requestDone && (ctrl.context.currentUser.isAdmin) ? m('.btn-group.m-l-xs.m-t-xs', [ + ctrl.context.currentUser.canEdit && (!ctrl.canEdit()) && (ctrl.context.currentUser.isAdmin) ? m('.btn-group.m-l-xs.m-t-xs', [ ctrl.isLatestVersion ? m('.btn.btn-sm.btn-danger', {onclick: $(document).trigger.bind($(document), 'fileviewpage:force_checkin')}, 'Force check in') : null ]) : '', - ctrl.canEdit() && (!ctrl.file.checkoutUser) && ctrl.requestDone && (ctrl.file.provider === 'osfstorage') ? m('.btn-group.m-l-xs.m-t-xs', [ + ctrl.canEdit() && (!ctrl.file.checkoutUser) && (ctrl.file.provider === 'osfstorage') ? m('.btn-group.m-l-xs.m-t-xs', [ ctrl.isLatestVersion ? m('.btn.btn-sm.btn-warning', {onclick: $(document).trigger.bind($(document), 'fileviewpage:checkout')}, 'Check out') : null ]) : '', - (ctrl.canEdit() && (ctrl.file.checkoutUser === ctrl.context.currentUser.id) && ctrl.requestDone) ? m('.btn-group.m-l-xs.m-t-xs', [ + (ctrl.canEdit() && (ctrl.file.checkoutUser === ctrl.context.currentUser.id) ) ? m('.btn-group.m-l-xs.m-t-xs', [ ctrl.isLatestVersion ? m('.btn.btn-sm.btn-warning', {onclick: $(document).trigger.bind($(document), 'fileviewpage:checkin')}, 'Check in') : null ]) : '', window.contextVars.node.isPublic? m('.btn-group.m-t-xs', [ From 9611410e55021bd1615897252bc918df9b064b6b Mon Sep 17 00:00:00 2001 From: Alex Schiller Date: Mon, 12 Jun 2017 14:20:01 -0400 Subject: [PATCH 076/163] semicolon --- website/static/js/filepage/index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/website/static/js/filepage/index.js b/website/static/js/filepage/index.js index 1df2c6c354d..3526e18d00d 100644 --- a/website/static/js/filepage/index.js +++ b/website/static/js/filepage/index.js @@ -418,7 +418,7 @@ var FileViewPage = { changeVersionHeader(); } - self.enableEditing() + self.enableEditing(); }, view: function(ctrl) { //This code was abstracted into a panel toggler at one point From a5f00c0f1ed8f8ac3ebc9b142d2bd9090dbe385f Mon Sep 17 00:00:00 2001 From: Rheisen Dennis Date: Mon, 12 Jun 2017 16:13:55 -0400 Subject: [PATCH 077/163] pytest conversion of test_node_relationship_institutions.py --- .../test_node_relationship_institutions.py | 662 +++++++++--------- 1 file changed, 346 insertions(+), 316 deletions(-) diff --git a/api_tests/nodes/views/test_node_relationship_institutions.py b/api_tests/nodes/views/test_node_relationship_institutions.py index 731aa22c45c..8c635481c23 100644 --- a/api_tests/nodes/views/test_node_relationship_institutions.py +++ b/api_tests/nodes/views/test_node_relationship_institutions.py @@ -1,472 +1,502 @@ -from nose.tools import * # flake8: noqa - -from tests.base import ApiTestCase -from osf_tests.factories import InstitutionFactory, AuthUserFactory, NodeFactory +import pytest from api.base.settings.defaults import API_BASE - +from osf_tests.factories import ( + InstitutionFactory, + AuthUserFactory, + NodeFactory, +) from website.util import permissions +@pytest.mark.django_db +class TestNodeRelationshipInstitutions: -class TestNodeRelationshipInstitutions(ApiTestCase): - - def setUp(self): - super(TestNodeRelationshipInstitutions, self).setUp() - - self.institution2 = InstitutionFactory() - self.institution1 = InstitutionFactory() - - self.user = AuthUserFactory() - self.user.affiliated_institutions.add(self.institution1) - self.user.affiliated_institutions.add(self.institution2) - self.user.save() - - self.read_write_contributor = AuthUserFactory() - self.read_write_contributor_institution = InstitutionFactory() - self.read_write_contributor.affiliated_institutions.add(self.read_write_contributor_institution) - self.read_write_contributor.save() + @pytest.fixture() + def institution_one(self): + return InstitutionFactory() - self.read_only_contributor = AuthUserFactory() - self.read_only_contributor_institution = InstitutionFactory() - self.read_only_contributor.affiliated_institutions.add(self.read_only_contributor_institution) - self.read_only_contributor.save() + @pytest.fixture() + def institution_two(self): + return InstitutionFactory() - self.node = NodeFactory(creator=self.user) - self.node.add_contributor(self.read_write_contributor, permissions=[permissions.WRITE]) - self.node.add_contributor(self.read_only_contributor, permissions=[permissions.READ]) - self.node.save() + @pytest.fixture() + def write_contrib_institution(self): + return InstitutionFactory() - self.node_institutions_url = '/{0}nodes/{1}/relationships/institutions/'.format(API_BASE, self.node._id) + @pytest.fixture() + def read_contrib_institution(self): + return InstitutionFactory() - def create_payload(self, *institution_ids): - data = [] - for id_ in institution_ids: - data.append({'type': 'institutions', 'id': id_}) - return {'data': data} - - def test_node_with_no_permissions(self): + @pytest.fixture() + def user(self, institution_one, institution_two): user = AuthUserFactory() - user.affiliated_institutions.add(self.institution1) + user.affiliated_institutions.add(institution_one) + user.affiliated_institutions.add(institution_two) user.save() - res = self.app.put_json_api( - self.node_institutions_url, - self.create_payload([self.institution1._id]), - auth=user.auth, + return user + + @pytest.fixture() + def write_contrib(self, write_contrib_institution): + write_contrib = AuthUserFactory() + write_contrib.affiliated_institutions.add(write_contrib_institution) + write_contrib.save() + return write_contrib + + @pytest.fixture() + def read_contrib(self, read_contrib_institution): + read_contrib = AuthUserFactory() + read_contrib.affiliated_institutions.add(read_contrib_institution) + read_contrib.save() + return read_contrib + + @pytest.fixture() + def node(self, user, write_contrib, read_contrib): + node = NodeFactory(creator=user) + node.add_contributor(write_contrib, permissions=[permissions.WRITE]) + node.add_contributor(read_contrib, permissions=[permissions.READ]) + node.save() + return node + + @pytest.fixture() + def node_institutions_url(self, node): + return '/{0}nodes/{1}/relationships/institutions/'.format(API_BASE, node._id) + + @pytest.fixture() + def create_payload(self): + def payload(*institution_ids): + data = [] + for id_ in institution_ids: + data.append({'type': 'institutions', 'id': id_}) + return {'data': data} + return payload + + def test_node_errors(self, app, user, institution_one, create_payload, node_institutions_url): + + # test_node_with_no_permissions + unauthorized_user = AuthUserFactory() + unauthorized_user.affiliated_institutions.add(institution_one) + unauthorized_user.save() + res = app.put_json_api( + node_institutions_url, + create_payload([institution_one._id]), + auth=unauthorized_user.auth, expect_errors=True, ) - assert_equal(res.status_code, 403) + assert res.status_code == 403 - def test_user_with_no_institution(self): - user = AuthUserFactory() - node = NodeFactory(creator=user) - res = self.app.put_json_api( + # test_user_with_no_institution + unauthorized_user = AuthUserFactory() + node = NodeFactory(creator=unauthorized_user) + res = app.put_json_api( '/{0}nodes/{1}/relationships/institutions/'.format(API_BASE, node._id), - self.create_payload(self.institution1._id), + create_payload(institution_one._id), + expect_errors=True, + auth=unauthorized_user.auth + ) + assert res.status_code == 403 + + # test_institution_does_not_exist + res = app.put_json_api( + node_institutions_url, + create_payload('not_an_id'), expect_errors=True, auth=user.auth ) - assert_equal(res.status_code, 403) - def test_get_public_node(self): - self.node.is_public = True - self.node.save() + assert res.status_code == 404 - res = self.app.get( - self.node_institutions_url + # test_wrong_type + res = app.put_json_api( + node_institutions_url, + {'data': [{'type': 'not_institution', 'id': institution_one._id}]}, + expect_errors=True, + auth=user.auth ) - assert_equal(res.status_code, 200) - assert_equal(res.json['data'], []) + assert res.status_code == 409 - def test_institution_does_not_exist(self): - res = self.app.put_json_api( - self.node_institutions_url, - self.create_payload('not_an_id'), - expect_errors=True, - auth=self.user.auth + # test_remove_institutions_with_no_permissions + res = app.put_json_api( + node_institutions_url, + create_payload(), + expect_errors=True ) + assert res.status_code == 401 - assert_equal(res.status_code, 404) + # test_retrieve_private_node_no_auth + res = app.get(node_institutions_url, expect_errors=True) + assert res.status_code == 401 - def test_wrong_type(self): - res = self.app.put_json_api( - self.node_institutions_url, - {'data': [{'type': 'not_institution', 'id': self.institution1._id}]}, - expect_errors=True, - auth=self.user.auth + def test_get_public_node(self, app, node, node_institutions_url): + node.is_public = True + node.save() + + res = app.get( + node_institutions_url ) - assert_equal(res.status_code, 409) + assert res.status_code == 200 + assert res.json['data'] == [] - def test_user_with_institution_and_permissions(self): - assert_not_in(self.institution1, self.node.affiliated_institutions.all()) - assert_not_in(self.institution2, self.node.affiliated_institutions.all()) + def test_user_with_institution_and_permissions(self, app, user, institution_one, institution_two, node, node_institutions_url, create_payload): + assert institution_one not in node.affiliated_institutions.all() + assert institution_two not in node.affiliated_institutions.all() - res = self.app.post_json_api( - self.node_institutions_url, - self.create_payload(self.institution1._id, self.institution2._id), - auth=self.user.auth + res = app.post_json_api( + node_institutions_url, + create_payload(institution_one._id, institution_two._id), + auth=user.auth ) - assert_equal(res.status_code, 201) + assert res.status_code == 201 data = res.json['data'] ret_institutions = [inst['id'] for inst in data] - assert_in(self.institution1._id, ret_institutions) - assert_in(self.institution2._id, ret_institutions) + assert institution_one._id in ret_institutions + assert institution_two._id in ret_institutions - self.node.reload() - assert_in(self.institution1, self.node.affiliated_institutions.all()) - assert_in(self.institution2, self.node.affiliated_institutions.all()) + node.reload() + assert institution_one in node.affiliated_institutions.all() + assert institution_two in node.affiliated_institutions.all() - def test_user_with_institution_and_permissions_through_patch(self): - assert_not_in(self.institution1, self.node.affiliated_institutions.all()) - assert_not_in(self.institution2, self.node.affiliated_institutions.all()) + def test_user_with_institution_and_permissions_through_patch(self, app, user, institution_one, institution_two, node, node_institutions_url, create_payload): + assert institution_one not in node.affiliated_institutions.all() + assert institution_two not in node.affiliated_institutions.all() - res = self.app.put_json_api( - self.node_institutions_url, - self.create_payload(self.institution1._id, self.institution2._id), - auth=self.user.auth + res = app.put_json_api( + node_institutions_url, + create_payload(institution_one._id, institution_two._id), + auth=user.auth ) - assert_equal(res.status_code, 200) + assert res.status_code == 200 data = res.json['data'] ret_institutions = [inst['id'] for inst in data] - assert_in(self.institution1._id, ret_institutions) - assert_in(self.institution2._id, ret_institutions) - - self.node.reload() - assert_in(self.institution1, self.node.affiliated_institutions.all()) - assert_in(self.institution2, self.node.affiliated_institutions.all()) + assert institution_one._id in ret_institutions + assert institution_two._id in ret_institutions - def test_remove_institutions_with_no_permissions(self): - res = self.app.put_json_api( - self.node_institutions_url, - self.create_payload(), - expect_errors=True - ) - assert_equal(res.status_code, 401) + node.reload() + assert institution_one in node.affiliated_institutions.all() + assert institution_two in node.affiliated_institutions.all() - def test_remove_institutions_with_affiliated_user(self): - self.node.affiliated_institutions.add(self.institution1) - self.node.save() - assert_in(self.institution1, self.node.affiliated_institutions.all()) + def test_remove_institutions_with_affiliated_user(self, app, user, institution_one, node, node_institutions_url): + node.affiliated_institutions.add(institution_one) + node.save() + assert institution_one in node.affiliated_institutions.all() - res = self.app.put_json_api( - self.node_institutions_url, + res = app.put_json_api( + node_institutions_url, {'data': []}, - auth=self.user.auth + auth=user.auth ) - assert_equal(res.status_code, 200) - self.node.reload() - assert_equal(self.node.affiliated_institutions.count(), 0) + assert res.status_code == 200 + node.reload() + assert node.affiliated_institutions.count() == 0 - def test_using_post_making_no_changes_returns_204(self): - self.node.affiliated_institutions.add(self.institution1) - self.node.save() - assert_in(self.institution1, self.node.affiliated_institutions.all()) + def test_using_post_making_no_changes_returns_204(self, app, user, institution_one, node, node_institutions_url, create_payload): + node.affiliated_institutions.add(institution_one) + node.save() + assert institution_one in node.affiliated_institutions.all() - res = self.app.post_json_api( - self.node_institutions_url, - self.create_payload(self.institution1._id), - auth=self.user.auth + res = app.post_json_api( + node_institutions_url, + create_payload(institution_one._id), + auth=user.auth ) - assert_equal(res.status_code, 204) - self.node.reload() - assert_in(self.institution1, self.node.affiliated_institutions.all()) + assert res.status_code == 204 + node.reload() + assert institution_one in node.affiliated_institutions.all() - def test_put_not_admin_but_affiliated(self): + def test_put_not_admin_but_affiliated(self, app, institution_one, node, node_institutions_url, create_payload): user = AuthUserFactory() - user.affiliated_institutions.add(self.institution1) + user.affiliated_institutions.add(institution_one) user.save() - self.node.add_contributor(user) - self.node.save() + node.add_contributor(user) + node.save() - res = self.app.put_json_api( - self.node_institutions_url, - self.create_payload(self.institution1._id), + res = app.put_json_api( + node_institutions_url, + create_payload(institution_one._id), auth=user.auth ) - self.node.reload() - assert_equal(res.status_code, 200) - assert_in(self.institution1, self.node.affiliated_institutions.all()) - - def test_retrieve_private_node_no_auth(self): - res = self.app.get(self.node_institutions_url, expect_errors=True) - assert_equal(res.status_code, 401) + node.reload() + assert res.status_code == 200 + assert institution_one in node.affiliated_institutions.all() - def test_add_through_patch_one_inst_to_node_with_inst(self): - self.node.affiliated_institutions.add(self.institution1) - self.node.save() - assert_in(self.institution1, self.node.affiliated_institutions.all()) - assert_not_in(self.institution2, self.node.affiliated_institutions.all()) + def test_add_through_patch_one_inst_to_node_with_inst(self, app, user, institution_one, institution_two, node, node_institutions_url, create_payload): + node.affiliated_institutions.add(institution_one) + node.save() + assert institution_one in node.affiliated_institutions.all() + assert institution_two not in node.affiliated_institutions.all() - res = self.app.patch_json_api( - self.node_institutions_url, - self.create_payload(self.institution1._id, self.institution2._id), - auth=self.user.auth + res = app.patch_json_api( + node_institutions_url, + create_payload(institution_one._id, institution_two._id), + auth=user.auth ) - assert_equal(res.status_code, 200) - self.node.reload() - assert_in(self.institution1, self.node.affiliated_institutions.all()) - assert_in(self.institution2, self.node.affiliated_institutions.all()) - - def test_add_through_patch_one_inst_while_removing_other(self): - self.node.affiliated_institutions.add(self.institution1) - self.node.save() - assert_in(self.institution1, self.node.affiliated_institutions.all()) - assert_not_in(self.institution2, self.node.affiliated_institutions.all()) - - res = self.app.patch_json_api( - self.node_institutions_url, - self.create_payload(self.institution2._id), - auth=self.user.auth + assert res.status_code == 200 + node.reload() + assert institution_one in node.affiliated_institutions.all() + assert institution_two in node.affiliated_institutions.all() + + def test_add_through_patch_one_inst_while_removing_other(self, app, user, institution_one, institution_two, node, node_institutions_url, create_payload): + node.affiliated_institutions.add(institution_one) + node.save() + assert institution_one in node.affiliated_institutions.all() + assert institution_two not in node.affiliated_institutions.all() + + res = app.patch_json_api( + node_institutions_url, + create_payload(institution_two._id), + auth=user.auth ) - assert_equal(res.status_code, 200) - self.node.reload() - assert_not_in(self.institution1, self.node.affiliated_institutions.all()) - assert_in(self.institution2, self.node.affiliated_institutions.all()) - - def test_add_one_inst_with_post_to_node_with_inst(self): - self.node.affiliated_institutions.add(self.institution1) - self.node.save() - assert_in(self.institution1, self.node.affiliated_institutions.all()) - assert_not_in(self.institution2, self.node.affiliated_institutions.all()) - - res = self.app.post_json_api( - self.node_institutions_url, - self.create_payload(self.institution2._id), - auth=self.user.auth + assert res.status_code == 200 + node.reload() + assert institution_one not in node.affiliated_institutions.all() + assert institution_two in node.affiliated_institutions.all() + + def test_add_one_inst_with_post_to_node_with_inst(self, app, user, institution_one, institution_two, node, node_institutions_url, create_payload): + node.affiliated_institutions.add(institution_one) + node.save() + assert institution_one in node.affiliated_institutions.all() + assert institution_two not in node.affiliated_institutions.all() + + res = app.post_json_api( + node_institutions_url, + create_payload(institution_two._id), + auth=user.auth ) - assert_equal(res.status_code, 201) - self.node.reload() - assert_in(self.institution1, self.node.affiliated_institutions.all()) - assert_in(self.institution2, self.node.affiliated_institutions.all()) + assert res.status_code == 201 + node.reload() + assert institution_one in node.affiliated_institutions.all() + assert institution_two in node.affiliated_institutions.all() - def test_delete_nothing(self): - res = self.app.delete_json_api( - self.node_institutions_url, - self.create_payload(), - auth=self.user.auth + def test_delete_nothing(self, app, user, node_institutions_url, create_payload): + res = app.delete_json_api( + node_institutions_url, + create_payload(), + auth=user.auth ) - assert_equal(res.status_code, 204) + assert res.status_code == 204 - def test_delete_existing_inst(self): - self.node.affiliated_institutions.add(self.institution1) - self.node.save() - assert_in(self.institution1, self.node.affiliated_institutions.all()) + def test_delete_existing_inst(self, app, user, institution_one, node, node_institutions_url, create_payload): + node.affiliated_institutions.add(institution_one) + node.save() + assert institution_one in node.affiliated_institutions.all() - res = self.app.delete_json_api( - self.node_institutions_url, - self.create_payload(self.institution1._id), - auth=self.user.auth + res = app.delete_json_api( + node_institutions_url, + create_payload(institution_one._id), + auth=user.auth ) - assert_equal(res.status_code, 204) - self.node.reload() - assert_not_in(self.institution1, self.node.affiliated_institutions.all()) + assert res.status_code == 204 + node.reload() + assert institution_one not in node.affiliated_institutions.all() - def test_delete_not_affiliated_and_affiliated_insts(self): - self.node.affiliated_institutions.add(self.institution1) - self.node.save() - assert_in(self.institution1, self.node.affiliated_institutions.all()) - assert_not_in(self.institution2, self.node.affiliated_institutions.all()) + def test_delete_not_affiliated_and_affiliated_insts(self, app, user, institution_one, institution_two, node, node_institutions_url, create_payload): + node.affiliated_institutions.add(institution_one) + node.save() + assert institution_one in node.affiliated_institutions.all() + assert institution_two not in node.affiliated_institutions.all() - res = self.app.delete_json_api( - self.node_institutions_url, - self.create_payload(self.institution1._id, self.institution2._id), - auth=self.user.auth, + res = app.delete_json_api( + node_institutions_url, + create_payload(institution_one._id, institution_two._id), + auth=user.auth, ) - assert_equal(res.status_code, 204) - self.node.reload() - assert_not_in(self.institution1, self.node.affiliated_institutions.all()) - assert_not_in(self.institution2, self.node.affiliated_institutions.all()) + assert res.status_code == 204 + node.reload() + assert institution_one not in node.affiliated_institutions.all() + assert institution_two not in node.affiliated_institutions.all() - def test_delete_user_is_admin(self): - self.node.affiliated_institutions.add(self.institution1) - self.node.save() + def test_delete_user_is_admin(self, app, user, institution_one, node, node_institutions_url, create_payload): + node.affiliated_institutions.add(institution_one) + node.save() - res = self.app.delete_json_api( - self.node_institutions_url, - self.create_payload(self.institution1._id), - auth=self.user.auth + res = app.delete_json_api( + node_institutions_url, + create_payload(institution_one._id), + auth=user.auth ) - assert_equal(res.status_code, 204) + assert res.status_code == 204 - def test_delete_user_is_read_write(self): + def test_delete_user_is_read_write(self, app, institution_one, node, node_institutions_url, create_payload): user = AuthUserFactory() - user.affiliated_institutions.add(self.institution1) + user.affiliated_institutions.add(institution_one) user.save() - self.node.add_contributor(user) - self.node.affiliated_institutions.add(self.institution1) - self.node.save() + node.add_contributor(user) + node.affiliated_institutions.add(institution_one) + node.save() - res = self.app.delete_json_api( - self.node_institutions_url, - self.create_payload(self.institution1._id), + res = app.delete_json_api( + node_institutions_url, + create_payload(institution_one._id), auth=user.auth ) - assert_equal(res.status_code, 204) + assert res.status_code == 204 - def test_delete_user_is_read_only(self): + def test_delete_user_is_read_only(self, app, institution_one, node, node_institutions_url, create_payload): user = AuthUserFactory() - user.affiliated_institutions.add(self.institution1) + user.affiliated_institutions.add(institution_one) user.save() - self.node.add_contributor(user, permissions=[permissions.READ]) - self.node.affiliated_institutions.add(self.institution1) - self.node.save() + node.add_contributor(user, permissions=[permissions.READ]) + node.affiliated_institutions.add(institution_one) + node.save() - res = self.app.delete_json_api( - self.node_institutions_url, - self.create_payload(self.institution1._id), + res = app.delete_json_api( + node_institutions_url, + create_payload(institution_one._id), auth=user.auth, expect_errors=True ) - assert_equal(res.status_code, 403) + assert res.status_code == 403 - def test_delete_user_is_admin_but_not_affiliated_with_inst(self): + def test_delete_user_is_admin_but_not_affiliated_with_inst(self, app, institution_one, create_payload): user = AuthUserFactory() node = NodeFactory(creator=user) - node.affiliated_institutions.add(self.institution1) + node.affiliated_institutions.add(institution_one) node.save() - assert_in(self.institution1, node.affiliated_institutions.all()) + assert institution_one in node.affiliated_institutions.all() - res = self.app.delete_json_api( + res = app.delete_json_api( '/{0}nodes/{1}/relationships/institutions/'.format(API_BASE, node._id), - self.create_payload(self.institution1._id), + create_payload(institution_one._id), auth=user.auth, ) - assert_equal(res.status_code, 204) + assert res.status_code == 204 node.reload() - assert_not_in(self.institution1, node.affiliated_institutions.all()) + assert institution_one not in node.affiliated_institutions.all() - def test_admin_can_add_affiliated_institution(self): + def test_admin_can_add_affiliated_institution(self, app, user, institution_one, node, node_institutions_url): payload = { 'data': [{ 'type': 'institutions', - 'id': self.institution1._id + 'id': institution_one._id }] } - res = self.app.post_json_api(self.node_institutions_url, payload, auth=self.user.auth) - self.node.reload() - assert_equal(res.status_code, 201) - assert_in(self.institution1, self.node.affiliated_institutions.all()) + res = app.post_json_api(node_institutions_url, payload, auth=user.auth) + node.reload() + assert res.status_code == 201 + assert institution_one in node.affiliated_institutions.all() - def test_admin_can_remove_admin_affiliated_institution(self): - self.node.affiliated_institutions.add(self.institution1) + def test_admin_can_remove_admin_affiliated_institution(self, app, user, institution_one, node, node_institutions_url): + node.affiliated_institutions.add(institution_one) payload = { 'data': [{ 'type': 'institutions', - 'id': self.institution1._id + 'id': institution_one._id }] } - res = self.app.delete_json_api(self.node_institutions_url, payload, auth=self.user.auth) - self.node.reload() - assert_equal(res.status_code, 204) - assert_not_in(self.institution1, self.node.affiliated_institutions.all()) - - def test_admin_can_remove_read_write_contributor_affiliated_institution(self): - self.node.affiliated_institutions.add(self.read_write_contributor_institution) - self.node.save() + res = app.delete_json_api(node_institutions_url, payload, auth=user.auth) + node.reload() + assert res.status_code == 204 + assert institution_one not in node.affiliated_institutions.all() + + def test_admin_can_remove_read_write_contributor_affiliated_institution(self, app, user, read_contrib_institution, node, node_institutions_url): + node.affiliated_institutions.add(read_contrib_institution) + node.save() payload = { 'data': [{ 'type': 'institutions', - 'id': self.read_write_contributor_institution._id + 'id': read_contrib_institution._id }] } - res = self.app.delete_json_api(self.node_institutions_url, payload, auth=self.user.auth) - self.node.reload() - assert_equal(res.status_code, 204) - assert_not_in(self.read_write_contributor_institution, self.node.affiliated_institutions.all()) + res = app.delete_json_api(node_institutions_url, payload, auth=user.auth) + node.reload() + assert res.status_code == 204 + assert read_contrib_institution not in node.affiliated_institutions.all() - def test_read_write_contributor_can_add_affiliated_institution(self): + def test_read_write_contributor_can_add_affiliated_institution(self, app, write_contrib, write_contrib_institution, node, node_institutions_url): payload = { 'data': [{ 'type': 'institutions', - 'id': self.read_write_contributor_institution._id + 'id': write_contrib_institution._id }] } - res = self.app.post_json_api(self.node_institutions_url, payload, auth=self.read_write_contributor.auth) - self.node.reload() - assert_equal(res.status_code, 201) - assert_in(self.read_write_contributor_institution, self.node.affiliated_institutions.all()) - - def test_read_write_contributor_can_remove_affiliated_institution(self): - self.node.affiliated_institutions.add(self.read_write_contributor_institution) - self.node.save() + res = app.post_json_api(node_institutions_url, payload, auth=write_contrib.auth) + node.reload() + assert res.status_code == 201 + assert write_contrib_institution in node.affiliated_institutions.all() + + def test_read_write_contributor_can_remove_affiliated_institution(self, app, write_contrib, write_contrib_institution, node, node_institutions_url): + node.affiliated_institutions.add(write_contrib_institution) + node.save() payload = { 'data': [{ 'type': 'institutions', - 'id': self.read_write_contributor_institution._id + 'id': write_contrib_institution._id }] } - res = self.app.delete_json_api(self.node_institutions_url, payload, auth=self.read_write_contributor.auth) - self.node.reload() - assert_equal(res.status_code, 204) - assert_not_in(self.read_write_contributor_institution, self.node.affiliated_institutions.all()) - - def test_read_write_contributor_cannot_remove_admin_affiliated_institution(self): - self.node.affiliated_institutions.add(self.institution1) - self.node.save() + res = app.delete_json_api(node_institutions_url, payload, auth=write_contrib.auth) + node.reload() + assert res.status_code == 204 + assert write_contrib_institution not in node.affiliated_institutions.all() + + def test_contribs_cannot_perform_action(self, app, write_contrib, read_contrib, institution_one, read_contrib_institution, node, node_institutions_url): + + # test_read_write_contributor_cannot_remove_admin_affiliated_institution + node.affiliated_institutions.add(institution_one) + node.save() payload = { 'data': [{ 'type': 'institutions', - 'id': self.institution1._id + 'id': institution_one._id }] } - res = self.app.delete_json_api(self.node_institutions_url, payload, auth=self.read_write_contributor.auth, expect_errors=True) - self.node.reload() - assert_equal(res.status_code, 403) - assert_in(self.institution1, self.node.affiliated_institutions.all()) - - def test_read_only_contributor_cannot_remove_admin_affiliated_institution(self): - self.node.affiliated_institutions.add(self.institution1) - self.node.save() + res = app.delete_json_api(node_institutions_url, payload, auth=write_contrib.auth, expect_errors=True) + node.reload() + assert res.status_code == 403 + assert institution_one in node.affiliated_institutions.all() + + # test_read_only_contributor_cannot_remove_admin_affiliated_institution + node.affiliated_institutions.add(institution_one) + node.save() payload = { 'data': [{ 'type': 'institutions', - 'id': self.institution1._id + 'id': institution_one._id }] } - res = self.app.delete_json_api(self.node_institutions_url, payload, auth=self.read_only_contributor.auth, expect_errors=True) - self.node.reload() - assert_equal(res.status_code, 403) - assert_in(self.institution1, self.node.affiliated_institutions.all()) + res = app.delete_json_api(node_institutions_url, payload, auth=read_contrib.auth, expect_errors=True) + node.reload() + assert res.status_code == 403 + assert institution_one in node.affiliated_institutions.all() - def test_read_only_contributor_cannot_add_affiliated_institution(self): + # test_read_only_contributor_cannot_add_affiliated_institution payload = { 'data': [{ 'type': 'institutions', - 'id': self.read_only_contributor_institution._id + 'id': read_contrib_institution._id }] } - res = self.app.post_json_api(self.node_institutions_url, payload, auth=self.read_only_contributor.auth, expect_errors=True) - self.node.reload() - assert_equal(res.status_code, 403) - assert_not_in(self.read_write_contributor_institution, self.node.affiliated_institutions.all()) - - def test_read_only_contributor_cannot_remove_affiliated_institution(self): - self.node.affiliated_institutions.add(self.read_only_contributor_institution) - self.node.save() + res = app.post_json_api(node_institutions_url, payload, auth=read_contrib.auth, expect_errors=True) + node.reload() + assert res.status_code == 403 + assert read_contrib_institution not in node.affiliated_institutions.all() + + # test_read_only_contributor_cannot_remove_affiliated_institution + node.affiliated_institutions.add(read_contrib_institution) + node.save() payload = { 'data': [{ 'type': 'institutions', - 'id': self.read_only_contributor_institution._id + 'id': read_contrib_institution._id }] } - res = self.app.delete_json_api(self.node_institutions_url, payload, auth=self.read_only_contributor.auth, expect_errors=True) - self.node.reload() - assert_equal(res.status_code, 403) - assert_in(self.read_only_contributor_institution, self.node.affiliated_institutions.all()) + res = app.delete_json_api(node_institutions_url, payload, auth=read_contrib.auth, expect_errors=True) + node.reload() + assert res.status_code == 403 + assert read_contrib_institution in node.affiliated_institutions.all() From db6c73bacab961debe41d4022aeebf1c8ee7b433 Mon Sep 17 00:00:00 2001 From: Fabrice Mizero Date: Tue, 13 Jun 2017 11:11:06 -0400 Subject: [PATCH 078/163] Update admin users test views --- admin_tests/users/test_views.py | 28 +++++++++++++++++++++------- 1 file changed, 21 insertions(+), 7 deletions(-) diff --git a/admin_tests/users/test_views.py b/admin_tests/users/test_views.py index 1316dfaa440..7038412ed33 100644 --- a/admin_tests/users/test_views.py +++ b/admin_tests/users/test_views.py @@ -87,14 +87,28 @@ def test_correct_view_permissions(self): class TestResetPasswordView(AdminTestCase): - def test_reset_password_context(self): - user = UserFactory() + def setUp(self): + super(TestResetPasswordView, self).setUp() + self.user = UserFactory() + user = self.user + self.request = RequestFactory().get('/fake_path') + self.request.user = self.user + self.plain_view = views.ResetPasswordView + self.view = setup_view(self.plain_view(), self.request, guid=user._id) + + def test_get_initial(self): + self.view.user = self.user + self.view.get_initial() + res = self.view.initial + nt.assert_is_instance(res, dict) + nt.assert_equal(res['guid'], self.user._id) + nt.assert_equal(res['emails'], self.user.emails) - guid = user._id - request = RequestFactory().get('/fake_path') - view = views.ResetPasswordView(initial={}) - view = setup_view(view, request, guid=guid) - res = view.get_context_data() + def test_reset_password_context(self): + self.view.user = self.user + res = self.view.get_context_data() + user = self.user + view = self.view nt.assert_is_instance(res, dict) nt.assert_in((user.emails.first().address, user.emails.first().address), view.initial['emails']) From 93457a7f9c4b9b375280a1d330fe0c8012cb5e31 Mon Sep 17 00:00:00 2001 From: Rheisen Dennis Date: Tue, 13 Jun 2017 13:32:15 -0400 Subject: [PATCH 079/163] switch tabs to spaces --- api_tests/nodes/views/test_node_citations.py | 96 ++++++++++---------- 1 file changed, 48 insertions(+), 48 deletions(-) diff --git a/api_tests/nodes/views/test_node_citations.py b/api_tests/nodes/views/test_node_citations.py index 738ae0ae0b7..6716d071d0f 100644 --- a/api_tests/nodes/views/test_node_citations.py +++ b/api_tests/nodes/views/test_node_citations.py @@ -14,82 +14,82 @@ def admin_contributor(): @pytest.fixture() def write_contrib(): - return AuthUserFactory() + return AuthUserFactory() @pytest.fixture() def read_contrib(): - return AuthUserFactory() + return AuthUserFactory() @pytest.fixture() def non_contrib(): - return AuthUserFactory() + return AuthUserFactory() @pytest.fixture() def public_project(admin_contributor): - return ProjectFactory(creator=admin_contributor, is_public=True) + return ProjectFactory(creator=admin_contributor, is_public=True) @pytest.fixture() def private_project(admin_contributor, write_contrib, read_contrib): - private_project = ProjectFactory(creator=admin_contributor) - private_project.add_contributor(write_contrib, permissions=['read','write'], auth=Auth(admin_contributor)) - private_project.add_contributor(read_contrib, permissions=['read'], auth=Auth(admin_contributor)) - private_project.save() - return private_project + private_project = ProjectFactory(creator=admin_contributor) + private_project.add_contributor(write_contrib, permissions=['read','write'], auth=Auth(admin_contributor)) + private_project.add_contributor(read_contrib, permissions=['read'], auth=Auth(admin_contributor)) + private_project.save() + return private_project @pytest.mark.django_db class NodeCitationsMixin: def test_node_citations(self, app, admin_contributor, write_contrib, read_contrib, non_contrib, private_url, public_url): - # test_admin_can_view_private_project_citations - res = app.get(private_url, auth=admin_contributor.auth) - assert res.status_code == 200 + # test_admin_can_view_private_project_citations + res = app.get(private_url, auth=admin_contributor.auth) + assert res.status_code == 200 - # test_write_contrib_can_view_private_project_citations - res = app.get(private_url, auth=write_contrib.auth) - assert res.status_code == 200 + # test_write_contrib_can_view_private_project_citations + res = app.get(private_url, auth=write_contrib.auth) + assert res.status_code == 200 - # test_read_contrib_can_view_private_project_citations - res = app.get(private_url, auth=read_contrib.auth) - assert res.status_code == 200 + # test_read_contrib_can_view_private_project_citations + res = app.get(private_url, auth=read_contrib.auth) + assert res.status_code == 200 - # test_non_contrib_cannot_view_private_project_citations - res = app.get(private_url, auth=non_contrib.auth, expect_errors=True) - assert res.status_code == 403 - assert res.json['errors'][0]['detail'] == exceptions.PermissionDenied.default_detail + # test_non_contrib_cannot_view_private_project_citations + res = app.get(private_url, auth=non_contrib.auth, expect_errors=True) + assert res.status_code == 403 + assert res.json['errors'][0]['detail'] == exceptions.PermissionDenied.default_detail - # test_unauthenticated_cannot_view_private_project_citations - res = app.get(private_url, expect_errors=True) - assert res.status_code == 401 - assert res.json['errors'][0]['detail'] == exceptions.NotAuthenticated.default_detail + # test_unauthenticated_cannot_view_private_project_citations + res = app.get(private_url, expect_errors=True) + assert res.status_code == 401 + assert res.json['errors'][0]['detail'] == exceptions.NotAuthenticated.default_detail - # test_unauthenticated_can_view_public_project_citations - res = app.get(public_url) - assert res.status_code == 200 + # test_unauthenticated_can_view_public_project_citations + res = app.get(public_url) + assert res.status_code == 200 - # test_citations_are_read_only - post_res = app.post_json_api(public_url, {}, auth=admin_contributor.auth, expect_errors=True) - assert post_res.status_code == 405 - put_res = app.put_json_api(public_url, {}, auth=admin_contributor.auth, expect_errors=True) - assert put_res.status_code == 405 - delete_res = app.delete_json_api(public_url, auth=admin_contributor.auth, expect_errors=True) - assert delete_res.status_code == 405 + # test_citations_are_read_only + post_res = app.post_json_api(public_url, {}, auth=admin_contributor.auth, expect_errors=True) + assert post_res.status_code == 405 + put_res = app.put_json_api(public_url, {}, auth=admin_contributor.auth, expect_errors=True) + assert put_res.status_code == 405 + delete_res = app.delete_json_api(public_url, auth=admin_contributor.auth, expect_errors=True) + assert delete_res.status_code == 405 class TestNodeCitations(NodeCitationsMixin): - @pytest.fixture() - def public_url(self, public_project): - return '/{}nodes/{}/citation/'.format(API_BASE, public_project._id) + @pytest.fixture() + def public_url(self, public_project): + return '/{}nodes/{}/citation/'.format(API_BASE, public_project._id) - @pytest.fixture() - def private_url(self, private_project): - return '/{}nodes/{}/citation/'.format(API_BASE, private_project._id) + @pytest.fixture() + def private_url(self, private_project): + return '/{}nodes/{}/citation/'.format(API_BASE, private_project._id) class TestNodeCitationsStyle(NodeCitationsMixin): - @pytest.fixture() - def public_url(self, public_project): - return '/{}nodes/{}/citation/apa/'.format(API_BASE, public_project._id) + @pytest.fixture() + def public_url(self, public_project): + return '/{}nodes/{}/citation/apa/'.format(API_BASE, public_project._id) - @pytest.fixture() - def private_url(self, private_project): - return '/{}nodes/{}/citation/apa/'.format(API_BASE, private_project._id) + @pytest.fixture() + def private_url(self, private_project): + return '/{}nodes/{}/citation/apa/'.format(API_BASE, private_project._id) From 87f911349568951dc7569a732a57c09d3c8a9e9e Mon Sep 17 00:00:00 2001 From: Fabrice Mizero Date: Thu, 15 Jun 2017 09:50:56 -0400 Subject: [PATCH 080/163] Update class tests --- admin/users/views.py | 4 ++-- admin_tests/users/test_views.py | 10 +++------- 2 files changed, 5 insertions(+), 9 deletions(-) diff --git a/admin/users/views.py b/admin/users/views.py index 7b841a367d4..3ad0ac67297 100644 --- a/admin/users/views.py +++ b/admin/users/views.py @@ -525,9 +525,9 @@ def dispatch(self, request, *args, **kwargs): return super(ResetPasswordView, self).dispatch(request, *args, **kwargs) def get_initial(self): - user = self.user self.initial = { - 'emails': [(r, r) for r in user.emails.values_list('address', flat=True)], + 'guid': self.user._id, + 'emails': [(r, r) for r in self.user.emails.values_list('address', flat=True)], } return super(ResetPasswordView, self).get_initial() diff --git a/admin_tests/users/test_views.py b/admin_tests/users/test_views.py index 7038412ed33..2d7f0c1591d 100644 --- a/admin_tests/users/test_views.py +++ b/admin_tests/users/test_views.py @@ -90,11 +90,10 @@ class TestResetPasswordView(AdminTestCase): def setUp(self): super(TestResetPasswordView, self).setUp() self.user = UserFactory() - user = self.user self.request = RequestFactory().get('/fake_path') self.request.user = self.user self.plain_view = views.ResetPasswordView - self.view = setup_view(self.plain_view(), self.request, guid=user._id) + self.view = setup_view(self.plain_view(), self.request, guid=self.user._id) def test_get_initial(self): self.view.user = self.user @@ -102,15 +101,13 @@ def test_get_initial(self): res = self.view.initial nt.assert_is_instance(res, dict) nt.assert_equal(res['guid'], self.user._id) - nt.assert_equal(res['emails'], self.user.emails) + nt.assert_equal(res['emails'], [(r, r) for r in self.user.emails.values_list('address', flat=True)]) def test_reset_password_context(self): self.view.user = self.user res = self.view.get_context_data() - user = self.user - view = self.view nt.assert_is_instance(res, dict) - nt.assert_in((user.emails.first().address, user.emails.first().address), view.initial['emails']) + nt.assert_in((self.user.emails.first().address, self.user.emails.first().address), self.view.initial['emails']) def test_no_user_permissions_raises_error(self): user = UserFactory() @@ -301,7 +298,6 @@ def test_correct_view_permissions(self): response = self.plain_view.as_view()(request, guid=guid) self.assertEqual(response.status_code, 200) - class TestFlaggedSpamUserList(SpamUserListMixin, AdminTestCase): def setUp(self): super(TestFlaggedSpamUserList, self).setUp() From f51284af2132a8166f3190a450c6f49800da0d15 Mon Sep 17 00:00:00 2001 From: Fabrice Mizero Date: Fri, 28 Apr 2017 14:19:35 -0400 Subject: [PATCH 081/163] Allow component api url to be passed as argument --- website/static/js/projectSettings.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/website/static/js/projectSettings.js b/website/static/js/projectSettings.js index 11adf3be8a8..f9cfec549a1 100644 --- a/website/static/js/projectSettings.js +++ b/website/static/js/projectSettings.js @@ -29,7 +29,7 @@ var ProjectSettings = oop.extend( self.categoryOptions = params.categoryOptions; self.categoryPlaceholder = params.category; self.selectedCategory = ko.observable(params.category); - + if (!params.updateUrl) { throw new Error(language.instantiationErrorMessage); } @@ -79,7 +79,7 @@ var ProjectSettings = oop.extend( xhrFields: {withCredentials: true}, processData: false, data: requestPayload - }); + }); request.done(function(response) { self.categoryPlaceholder = response.data.attributes.category; self.titlePlaceholder = response.data.attributes.title; @@ -152,7 +152,7 @@ request.fail(function(xhr, textStatus, err) { * Pulls a random name from the scientist list to use as confirmation string * Ignores case and whitespace */ -var getConfirmationCode = function(nodeType, isPreprint) { +var getConfirmationCode = function(nodeType, isPreprint, nodeApiUrl=nodeApiUrl) { var preprint_message = '

      This ' + nodeType + ' contains a preprint. Deleting this ' + nodeType + ' will also delete your preprint. This action is irreversible.

      '; From 2600d0c78359ea3d42e1fcf27c4e48dafafa81c1 Mon Sep 17 00:00:00 2001 From: Fabrice Mizero Date: Fri, 28 Apr 2017 14:22:02 -0400 Subject: [PATCH 082/163] Add component settings file --- webpack.common.config.js | 1 + 1 file changed, 1 insertion(+) diff --git a/webpack.common.config.js b/webpack.common.config.js index dfecd22ea20..7579a4dfd77 100644 --- a/webpack.common.config.js +++ b/webpack.common.config.js @@ -31,6 +31,7 @@ var entry = { 'project-dashboard': staticPath('js/pages/project-dashboard-page.js'), 'project-base-page': staticPath('js/pages/project-base-page.js'), 'project-settings-page': staticPath('js/pages/project-settings-page.js'), + 'component-settings-page': staticPath('js/pages/component-settings-page.js'), 'project-registrations-page': staticPath('js/pages/project-registrations-page.js'), 'registration-retraction-page': staticPath('js/pages/registration-retraction-page.js'), 'registration-edit-page': staticPath('js/pages/registration-edit-page.js'), From 8287d8b5563bf70b23695f686bce8171ff9f14e7 Mon Sep 17 00:00:00 2001 From: Fabrice Mizero Date: Fri, 28 Apr 2017 14:24:10 -0400 Subject: [PATCH 083/163] Add common actions for component widget --- .../js/pages/component-settings-page.js | 22 +++++++++++++++++++ 1 file changed, 22 insertions(+) create mode 100644 website/static/js/pages/component-settings-page.js diff --git a/website/static/js/pages/component-settings-page.js b/website/static/js/pages/component-settings-page.js new file mode 100644 index 00000000000..b1eec6233e5 --- /dev/null +++ b/website/static/js/pages/component-settings-page.js @@ -0,0 +1,22 @@ +'use strict'; + +var $ = require('jquery'); +var bootbox = require('bootbox'); +var Raven = require('raven-js'); +var ko = require('knockout'); +var $osf = require('js/osfHelpers.js'); +var ProjectSettings = require('js/projectSettings.js'); + +$(document).ready(function() { + $(".deleteComponent").each( function() { + $(this).off().on('click', function(e) { + var component = $(this).data('summary'); + if(component.childExists){ + $osf.growl('Error', 'Any child components must be deleted prior to deleting this project.','danger', 30000); + }else{ + ProjectSettings.getConfirmationCode(component.node_type, component.isPreprint, component.api_url); + } + }); + }); + +}); From 148fbb885f7eba83c12cb3455424b30b113fff15 Mon Sep 17 00:00:00 2001 From: Fabrice Mizero Date: Fri, 28 Apr 2017 14:26:02 -0400 Subject: [PATCH 084/163] Add html for common actions menu in component widget --- website/templates/util/render_node.mako | 24 +++++++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) diff --git a/website/templates/util/render_node.mako b/website/templates/util/render_node.mako index 949d11dac45..312e6a2adf9 100644 --- a/website/templates/util/render_node.mako +++ b/website/templates/util/render_node.mako @@ -58,7 +58,22 @@ % endif - +
  • % endif @@ -137,6 +152,10 @@