Skip to content
Open
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
3 changes: 2 additions & 1 deletion admin/preprint_providers/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
re_path(r'^(?P<preprint_provider_id>[a-z0-9]+)/delete/$', views.DeletePreprintProvider.as_view(), name='delete'),
re_path(r'^(?P<preprint_provider_id>[a-z0-9]+)/export/$', views.ExportPreprintProvider.as_view(), name='export'),
re_path(r'^(?P<preprint_provider_id>[a-z0-9]+)/share_source/$', views.ShareSourcePreprintProvider.as_view(), name='share_source'),
re_path(r'^(?P<preprint_provider_id>[a-z0-9]+)/register/$', views.PreprintProviderRegisterModeratorOrAdmin.as_view(), name='register_moderator_admin'),
re_path(r'^(?P<preprint_provider_id>[a-z0-9]+)/edit/$', views.PreprintProviderChangeForm.as_view(), name='edit'),
re_path(r'^(?P<provider_id>[a-z0-9]+)/add_admin_or_moderator/$', views.PreprintAddAdminOrModerator.as_view(), name='add_admin_or_moderator'),
re_path(r'^(?P<provider_id>[a-z0-9]+)/remove_admins_and_moderators/$', views.PreprintRemoveAdminsAndModerators.as_view(), name='remove_admins_and_moderators'),
]
56 changes: 14 additions & 42 deletions admin/preprint_providers/views.py
Original file line number Diff line number Diff line change
@@ -1,25 +1,23 @@
import json


from django.http import Http404
from django.core import serializers
from django.core.exceptions import ValidationError
from django.urls import reverse_lazy, reverse
from django.urls import reverse_lazy
from django.http import HttpResponse, JsonResponse
from django.views.generic import ListView, DetailView, View, CreateView, DeleteView, TemplateView, UpdateView
from django.views.generic.edit import FormView
from django.contrib import messages
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
from admin.preprint_providers.forms import PreprintProviderForm, PreprintProviderCustomTaxonomyForm, PreprintProviderRegisterModeratorOrAdminForm
from osf.models import PreprintProvider, Subject, OSFUser, RegistrationProvider, CollectionProvider
from admin.preprint_providers.forms import PreprintProviderForm, PreprintProviderCustomTaxonomyForm
from osf.models import PreprintProvider, Subject, RegistrationProvider, CollectionProvider
from osf.models.provider import rules_to_subjects, WhitelistedSHAREPreprintProvider
from website import settings as website_settings
from admin.providers.views import AddAdminOrModerator, RemoveAdminsAndModerators

FIELDS_TO_NOT_IMPORT_EXPORT = ['access_token', 'share_source', 'subjects_acceptable', 'primary_collection']

Expand Down Expand Up @@ -454,43 +452,17 @@ def get(self, request):
return render(request, self.template_name, {'share_api_url': share_api_url, 'api_v2_url': api_v2_url})


class PreprintProviderRegisterModeratorOrAdmin(PermissionRequiredMixin, FormView):
class PreprintAddAdminOrModerator(AddAdminOrModerator):
permission_required = 'osf.change_preprintprovider'
template_name = 'preprint_providers/edit_moderators.html'
provider_class = PreprintProvider
url_namespace = 'preprint_providers'
raise_exception = True
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_groups'] = self.target_provider.group_objects
return kwargs

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

def form_valid(self, form):
user_id = form.cleaned_data.get('user_id')
osf_user = OSFUser.load(user_id)

if not osf_user:
raise Http404(f'OSF user with id "{user_id}" not found. Please double check.')

if osf_user.has_groups(self.target_provider.group_names):
messages.error(self.request, f'User with guid: {user_id} is already a moderator or admin')
return super().form_invalid(form)

group = form.cleaned_data.get('group_perms')
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}!')
return super().form_valid(form)

def get_success_url(self):
return reverse('preprint_providers:register_moderator_admin', kwargs={'preprint_provider_id': self.kwargs['preprint_provider_id']})
class PreprintRemoveAdminsAndModerators(RemoveAdminsAndModerators):
permission_required = 'osf.change_preprintprovider'
template_name = 'preprint_providers/edit_moderators.html'
provider_class = PreprintProvider
url_namespace = 'preprint_providers'
raise_exception = True
19 changes: 8 additions & 11 deletions admin/templates/institutions/detail.html
Original file line number Diff line number Diff line change
Expand Up @@ -24,12 +24,15 @@
<a class="btn btn-danger" href={% url 'institutions:delete' institution.id %}>Delete institution</a>
{% endif %}
{% if perms.osf.change_institution %}
{% if institution.deactivated is None %}
<a class="btn btn-danger" href={% url 'institutions:deactivate' institution.id %}>Deactivate institution</a>
{% else %}
<a class="btn btn-danger" href={% url 'institutions:reactivate' institution.id %}>Reactivate institution</a>
{% endif %}
{% if institution.deactivated is None %}
<a class="btn btn-danger" href={% url 'institutions:deactivate' institution.id %}>Deactivate institution</a>
{% else %}
<a class="btn btn-danger" href={% url 'institutions:reactivate' institution.id %}>Reactivate institution</a>
{% endif %}
{% endif %}
{% if perms.osf.change_institution %}
<a class="btn btn-primary" href={% url 'institutions:list_and_add_admin' institution.id %}>Manage Admins</a>
{% endif %}
</div>
</div>

Expand Down Expand Up @@ -64,12 +67,6 @@ <h4>Banner:</h4>
<button id="show-modify-form" class="btn btn-link" type="button">
Modify Institution
</button>
<div class="col-md-12">
<a class="btn btn-link" href={% url 'institutions:register_metrics_admin' institution.id %}>Create Moderator/Admin</a>
</div>
<div class="col-md-12">
<a class="btn btn-link" href={% url 'institutions:list_and_add_admin' institution.id %}>Contributors list</a>
</div>
{% endif %}
</div>
</div>
Expand Down
2 changes: 1 addition & 1 deletion admin/templates/preprint_providers/detail.html
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@
<a class="btn btn-primary" href={% url 'preprint_providers:share_source' preprint_provider.id %}>Setup Share Source</a>
{% endif %}
{% if perms.osf.change_preprintprovider %}
<a class="btn btn-primary" href={% url 'preprint_providers:register_moderator_admin' preprint_provider.id %}>Register Moderator/Admin</a>
<a class="btn btn-primary" href={% url 'preprint_providers:add_admin_or_moderator' preprint_provider.id %}>Manage Admins and Moderators</a>
<a class="btn btn-primary" href={% url 'preprint_providers:edit' preprint_provider.id %}>Modify Preprint Provider</a>
{% if show_taxonomies %}
<a class="btn btn-primary" href={% url 'preprint_providers:process_custom_taxonomy' preprint_provider.id %}>Modify Custom Taxonomy</a>
Expand Down
63 changes: 63 additions & 0 deletions admin/templates/preprint_providers/edit_moderators.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
{% extends "base.html" %}
{% load static %}
{% load render_bundle from webpack_loader %}
{% block title %}
<title>Preprint Provider</title>
{% endblock title %}
{% block content %}
<div class="container-fluid">
<div class="row">
{% if messages %}
<ul>
{% for message in messages %}
<li{% if message.tags %} class="{{ message.tags }}"{% endif %}>{{ message }}</li>
{% endfor %}
</ul>
{% endif %}
</div>
<div class="row">
<div class="col-md-12 text-center">
<h2>{{ provider.name }}</h2>
</div>
</div>
<div class="row">
<div class="col-md-12">
<form id="add-moderators-form" action="{% url 'preprint_providers:add_admin_or_moderator' provider.id %}" method="post">
{% csrf_token %}
<label>Add moderator by guid: </label>
<input type="text" name="add-moderators-form">
<input type="submit" name="mod" value="Add Moderator" class="form-button btn btn-success">
<input type="submit" name="admin" value="Add Admin" class="form-button btn btn-success">
</form>
</div>
</div>
<hr>
<div class="row">
<div class="col-md-12">
<form id="remove-moderators-form" action="{% url 'preprint_providers:remove_admins_and_moderators' provider.id %}" method="post">
{% csrf_token %}
<table class="table table-striped">
<th></th>
<th>Name</th>
<th>Type</th>
{% for moderator in moderators %}
<tr>
<td><input type='checkbox' name="Moderator-{{moderator.id}}"></td>
<td>{{ moderator.fullname }} ({{moderator.username}})</td>
<td>Moderator</td>
</tr>
{% endfor %}
{% for admin in admins %}
<tr>
<td><input type='checkbox' name="Admin-{{admin.id}}"></td>
<td>{{ admin.fullname }} ({{admin.username}})</td>
<td>Admin</td>
</tr>
{% endfor %}
</table>
<input class="form-button btn btn-danger" type="submit" value="Remove Moderators/Admins" />
</form>
</div>
</div>
</div>
{% endblock content %}
96 changes: 95 additions & 1 deletion admin_tests/preprint_providers/test_views.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@
from admin.preprint_providers import views
from admin.preprint_providers.forms import PreprintProviderForm
from admin.base.forms import ImportFileForm

from django.contrib.messages.storage.fallback import FallbackStorage
import website

pytestmark = pytest.mark.django_db
Expand Down Expand Up @@ -424,3 +424,97 @@ def provider_factory(self):
def view(self, req):
plain_view = views.ProcessCustomTaxonomy()
return setup_view(plain_view, req)


from osf.migrations import update_provider_auth_groups

@pytest.mark.urls('admin.base.urls')
class TestEditModerators:

@pytest.fixture()
def req(self, user):
req = RequestFactory().get('/fake_path')
req.user = user
return req

@pytest.fixture()
def provider(self):
provider = PreprintProviderFactory()
update_provider_auth_groups()
return provider

@pytest.fixture()
def moderator(self, provider):
user = AuthUserFactory()
provider.add_to_group(user, 'moderator')
return user

@pytest.fixture()
def user(self):
return AuthUserFactory()

@pytest.fixture()
def remove_moderator_view(self, req, provider):
view = views.PreprintRemoveAdminsAndModerators()
view = setup_view(view, req)
view.kwargs = {'provider_id': provider.id}
return view

@pytest.fixture()
def add_moderator_view(self, req, provider):
view = views.PreprintAddAdminOrModerator()
view = setup_view(view, req)
view.kwargs = {'provider_id': provider.id}
return view

def test_get(self, add_moderator_view, remove_moderator_view, req):
res = add_moderator_view.get(req)
assert res.status_code == 200

res = remove_moderator_view.get(req)
assert res.status_code == 200

def test_post_remove(self, remove_moderator_view, req, moderator, provider):
moderator_id = f'Moderator-{moderator.id}'
req.POST = {
'csrfmiddlewaretoken': 'fake csfr',
moderator_id: ['on']
}

# django.contrib.messages has a bug which effects unittests
# more info here -> https://code.djangoproject.com/ticket/17971
setattr(req, 'session', 'session')
messages = FallbackStorage(req)
setattr(req, '_messages', messages)

res = remove_moderator_view.post(req)
assert res.status_code == 302
assert not provider.get_group('moderator').user_set.all()

def test_post_add(self, add_moderator_view, req, user, provider):
req.POST = {
'csrfmiddlewaretoken': 'fake csfr',
'add-moderators-form': [user._id],
'moderator': ['Add Moderator']
}

# django.contrib.messages has a bug which effects unittests
# more info here -> https://code.djangoproject.com/ticket/17971
setattr(req, 'session', 'session')
messages = FallbackStorage(req)
setattr(req, '_messages', messages)

res = add_moderator_view.post(req)
assert res.status_code == 302
assert user in provider.get_group('moderator').user_set.all()

# try to add the same user, but another group
req.POST = {
'csrfmiddlewaretoken': 'fake csfr',
'add-moderators-form': [user._id],
'admin': ['Add Admin']
}
res = add_moderator_view.post(req)
assert res.status_code == 302
assert user in provider.get_group('moderator').user_set.all()
assert user not in provider.get_group('admin').user_set.all()
Loading