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
2 changes: 2 additions & 0 deletions admin/institutions/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,5 +20,7 @@
name='list_and_add_admin'),
re_path(r'^(?P<institution_id>[0-9]+)/remove_admins/$', views.InstitutionRemoveAdmin.as_view(),
name='remove_admins'),
re_path(r'^(?P<institution_id>[0-9]+)/affiliations/$', views.InstitutionListAndAddAffiliation.as_view(), name='affiliations'),
re_path(r'^(?P<institution_id>[0-9]+)/remove_affiliations/$', views.InstitutionRemoveAffiliation.as_view(), name='remove_affiliations'),

]
60 changes: 60 additions & 0 deletions admin/institutions/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -373,3 +373,63 @@ def form_valid(self, form):

def get_success_url(self):
return reverse('institutions:register_metrics_admin', kwargs={'institution_id': self.kwargs['institution_id']})


class InstitutionAffiliationBaseView(PermissionRequiredMixin, ListView):
permission_required = 'osf.change_institution'
template_name = 'institutions/edit_affiliations.html'
raise_exception = True

def get_queryset(self):
return Institution.objects.get(id=self.kwargs['institution_id'])

def get_context_data(self, **kwargs):
institution = Institution.objects.get(id=self.kwargs['institution_id'])
context = super().get_context_data(**kwargs)
context['institution'] = institution
context['affiliations'] = institution.get_institution_users()
return context


class InstitutionListAndAddAffiliation(InstitutionAffiliationBaseView):

def get_permission_required(self):
if self.request.method == 'GET':
return ('osf.view_institution',)
return (self.permission_required,)

def post(self, request, *args, **kwargs):
institution = Institution.objects.get(id=self.kwargs['institution_id'])
data = dict(request.POST)
del data['csrfmiddlewaretoken'] # just to remove the key from the form dict

target_user = OSFUser.load(data['add-affiliation-form'][0])
if target_user is None:
messages.error(request, f'User for guid: {data["add-affiliation-form"][0]} could not be found')
return redirect('institutions:affiliations', institution_id=institution.id)

target_user.add_or_update_affiliated_institution(institution)

messages.success(request, f'The following user was successfully added: {target_user.fullname} ({target_user.username})')

return redirect('institutions:affiliations', institution_id=institution.id)


class InstitutionRemoveAffiliation(InstitutionAffiliationBaseView):

def post(self, request, *args, **kwargs):
institution = Institution.objects.get(id=self.kwargs['institution_id'])
data = dict(request.POST)
del data['csrfmiddlewaretoken'] # just to remove the key from the form dict

to_be_removed = list(data.keys())
removed_affiliations = [user.replace('User-', '') for user in to_be_removed if 'User-' in user]
affiliated_users = OSFUser.objects.filter(id__in=removed_affiliations)
for user in affiliated_users:
user.remove_affiliated_institution(institution._id)

if affiliated_users:
users_names = ' ,'.join(affiliated_users.values_list('fullname', flat=True))
messages.success(request, f'The following users were successfully removed: {users_names}')

return redirect('institutions:affiliations', institution_id=institution.id)
11 changes: 6 additions & 5 deletions admin/templates/institutions/detail.html
Original file line number Diff line number Diff line change
Expand Up @@ -24,11 +24,12 @@
<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 %}
<a class="btn btn-primary" href={% url 'institutions:affiliations' institution.id %}>Affiliations</a>
{% endif %}
{% if perms.osf.change_institution %}
<a class="btn btn-primary" href={% url 'institutions:list_and_add_admin' institution.id %}>Manage Admins</a>
Expand Down
55 changes: 55 additions & 0 deletions admin/templates/institutions/edit_affiliations.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
{% extends "base.html" %}
{% load static %}
{% load render_bundle from webpack_loader %}
{% block title %}
<title>Institution Affiliations</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>{{ institution.name }}</h2>
</div>
</div>
<div class="row">
<div class="col-md-12">
<form id="add-affiliation-form" action="{% url 'institutions:affiliations' institution.id %}" method="post">
{% csrf_token %}
<label>Add user by guid: </label>
<input type="text" name="add-affiliation-form">
<input type="submit" name="user" value="Add User" class="form-button btn btn-success">
</form>
</div>
</div>
<hr>
<div class="row">
<div class="col-md-12">
<form id="remove-affiliation-form" action="{% url 'institutions:remove_affiliations' institution.id %}" method="post">
{% csrf_token %}
<table class="table table-striped">
<th></th>
<th>Name</th>
<th>Username</th>
{% for user in affiliations %}
<tr>
<td><input type='checkbox' name="User-{{user.id}}"></td>
<td>{{ user.fullname }}</td>
<td>{{ user.username }}</td>
</tr>
{% endfor %}
</table>
<input class="form-button btn btn-danger" type="submit" value="Remove affiliation" />
</form>
</div>
</div>
</div>
{% endblock content %}
55 changes: 55 additions & 0 deletions admin/templates/users/affiliated_institutions.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
{% extends "base.html" %}
{% load static %}
{% load render_bundle from webpack_loader %}
{% block title %}
<title>Affiliated Institutions</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>{{ institution.name }}</h2>
</div>
</div>
<div class="row">
<div class="col-md-12">
<form id="add-affiliation-form" action="{% url 'users:affiliations' guid=user.guid %}" method="post">
{% csrf_token %}
<label>Add Institution by guid: </label>
<input type="text" name="add-affiliation-form">
<input type="submit" name="user" value="Add Institution" class="form-button btn btn-success">
</form>
</div>
</div>
<hr>
<div class="row">
<div class="col-md-12">
<form id="remove-affiliation-form" action="{% url 'users:remove_affiliations' guid=user.guid %}" method="post">
{% csrf_token %}
<table class="table table-striped">
<th></th>
<th>Name</th>
<th>Guid</th>
{% for institution in institutions %}
<tr>
<td><input type='checkbox' name="institution-{{institution.id}}"></td>
<td>{{ institution.name }}</td>
<td>{{ institution.guid }}</td>
</tr>
{% endfor %}
</table>
<input class="form-button btn btn-danger" type="submit" value="Remove affiliation" />
</form>
</div>
</div>
</div>
{% endblock content %}
3 changes: 3 additions & 0 deletions admin/templates/users/user.html
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,9 @@
{% include "users/disable_user.html" with user=user %}
{% include "users/mark_spam.html" with user=user %}
{% include "users/reindex_user_elastic.html" with user=user %}
{% if perms.osf.change_institution %}
<a class="btn btn-primary" href="{% url 'users:affiliations' guid=user.guid %}">Affiliations</a>
{% endif %}
</div>
</div>
</div>
Expand Down
2 changes: 2 additions & 0 deletions admin/users/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,4 +28,6 @@
name='reindex-elastic-user'),
re_path(r'^(?P<guid>[a-z0-9]+)/merge_accounts/$', views.UserMergeAccounts.as_view(), name='merge-accounts'),
re_path(r'^(?P<guid>[a-z0-9]+)/draft_registrations/$', views.UserDraftRegistrationsList.as_view(), name='draft-registrations'),
re_path(r'^(?P<guid>[a-z0-9]+)/affiliations/$', views.UserListAndAddAffiliations.as_view(), name='affiliations'),
re_path(r'^(?P<guid>[a-z0-9]+)/remove_affiliations/$', views.UserRemoveAffiliations.as_view(), name='remove_affiliations'),
]
58 changes: 58 additions & 0 deletions admin/users/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
from osf.models.spam import SpamStatus
from framework.auth import get_user
from framework.auth.core import generate_verification_key
from osf.models.institution import Institution

from website import search
from website.settings import EXTERNAL_IDENTITY_PROFILE
Expand Down Expand Up @@ -575,3 +576,60 @@ def get_context_data(self, **kwargs):
'draft_registrations': query_set
}
)


class UserAffiliationBaseView(UserMixin, ListView):
permission_required = 'osf.change_institution'
template_name = 'users/affiliated_institutions.html'
raise_exception = True

def get_queryset(self):
# Django template does not like attributes with underscores for some reason, so we annotate.
return self.get_object().get_affiliated_institutions().annotate(
guid=F('_id')
)

def get_context_data(self, **kwargs):
institutions = self.get_queryset()
context = super().get_context_data(**kwargs)
context['institutions'] = institutions
context['user'] = self.get_object()
return context


class UserRemoveAffiliations(UserAffiliationBaseView):

def post(self, request, *args, **kwargs):
user = self.get_object()
data = dict(request.POST)

to_be_removed = list(data.keys())
removed_affiliations = [institution.replace('institution-', '') for institution in to_be_removed if 'institution-' in institution]
institutions_qs = Institution.objects.filter(id__in=removed_affiliations)
for institution in institutions_qs:
user.remove_affiliated_institution(institution._id)

if institutions_qs:
institutions_names = ' ,'.join(institutions_qs.values_list('name', flat=True))
messages.success(request, f'The following users were successfully removed: {institutions_names}')

return redirect('users:affiliations', guid=user.guid)


class UserListAndAddAffiliations(UserAffiliationBaseView):

def post(self, request, *args, **kwargs):
user = self.get_object()
data = dict(request.POST)
del data['csrfmiddlewaretoken'] # just to remove the key from the form dict

institution = Institution.load(data['add-affiliation-form'][0])
if institution is None:
messages.error(request, f'Institution for guid: {data["add-affiliation-form"][0]} could not be found')
return redirect('users:affiliations', guid=user.guid)

user.add_or_update_affiliated_institution(institution)

messages.success(request, f'The following institution was successfully added: {institution.name}')

return redirect('users:affiliations', guid=user.guid)
Loading