Skip to content
Draft
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
106 changes: 57 additions & 49 deletions admin/base/urls.py
Original file line number Diff line number Diff line change
@@ -1,62 +1,70 @@
from django.conf.urls import include, url
from django.contrib import admin
from admin.base.settings import ADMIN_BASE, DEBUG
from admin.base.settings import ADMIN_BASE, DEBUG, ENABLE_LOGIN_FORM
from admin.base import views

base_pattern = '^{}'.format(ADMIN_BASE)

admin_urls = [
url(r'^$', views.home, name='home'),
url(r'^admin/', admin.site.urls),
url(r'^asset_files/', include('admin.asset_files.urls', namespace='asset_files')),
url(r'^banners/', include('admin.banners.urls', namespace='banners')),
url(r'^brands/', include('admin.brands.urls', namespace='brands')),
url(r'^spam/', include('admin.spam.urls', namespace='spam')),
url(r'^institutions/', include('admin.institutions.urls', namespace='institutions')),
url(r'^entitlements/', include('admin.entitlements.urls', namespace='entitlements')),
url(r'^quota_recalc/', include('admin.quota_recalc.urls', namespace='quota_recalc')),
url(r'^preprint_providers/', include('admin.preprint_providers.urls', namespace='preprint_providers')),
url(r'^collection_providers/', include('admin.collection_providers.urls', namespace='collection_providers')),
url(r'^registration_providers/', include('admin.registration_providers.urls', namespace='registration_providers')),
url(r'^account/', include('admin.common_auth.urls', namespace='auth')),
]

if ENABLE_LOGIN_FORM:
# password recovery/reset only makes sense while password-based login itself is enabled
admin_urls.append(url(r'^password/', include('password_reset.urls')))

admin_urls += [
url(r'^nodes/', include('admin.nodes.urls', namespace='nodes')),
url(r'^preprints/', include('admin.preprints.urls', namespace='preprints')),
url(r'^subjects/', include('admin.subjects.urls', namespace='subjects')),
url(r'^users/', include('admin.users.urls', namespace='users')),
url(r'^user-emails/', include('admin.user_emails.urls', namespace='user-emails')),
url(r'^maintenance/', include('admin.maintenance.urls', namespace='maintenance')),
url(r'^meetings/', include('admin.meetings.urls',
namespace='meetings')),
url(r'^metrics/', include('admin.metrics.urls',
namespace='metrics')),
url(r'^desk/', include('admin.desk.urls',
namespace='desk')),
url(r'^osf_groups/', include('admin.osf_groups.urls', namespace='osf_groups')),
url(r'^management/', include('admin.management.urls', namespace='management')),
url(r'^announcement/', include('admin.rdm_announcement.urls', namespace='announcement')),
url(r'^addons/', include('admin.rdm_addons.urls', namespace='addons')),
url(r'^oauth/', include('admin.rdm_addons.oauth.urls', namespace='oauth')),
url(r'^statistics/', include('admin.rdm_statistics.urls', namespace='statistics')),
url(r'^timestampadd/', include('admin.rdm_timestampadd.urls', namespace='timestampadd')),
url(r'^keymanagement/', include('admin.rdm_keymanagement.urls', namespace='keymanagement')),
url(r'^timestampsettings/', include('admin.rdm_timestampsettings.urls', namespace='timestampsettings')),
url(r'^custom_storage_location/', include('admin.rdm_custom_storage_location.urls', namespace='custom_storage_location')),
url(r'^institutional_storage_quota_control/', include('admin.institutional_storage_quota_control.urls',
namespace='institutional_storage_quota_control')),
url(r'^metadata/', include('admin.rdm_metadata.urls', namespace='metadata')),
url(r'^user_identification_information/',
include('admin.user_identification_information.urls', namespace='user_identification_information')),
url(r'^user_identification_information_admin/',
include('admin.user_identification_information_admin.urls', namespace='user_identification_information_admin')),
url(r'^project_limit_number/', include('admin.project_limit_number.urls', namespace='project_limit_number')),
url(r'^rdm_workflow/', include('admin.rdm_workflow.urls', namespace='rdm_workflow')),
url(r'^loa/', include('admin.loa.urls', namespace='loa')),
]

urlpatterns = [
### ADMIN ###
url(
base_pattern,
include([
url(r'^$', views.home, name='home'),
url(r'^admin/', admin.site.urls),
url(r'^asset_files/', include('admin.asset_files.urls', namespace='asset_files')),
url(r'^banners/', include('admin.banners.urls', namespace='banners')),
url(r'^brands/', include('admin.brands.urls', namespace='brands')),
url(r'^spam/', include('admin.spam.urls', namespace='spam')),
url(r'^institutions/', include('admin.institutions.urls', namespace='institutions')),
url(r'^entitlements/', include('admin.entitlements.urls', namespace='entitlements')),
url(r'^quota_recalc/', include('admin.quota_recalc.urls', namespace='quota_recalc')),
url(r'^preprint_providers/', include('admin.preprint_providers.urls', namespace='preprint_providers')),
url(r'^collection_providers/', include('admin.collection_providers.urls', namespace='collection_providers')),
url(r'^registration_providers/', include('admin.registration_providers.urls', namespace='registration_providers')),
url(r'^account/', include('admin.common_auth.urls', namespace='auth')),
url(r'^password/', include('password_reset.urls')),
url(r'^nodes/', include('admin.nodes.urls', namespace='nodes')),
url(r'^preprints/', include('admin.preprints.urls', namespace='preprints')),
url(r'^subjects/', include('admin.subjects.urls', namespace='subjects')),
url(r'^users/', include('admin.users.urls', namespace='users')),
url(r'^user-emails/', include('admin.user_emails.urls', namespace='user-emails')),
url(r'^maintenance/', include('admin.maintenance.urls', namespace='maintenance')),
url(r'^meetings/', include('admin.meetings.urls',
namespace='meetings')),
url(r'^metrics/', include('admin.metrics.urls',
namespace='metrics')),
url(r'^desk/', include('admin.desk.urls',
namespace='desk')),
url(r'^osf_groups/', include('admin.osf_groups.urls', namespace='osf_groups')),
url(r'^management/', include('admin.management.urls', namespace='management')),
url(r'^announcement/', include('admin.rdm_announcement.urls', namespace='announcement')),
url(r'^addons/', include('admin.rdm_addons.urls', namespace='addons')),
url(r'^oauth/', include('admin.rdm_addons.oauth.urls', namespace='oauth')),
url(r'^statistics/', include('admin.rdm_statistics.urls', namespace='statistics')),
url(r'^timestampadd/', include('admin.rdm_timestampadd.urls', namespace='timestampadd')),
url(r'^keymanagement/', include('admin.rdm_keymanagement.urls', namespace='keymanagement')),
url(r'^timestampsettings/', include('admin.rdm_timestampsettings.urls', namespace='timestampsettings')),
url(r'^custom_storage_location/', include('admin.rdm_custom_storage_location.urls', namespace='custom_storage_location')),
url(r'^institutional_storage_quota_control/', include('admin.institutional_storage_quota_control.urls',
namespace='institutional_storage_quota_control')),
url(r'^metadata/', include('admin.rdm_metadata.urls', namespace='metadata')),
url(r'^user_identification_information/',
include('admin.user_identification_information.urls', namespace='user_identification_information')),
url(r'^user_identification_information_admin/',
include('admin.user_identification_information_admin.urls', namespace='user_identification_information_admin')),
url(r'^project_limit_number/', include('admin.project_limit_number.urls', namespace='project_limit_number')),
url(r'^rdm_workflow/', include('admin.rdm_workflow.urls', namespace='rdm_workflow')),
url(r'^loa/', include('admin.loa.urls', namespace='loa')),
]),
include(admin_urls),
),
]

Expand Down
19 changes: 19 additions & 0 deletions admin/base/utils.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
"""
Utility functions and classes
"""
from functools import wraps

from osf.models import Subject, NodeLicense, Brand

from django.core.exceptions import ValidationError, PermissionDenied
Expand Down Expand Up @@ -35,6 +37,23 @@ def osf_staff_check(user):
return user.is_authenticated and user.is_staff


def osf_superuser_check(user):
return user.is_authenticated and user.is_superuser


def superuser_required(view_func):
"""Function-view decorator that returns 403 (PermissionDenied) instead of
redirecting to login, unlike django.contrib.auth.decorators.user_passes_test."""

@wraps(view_func)
def wrapped_view(request, *args, **kwargs):
if not osf_superuser_check(request.user):
raise PermissionDenied
return view_func(request, *args, **kwargs)

return wrapped_view


def get_subject_rules(subjects_selected):
"""
Take a list of subjects, and parse them into rules consistent with preprpint provider
Expand Down
8 changes: 5 additions & 3 deletions admin/collection_providers/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
from django.core import serializers
from django.core.exceptions import ValidationError
from django.urls import reverse_lazy
from django.shortcuts import redirect
from django.shortcuts import redirect, get_object_or_404
from django.views.generic import View, CreateView, ListView, DetailView, UpdateView, DeleteView, TemplateView
from django.contrib import messages
from django.contrib.auth.mixins import PermissionRequiredMixin
Expand Down Expand Up @@ -228,12 +228,14 @@ def get_object(self, queryset=None):
return CollectionProvider.objects.get(id=self.kwargs['collection_provider_id'])


class CannotDeleteProvider(TemplateView):
class CannotDeleteProvider(PermissionRequiredMixin, TemplateView):
permission_required = 'osf.delete_collectionprovider'
raise_exception = True
template_name = 'collection_providers/cannot_delete.html'

def get_context_data(self, **kwargs):
context = super(CannotDeleteProvider, self).get_context_data(**kwargs)
context['provider'] = CollectionProvider.objects.get(id=self.kwargs['collection_provider_id'])
context['provider'] = get_object_or_404(CollectionProvider, id=self.kwargs['collection_provider_id'])
return context


Expand Down
10 changes: 6 additions & 4 deletions admin/common_auth/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,10 +39,12 @@ def dispatch(self, request, *args, **kwargs):
return super(LoginView, self).dispatch(request, *args, **kwargs)

def form_valid(self, form):
user = authenticate(
username=form.cleaned_data.get('email').strip(),
password=form.cleaned_data.get('password').strip()
)
user = None
if ENABLE_LOGIN_FORM:
user = authenticate(
username=form.cleaned_data.get('email').strip(),
password=form.cleaned_data.get('password').strip()
)
if user is not None:
login(self.request, user)
else:
Expand Down
18 changes: 16 additions & 2 deletions admin/management/views.py
Original file line number Diff line number Diff line change
@@ -1,15 +1,29 @@
from django.contrib.auth.mixins import UserPassesTestMixin
from django.views.generic import TemplateView, View
from osf.management.commands.manage_switch_flags import manage_waffle
from django.core.urlresolvers import reverse
from django.shortcuts import redirect

class ManagementCommands(TemplateView):
from admin.rdm.utils import RdmPermissionMixin

class ManagementCommands(RdmPermissionMixin, UserPassesTestMixin, TemplateView):
""" Basic form to trigger various management commands
"""
template_name = 'management/commands.html'
object_type = 'management'
raise_exception = True

def test_func(self):
"""check user permissions"""
return self.is_super_admin


class WaffleFlag(RdmPermissionMixin, UserPassesTestMixin, View):
raise_exception = True

class WaffleFlag(View):
def test_func(self):
"""check user permissions"""
return self.is_super_admin

def post(self, request, *args, **kwargs):
manage_waffle()
Expand Down
8 changes: 5 additions & 3 deletions admin/preprint_providers/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
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.shortcuts import redirect, render, get_object_or_404

from admin.base import settings
from admin.base.forms import ImportFileForm
Expand Down Expand Up @@ -319,12 +319,14 @@ def get_object(self, queryset=None):
return PreprintProvider.objects.get(id=self.kwargs['preprint_provider_id'])


class CannotDeleteProvider(TemplateView):
class CannotDeleteProvider(PermissionRequiredMixin, TemplateView):
permission_required = 'osf.delete_preprintprovider'
raise_exception = True
template_name = 'preprint_providers/cannot_delete.html'

def get_context_data(self, **kwargs):
context = super(CannotDeleteProvider, self).get_context_data(**kwargs)
context['provider'] = PreprintProvider.objects.get(id=self.kwargs['preprint_provider_id'])
context['provider'] = get_object_or_404(PreprintProvider, id=self.kwargs['preprint_provider_id'])
return context


Expand Down
3 changes: 3 additions & 0 deletions admin/quota_recalc/views.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
from django.http import JsonResponse
from django.db import transaction, IntegrityError

from admin.base.utils import superuser_required
from addons.osfstorage.models import Region
from api.base import settings as api_settings
from osf.models import OSFUser, UserQuota, Node
Expand Down Expand Up @@ -60,6 +61,7 @@ def calculate_quota(user):
user_quota.used = used
user_quota.save()

@superuser_required
def all_users(request, **kwargs):
c = 0
for osf_user in OSFUser.objects.exclude(deleted__isnull=False):
Expand All @@ -70,6 +72,7 @@ def all_users(request, **kwargs):
'message': str(c) + ' users\' quota successfully recalculated!'
})

@superuser_required
def user(request, guid, **kwargs):
user = OSFUser.load(guid)
if user is None:
Expand Down
2 changes: 1 addition & 1 deletion admin/rdm_custom_storage_location/cron.sh
Original file line number Diff line number Diff line change
@@ -1 +1 @@
*/30 * * * * curl http://localhost:8001/custom_storage_location/external_acc_update/d610ef95f0b0f5868f13919b8ed64070b9acb9c19b8da9f2c514ed938203ec3e236c9cad4f4146bdf22b4e79cf0d92f6d4f4c996d236c6b0ee79a1336b26afb7/ | jq -c .
*/30 * * * * TOKEN=$(cd /code && python3 manage.py generate_signed_cron_token | tail -n1) && [ -n "$TOKEN" ] && curl "http://localhost:8001/custom_storage_location/external_acc_update/$TOKEN/" | jq -c .
2 changes: 1 addition & 1 deletion admin/rdm_custom_storage_location/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@


urlpatterns = [
url(r'^external_acc_update/(?P<access_token>-?\w+)/$', views.external_acc_update, name='external_acc_update'),
url(r'^external_acc_update/(?P<ts>\d+)/(?P<signature>[0-9a-fA-F]+)/$', views.external_acc_update, name='external_acc_update'),
url(r'^institutional_storage/$', views.InstitutionalStorageView.as_view(), name='institutional_storage'),
url(r'^institutional_storage/institutions/$', views.InstitutionalStorageListView.as_view(), name='institutional_storage_institutions'),
url(r'^institutional_storage/institutions/(?P<institution_id>[0-9]+)/$', views.InstitutionalStorageView.as_view(), name='institutional_storage_list'),
Expand Down
7 changes: 3 additions & 4 deletions admin/rdm_custom_storage_location/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@
from django.views.generic import TemplateView, View, ListView
import codecs
import json
import hashlib
from rest_framework import status as http_status
from mimetypes import MimeTypes
import os
Expand All @@ -19,13 +18,13 @@
from osf.models import Institution, OSFUser
from osf.models.external import ExternalAccountTemporary
from scripts import refresh_addon_tokens
from framework.auth import cron_signed_url
from website import settings as osf_settings
from distutils.util import strtobool
from admin.base import settings

logger = logging.getLogger(__name__)

SITE_KEY = 'rdm_custom_storage_location'
INSTITUTION_NOT_FOUND_MESSAGE = 'Institution does not exist'

class InstitutionalStorageBaseView(RdmPermissionMixin, UserPassesTestMixin):
Expand Down Expand Up @@ -522,8 +521,8 @@ def post(self, request, *args, **kwargs):
'message': 'Garbage data removed!!'
}, status=http_status.HTTP_200_OK)

def external_acc_update(request, access_token):
if hashlib.sha512(SITE_KEY.encode('utf-8')).hexdigest() != access_token.lower():
def external_acc_update(request, ts, signature):
if not cron_signed_url.verify_signed_params(ts, signature):
return HttpResponse(
json.dumps({'state': 'fail', 'error': 'access forbidden'}),
content_type='application/json',
Expand Down
2 changes: 1 addition & 1 deletion admin/rdm_statistics/cron.sh
Original file line number Diff line number Diff line change
@@ -1 +1 @@
0 2 * * 1 curl http://localhost:8001/statistics/gather/2A85563B2B0F7D3168199F475365F57DA1D56E4BB2CE2B7044EB058AE5E287637E7C636A772682D92C8D6B1830B9A97C5A5DC3DE7016C60BDE4BAA7CC3B38AEB/ | jq -c .
0 2 * * 1 TOKEN=$(cd /code && python3 manage.py generate_signed_cron_token | tail -n1) && [ -n "$TOKEN" ] && curl "http://localhost:8001/statistics/gather/$TOKEN/" | jq -c .
2 changes: 1 addition & 1 deletion admin/rdm_statistics/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
url(r'^index$', views.IndexView.as_view(), name='index'),
url(r'^(?P<institution_id>-?[0-9]+)/graph/(?P<graph_type>\w+)_(?P<provider>\w+)\.(\w+)$',
views.ImageView.as_view(), name='graph'),
url(r'^gather/(?P<access_token>-?\w+)/$', views.GatherView.as_view(), name='gather'),
url(r'^gather/(?P<ts>\d+)/(?P<signature>[0-9a-fA-F]+)/$', views.GatherView.as_view(), name='gather'),
url(r'^report/(?P<institution_id>-?[0-9]+)/$', views.create_pdf, name='report'),
url(r'^csv/(?P<institution_id>-?[0-9]+)/$', views.create_csv, name='csv'),
url(r'^mail/(?P<institution_id>-?[0-9]+)/$', views.SendView.as_view(), name='mail'),
Expand Down
Loading
Loading