Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
86 changes: 1 addition & 85 deletions admin/collection_providers/forms.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
from django import forms

from framework.utils import sanitize_html
from osf.models import CollectionProvider, CollectionSubmission
from osf.models import CollectionProvider
from admin.base.utils import get_nodelicense_choices, get_defaultlicense_choices, validate_slug


Expand Down Expand Up @@ -74,12 +74,6 @@ def clean_collected_type_choices(self):
type_choices_new = {c.strip(' ') for c in json.loads(self.data.get('collected_type_choices'))}
type_choices_added = type_choices_new - type_choices_old
type_choices_removed = type_choices_old - type_choices_new
for item in type_choices_removed:
if CollectionSubmission.objects.filter(collection=collection_provider.primary_collection,
collected_type=item).exists():
raise forms.ValidationError(
f'Cannot delete "{item}" because it is used as metadata on objects.'
)
else:
# if this is creating a CollectionProvider
type_choices_added = []
Expand All @@ -104,12 +98,6 @@ def clean_status_choices(self):
status_choices_new = {c.strip(' ') for c in json.loads(self.data.get('status_choices'))}
status_choices_added = status_choices_new - status_choices_old
status_choices_removed = status_choices_old - status_choices_new
for item in status_choices_removed:
if CollectionSubmission.objects.filter(collection=collection_provider.primary_collection,
status=item).exists():
raise forms.ValidationError(
f'Cannot delete "{item}" because it is used as metadata on objects.'
)
else:
# if this is creating a CollectionProvider
status_choices_added = []
Expand All @@ -134,12 +122,6 @@ def clean_volume_choices(self):
volume_choices_new = {c.strip(' ') for c in json.loads(self.data.get('volume_choices'))}
volume_choices_added = volume_choices_new - volume_choices_old
volume_choices_removed = volume_choices_old - volume_choices_new
for item in volume_choices_removed:
if CollectionSubmission.objects.filter(collection=collection_provider.primary_collection,
volume=item).exists():
raise forms.ValidationError(
f'Cannot delete "{item}" because it is used as metadata on objects.'
)
else:
# if this is creating a CollectionProvider
volume_choices_added = []
Expand All @@ -164,12 +146,6 @@ def clean_issue_choices(self):
issue_choices_new = {c.strip(' ') for c in json.loads(self.data.get('issue_choices'))}
issue_choices_added = issue_choices_new - issue_choices_old
issue_choices_removed = issue_choices_old - issue_choices_new
for item in issue_choices_removed:
if CollectionSubmission.objects.filter(collection=collection_provider.primary_collection,
issue=item).exists():
raise forms.ValidationError(
f'Cannot delete "{item}" because it is used as metadata on objects.'
)
else:
# if this is creating a CollectionProvider
issue_choices_added = []
Expand All @@ -194,12 +170,6 @@ def clean_program_area_choices(self):
program_area_choices_new = {c.strip(' ') for c in json.loads(self.data.get('program_area_choices'))}
program_area_choices_added = program_area_choices_new - program_area_choices_old
program_area_choices_removed = program_area_choices_old - program_area_choices_new
for item in program_area_choices_removed:
if CollectionSubmission.objects.filter(collection=collection_provider.primary_collection,
program_area=item).exists():
raise forms.ValidationError(
f'Cannot delete "{item}" because it is used as metadata on objects.'
)
else:
# if this is creating a CollectionProvider
program_area_choices_added = []
Expand All @@ -224,16 +194,6 @@ def clean_school_type_choices(self):
updated_choices = {c.strip(' ') for c in json.loads(self.data.get('school_type_choices'))}
added_choices = updated_choices - old_choices
removed_choices = old_choices - updated_choices
active_removed_choices = set(
primary_collection.collectionsubmission_set.filter(
school_type__in=removed_choices
).values_list('school_type', flat=True)
)
if active_removed_choices:
raise forms.ValidationError(
'Cannot remove the following choices for "school_type", as they are '
f'currently in use: {active_removed_choices}'
)
else: # Creating a new CollectionProvider
added_choices = set()
removed_choices = set()
Expand All @@ -253,17 +213,6 @@ def clean_study_design_choices(self):
updated_choices = {c.strip(' ') for c in json.loads(self.data.get('study_design_choices'))}
added_choices = updated_choices - old_choices
removed_choices = old_choices - updated_choices

active_removed_choices = set(
primary_collection.collectionsubmission_set.filter(
study_design__in=removed_choices
).values_list('school_type', flat=True)
)
if active_removed_choices:
raise forms.ValidationError(
'Cannot remove the following choices for "study_design", as they are '
f'currently in use: {active_removed_choices}'
)
else: # Creating a new CollectionProvider
added_choices = set()
removed_choices = set()
Expand All @@ -283,17 +232,6 @@ def clean_disease_choices(self):
updated_choices = {c.strip(' ') for c in json.loads(self.data.get('disease_choices'))}
added_choices = updated_choices - old_choices
removed_choices = old_choices - updated_choices

active_removed_choices = set(
primary_collection.collectionsubmission_set.filter(
disease__in=removed_choices
).values_list('disease', flat=True)
)
if active_removed_choices:
raise forms.ValidationError(
'Cannot remove the following choices for "disease", as they are '
f'currently in use: {active_removed_choices}'
)
else: # Creating a new CollectionProvider
added_choices = set()
removed_choices = set()
Expand All @@ -313,17 +251,6 @@ def clean_data_type_choices(self):
updated_choices = {c.strip(' ') for c in json.loads(self.data.get('data_type_choices'))}
added_choices = updated_choices - old_choices
removed_choices = old_choices - updated_choices

active_removed_choices = set(
primary_collection.collectionsubmission_set.filter(
data_type__in=removed_choices
).values_list('data_type', flat=True)
)
if active_removed_choices:
raise forms.ValidationError(
'Cannot remove the following choices for "data_type", as they are '
f'currently in use: {active_removed_choices}'
)
else: # Creating a new CollectionProvider
added_choices = set()
removed_choices = set()
Expand All @@ -343,17 +270,6 @@ def clean_grade_levels_choices(self):
updated_choices = {c.strip(' ') for c in json.loads(self.data.get('grade_levels_choices'))}
added_choices = updated_choices - old_choices
removed_choices = old_choices - updated_choices

active_removed_choices = set(
primary_collection.collectionsubmission_set.filter(
data_type__in=removed_choices
).values_list('grade_levels', flat=True)
)
if active_removed_choices:
raise forms.ValidationError(
'Cannot remove the following choices for "grade_levels", as they are '
f'currently in use: {active_removed_choices}'
)
else: # Creating a new CollectionProvider
added_choices = set()
removed_choices = set()
Expand Down
4 changes: 3 additions & 1 deletion admin/management/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -150,10 +150,12 @@ def post(self, request):
class BulkResync(ManagementCommandPermissionView):

def post(self, request):
missing_dois_only = request.POST.get('missing_preprint_dois_only', False)
sync_doi_metadata.apply_async(kwargs={
'modified_date': timezone.now(),
'batch_size': None,
'dry_run': False
'dry_run': False,
'missing_preprint_dois_only': missing_dois_only
})
messages.success(request, 'Resyncing with CrossRef and DataCite! It will take some time.')
return redirect(reverse('management:commands'))
Expand Down
7 changes: 4 additions & 3 deletions admin/preprint_providers/forms.py
Original file line number Diff line number Diff line change
Expand Up @@ -112,11 +112,12 @@ class PreprintProviderRegisterModeratorOrAdminForm(forms.Form):
""" A form that finds an existing OSF User, and grants permissions to that
user so that they can use the admin app"""

def __init__(self, *args, **kwargs):
provider_id = kwargs.pop('provider_id')
def __init__(self, *args, provider_groups=None, **kwargs):
super().__init__(*args, **kwargs)

provider_groups = provider_groups or Group.objects.none()
self.fields['group_perms'] = forms.ModelMultipleChoiceField(
queryset=Group.objects.filter(name__startswith=f'reviews_preprint_{provider_id}'),
queryset=provider_groups,
required=False,
widget=forms.CheckboxSelectMultiple
)
Expand Down
17 changes: 8 additions & 9 deletions admin/preprint_providers/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
from django.contrib.auth.mixins import PermissionRequiredMixin
from django.forms.models import model_to_dict
from django.shortcuts import redirect, render
from django.utils.functional import cached_property

from admin.base import settings
from admin.base.forms import ImportFileForm
Expand Down Expand Up @@ -459,14 +460,18 @@ class PreprintProviderRegisterModeratorOrAdmin(PermissionRequiredMixin, FormView
template_name = 'preprint_providers/register_moderator_admin.html'
form_class = PreprintProviderRegisterModeratorOrAdminForm

@cached_property
def target_provider(self):
return PreprintProvider.objects.get(id=self.kwargs['preprint_provider_id'])

def get_form_kwargs(self):
kwargs = super().get_form_kwargs()
kwargs['provider_id'] = self.kwargs['preprint_provider_id']
kwargs['provider_groups'] = self.target_provider.group_objects
return kwargs

def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context['provider_name'] = PreprintProvider.objects.get(id=self.kwargs['preprint_provider_id']).name
context['provider_name'] = self.target_provider.name
return context

def form_valid(self, form):
Expand All @@ -477,13 +482,7 @@ def form_valid(self, form):
raise Http404(f'OSF user with id "{user_id}" not found. Please double check.')

for group in form.cleaned_data.get('group_perms'):
osf_user.groups.add(group)
split = group.name.split('_')
group_type = split[0]
if group_type == 'reviews':
provider_id = split[2]
provider = PreprintProvider.objects.get(id=provider_id)
provider.notification_subscriptions.get(event_name='new_pending_submissions').add_user_to_subscription(osf_user, 'email_transactional')
self.target_provider.add_to_group(osf_user, group)

osf_user.save()
messages.success(self.request, f'Permissions update successful for OSF User {osf_user.username}!')
Expand Down
3 changes: 2 additions & 1 deletion admin/templates/management/commands.html
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ <h4> <u>Ban spam users by regular expression</u>
<label>Nodes:</label> <input type="checkbox" name="node_ban" checked /><br>
<label>Registrations:</label> <input type="checkbox" name="registration_ban" checked /><br>
<label>Preprints:</label> <input type="checkbox" name="preprint_ban" checked /><br>
<input class="btn btn-danger" type="submit" value="Run" style="color: red" />
<input class="btn btn-danger" type="submit" value="Run" style="color: white" />
</form>
</ul>
<section>
Expand Down Expand Up @@ -133,6 +133,7 @@ <h4><u>Resync with CrossRef and DataCite</u></h4>
<form method="post"
action="{% url 'management:bulk-resync'%}">
{% csrf_token %}
<label>Only preprints missing DOI:</label> <input type="checkbox" name="missing_preprint_dois_only"/><br>
<nav>
<input class="btn btn-success" type="submit" value="Run" />
</nav>
Expand Down
1 change: 1 addition & 0 deletions admin/users/forms.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ class UserSearchForm(forms.Form):
guid = forms.CharField(label='guid', min_length=5, max_length=5, required=False) # TODO: Move max to 6 when needed
name = forms.CharField(label='name', required=False)
email = forms.EmailField(label='email', required=False)
orcid = forms.CharField(label='orcid', required=False)


class MergeUserForm(forms.Form):
Expand Down
17 changes: 14 additions & 3 deletions admin/users/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
from framework.auth.core import generate_verification_key

from website import search
from website.settings import EXTERNAL_IDENTITY_PROFILE

from osf.models.admin_log_entry import (
update_admin_log,
Expand Down Expand Up @@ -126,6 +127,7 @@ def form_valid(self, form):
guid = form.cleaned_data['guid']
name = form.cleaned_data['name']
email = form.cleaned_data['email']
orcid = form.cleaned_data['orcid']
if name:
return redirect(reverse('users:search-list', kwargs={'name': name}))

Expand All @@ -148,6 +150,18 @@ def form_valid(self, form):

return redirect(reverse('users:user', kwargs={'guid': guid}))

if orcid:
external_id_provider = EXTERNAL_IDENTITY_PROFILE.get('OrcidProfile')
user = get_user(external_id_provider=external_id_provider, external_id=orcid)

if not user:
return page_not_found(
self.request,
AttributeError(f'resource with id "{orcid}" not found.')
)

return redirect(reverse('users:user', kwargs={'guid': user._id}))

return super().form_valid(form)


Expand Down Expand Up @@ -456,9 +470,6 @@ def get_context_data(self, **kwargs):

class GetUserConfirmationLink(GetUserLink):
def get_link(self, user):
if user.is_confirmed:
return f'User {user._id} is already confirmed'

if user.deleted or user.is_merged:
return f'User {user._id} is deleted or merged'

Expand Down
9 changes: 8 additions & 1 deletion admin_tests/preprints/test_views.py
Original file line number Diff line number Diff line change
Expand Up @@ -536,7 +536,8 @@ def withdrawal_request(self, preprint, submitter):
withdrawal_request.run_submit(submitter)
return withdrawal_request

def test_can_approve_withdrawal_request(self, withdrawal_request, submitter, preprint, admin):
@mock.patch('osf.models.preprint.update_or_enqueue_on_preprint_updated')
def test_can_approve_withdrawal_request(self, mocked_function, withdrawal_request, submitter, preprint, admin):
assert withdrawal_request.machine_state == DefaultStates.PENDING.value
original_comment = withdrawal_request.comment

Expand All @@ -552,6 +553,12 @@ def test_can_approve_withdrawal_request(self, withdrawal_request, submitter, pre
assert withdrawal_request.machine_state == DefaultStates.ACCEPTED.value
assert original_comment == withdrawal_request.target.withdrawal_justification

# share update is triggered when update "date_withdrawn" and "withdrawal_justification" throughout withdrawal process
updated_fields = mocked_function.call_args[1]['saved_fields']
assert 'date_withdrawn' in updated_fields
assert 'withdrawal_justification' in updated_fields
assert preprint.SEARCH_UPDATE_FIELDS.intersection(updated_fields)

def test_can_reject_withdrawal_request(self, withdrawal_request, admin, preprint):
assert withdrawal_request.machine_state == DefaultStates.PENDING.value

Expand Down
Loading
Loading