From c2fe8ee8b6a492b145329325d47c8600637cd781 Mon Sep 17 00:00:00 2001 From: Mayo Faulkner Date: Wed, 8 Nov 2023 10:56:36 +0000 Subject: [PATCH 1/5] remove comma --- alyx/data/fixtures/data.datasettype.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/alyx/data/fixtures/data.datasettype.json b/alyx/data/fixtures/data.datasettype.json index 6c362bf1..910d5550 100644 --- a/alyx/data/fixtures/data.datasettype.json +++ b/alyx/data/fixtures/data.datasettype.json @@ -2220,5 +2220,5 @@ "description": "Look up table from photometry ROI, to fiber name registered in the database and Allen brain location", "filename_pattern": "*photometryROI.locations*" } - }, + } ] From c5a94e345691934fa29a39322e3c45fa0f5ee2ff Mon Sep 17 00:00:00 2001 From: github-actions Date: Wed, 8 Nov 2023 11:32:22 +0000 Subject: [PATCH 2/5] GitHub Actions generated requirements_frozen.txt --- requirements_frozen.txt | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/requirements_frozen.txt b/requirements_frozen.txt index bd2ad972..6e54f743 100644 --- a/requirements_frozen.txt +++ b/requirements_frozen.txt @@ -1,7 +1,7 @@ asgiref==3.7.2 backports.zoneinfo==0.2.1 -boto3==1.28.78 -botocore==1.31.78 +boto3==1.28.80 +botocore==1.31.80 certifi==2023.7.22 cffi==1.16.0 charset-normalizer==3.3.2 @@ -24,7 +24,7 @@ django-ipware==5.0.2 django-js-asset==2.1.0 django-mptt==0.14.0 django-polymorphic==3.1.0 -django-reversion==5.0.6 +django-reversion==5.0.7 django-storages==1.14.2 django-structlog==6.0.0 django-test-without-migrations==0.6 @@ -39,7 +39,7 @@ globus-sdk==3.28.0 iblutil==1.7.1 idna==3.4 importlib-metadata==6.8.0 -importlib-resources==6.1.0 +importlib-resources==6.1.1 itypes==1.2.0 Jinja2==3.1.2 jmespath==1.0.1 From 4eb68cf829df0b64b01b4d33a07793d1498345a3 Mon Sep 17 00:00:00 2001 From: olivier Date: Thu, 30 Nov 2023 10:45:03 +0000 Subject: [PATCH 3/5] user rest endpoint allows getting allowed users for iblrig login --- alyx/misc/serializers.py | 4 +++- alyx/misc/tests_rest.py | 9 ++++++++- alyx/misc/urls.py | 7 ++----- alyx/misc/views.py | 30 ++++++++++++++++++++++++----- scripts/sync_ucl/prune_cortexlab.py | 3 ++- 5 files changed, 40 insertions(+), 13 deletions(-) diff --git a/alyx/misc/serializers.py b/alyx/misc/serializers.py index e74f8c7e..464c2983 100644 --- a/alyx/misc/serializers.py +++ b/alyx/misc/serializers.py @@ -50,6 +50,8 @@ class Meta: class UserSerializer(serializers.ModelSerializer): subjects_responsible = serializers.SlugRelatedField( many=True, queryset=Subject.objects.all(), slug_field='nickname') + allowed_users = serializers.SlugRelatedField( + many=True, queryset=LabMember.objects.all(), slug_field='username') @staticmethod def setup_eager_loading(queryset): @@ -58,7 +60,7 @@ def setup_eager_loading(queryset): class Meta: model = get_user_model() - fields = ('id', 'username', 'email', 'subjects_responsible', 'lab') + fields = ('id', 'username', 'email', 'subjects_responsible', 'lab', 'allowed_users') class LabSerializer(serializers.HyperlinkedModelSerializer): diff --git a/alyx/misc/tests_rest.py b/alyx/misc/tests_rest.py index 9a3c26c1..37d2baa7 100644 --- a/alyx/misc/tests_rest.py +++ b/alyx/misc/tests_rest.py @@ -20,6 +20,7 @@ def setUp(self): self.lab = Lab.objects.create(name='basement') self.public_user = get_user_model().objects.create( username='troublemaker', password='azerty', is_public_user=True) + self.public_user.allowed_users.set([self.superuser]) def test_create_lab_membership(self): # first test creation of lab through rest endpoint @@ -55,6 +56,12 @@ def test_public_user(self): def test_user_rest(self): response = self.client.get(reverse('user-list') + '/test') self.ar(response, 200) + response = self.client.get(reverse('user-list') + '/troublemaker') + self.ar(response, 200) + self.assertEqual( + response.data.get('allowed_users'), + list(self.public_user.allowed_users.all().values_list('username', flat=True)) + ) def test_note_rest(self): user = self.ar(self.client.get(reverse('user-list')), 200) @@ -71,7 +78,7 @@ def test_note_rest(self): class TestCacheView(BaseTests): def setUp(self): - # This doesn't need super user privilages but I didn't know how to create a normal user + # This doesn't need super user privileges but I didn't know how to create a normal user self.superuser = get_user_model().objects.create_user('test', 'test', 'test') self.client.login(username='test', password='test') self.tag = Tag.objects.create(name='2022_Q1_paper') diff --git a/alyx/misc/urls.py b/alyx/misc/urls.py index 05db6211..a73f12ec 100644 --- a/alyx/misc/urls.py +++ b/alyx/misc/urls.py @@ -4,17 +4,14 @@ from django.conf.urls import include -user_list = mv.UserViewSet.as_view({'get': 'list'}) -user_detail = mv.UserViewSet.as_view({'get': 'retrieve'}) - urlpatterns = [ path('', RedirectView.as_view(url='/admin')), # redirect the page to admin interface path('labs', mv.LabList.as_view(), name="lab-list"), path('labs/', mv.LabDetail.as_view(), name="lab-detail"), path('notes', mv.NoteList.as_view(), name="note-list"), path('notes/', mv.NoteDetail.as_view(), name="note-detail"), - path('users/', user_detail, name='user-detail'), - path('users', user_list, name='user-list'), + path('users', mv.UserList.as_view(), name="user-list"), + path('users/', mv.UserDetail.as_view(), name="user-detail"), re_path('^uploaded/(?P.*)', mv.UploadedView.as_view(), name='uploaded'), path('cache.zip', mv.CacheDownloadView.as_view(), name='cache-download'), re_path(r'^cache/info(?:/(?P\w+))?/$', mv.CacheVersionView.as_view(), name='cache-info'), diff --git a/alyx/misc/views.py b/alyx/misc/views.py index 15ade025..4423a778 100644 --- a/alyx/misc/views.py +++ b/alyx/misc/views.py @@ -10,7 +10,7 @@ HttpResponse, FileResponse, JsonResponse, HttpResponseRedirect, HttpResponseNotFound ) -from rest_framework import viewsets, views +from rest_framework import views from rest_framework.response import Response from rest_framework.decorators import api_view from rest_framework.reverse import reverse @@ -69,15 +69,35 @@ def api_root(request, format=None): }) -class UserViewSet(viewsets.ReadOnlyModelViewSet): +class UserFilter(BaseFilterSet): + class Meta: + model = get_user_model() + exclude = ['json'] + + +class UserList(generics.ListCreateAPIView): """ - Lists all users with the subjects which they are responsible for. + get: **FILTERS** + - 'id' + - 'username' + - 'email' + - 'subjects_responsible' + - 'lab' + - 'allowed_users' + [===> user model reference](/admin/doc/models/misc.labmember) """ - queryset = get_user_model().objects.all() - queryset = UserSerializer.setup_eager_loading(queryset) + queryset = UserSerializer.setup_eager_loading(get_user_model().objects.all()) serializer_class = UserSerializer + permission_classes = rest_permission_classes() + filter_class = UserFilter lookup_field = 'username' + + +class UserDetail(generics.RetrieveUpdateDestroyAPIView): + queryset = UserSerializer.setup_eager_loading(get_user_model().objects.all()) + serializer_class = UserSerializer permission_classes = rest_permission_classes() + lookup_field = 'username' class LabFilter(BaseFilterSet): diff --git a/scripts/sync_ucl/prune_cortexlab.py b/scripts/sync_ucl/prune_cortexlab.py index 441131d8..e3dbd909 100755 --- a/scripts/sync_ucl/prune_cortexlab.py +++ b/scripts/sync_ucl/prune_cortexlab.py @@ -83,7 +83,8 @@ # only imports users that are relevant to IBL users_to_import = ['cyrille', 'Gaelle', 'kenneth', 'lauren', 'matteo', 'miles', 'nick', 'olivier', - 'Karolina_Socha', 'Hamish', 'laura', 'niccolo', 'SamuelP', 'miriam.jansen', 'carolina.quadrado'] + 'Karolina_Socha', 'Hamish', 'laura', 'niccolo', 'SamuelP', 'miriam.jansen', + 'carolina.quadrado'] users_to_leave = LabMember.objects.using('cortexlab').exclude(username__in=users_to_import) users_to_keep = Dataset.objects.using('cortexlab').values_list('created_by', flat=True).distinct() users_to_leave = users_to_leave.exclude(pk__in=users_to_keep) From 20eae4c025a571b03de47f18447c00744814e057 Mon Sep 17 00:00:00 2001 From: olivier Date: Thu, 30 Nov 2023 10:57:15 +0000 Subject: [PATCH 4/5] bump version number --- alyx/alyx/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/alyx/alyx/__init__.py b/alyx/alyx/__init__.py index d08f5d9b..e7b3befd 100644 --- a/alyx/alyx/__init__.py +++ b/alyx/alyx/__init__.py @@ -1 +1 @@ -VERSION = __version__ = '1.16.2' +VERSION = __version__ = '1.17.0' From 236dbba80d625e5ae03488baadad6cc41ed8ce39 Mon Sep 17 00:00:00 2001 From: github-actions Date: Thu, 30 Nov 2023 11:02:51 +0000 Subject: [PATCH 5/5] GitHub Actions generated requirements_frozen.txt --- requirements_frozen.txt | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/requirements_frozen.txt b/requirements_frozen.txt index 6e54f743..c7154991 100644 --- a/requirements_frozen.txt +++ b/requirements_frozen.txt @@ -1,8 +1,8 @@ asgiref==3.7.2 backports.zoneinfo==0.2.1 -boto3==1.28.80 -botocore==1.31.80 -certifi==2023.7.22 +boto3==1.33.4 +botocore==1.33.4 +certifi==2023.11.17 cffi==1.16.0 charset-normalizer==3.3.2 click==8.1.7 @@ -12,7 +12,7 @@ coreapi==2.3.3 coreschema==0.0.4 coverage==6.5.0 coveralls==3.3.1 -cryptography==41.0.5 +cryptography==41.0.7 cycler==0.12.1 Django==4.2.7 django-admin-list-filter-dropdown==1.0.3 @@ -24,20 +24,20 @@ django-ipware==5.0.2 django-js-asset==2.1.0 django-mptt==0.14.0 django-polymorphic==3.1.0 -django-reversion==5.0.7 +django-reversion==5.0.8 django-storages==1.14.2 -django-structlog==6.0.0 +django-structlog==6.0.1 django-test-without-migrations==0.6 djangorestframework==3.14.0 docopt==0.6.2 docutils==0.20.1 drfdocs==0.0.11 flake8==6.1.0 -fonttools==4.44.0 -globus-cli==3.18.0 -globus-sdk==3.28.0 +fonttools==4.45.1 +globus-cli==3.19.0 +globus-sdk==3.30.0 iblutil==1.7.1 -idna==3.4 +idna==3.6 importlib-metadata==6.8.0 importlib-resources==6.1.1 itypes==1.2.0 @@ -48,7 +48,7 @@ llvmlite==0.41.1 lxml==4.9.3 Markdown==3.5.1 MarkupSafe==2.1.3 -matplotlib==3.7.3 +matplotlib==3.7.4 mccabe==0.7.0 numba==0.58.1 numpy==1.24.4 @@ -57,7 +57,7 @@ packaging==23.2 pandas==2.0.3 Pillow==10.1.0 psycopg2-binary==2.9.9 -pyarrow==14.0.0 +pyarrow==14.0.1 pycodestyle==2.11.1 pycparser==2.21 pyflakes==3.1.0 @@ -68,7 +68,7 @@ python-magic==0.4.27 pytz==2023.3.post1 PyYAML==6.0.1 requests==2.31.0 -s3transfer==0.7.0 +s3transfer==0.8.2 six==1.16.0 sqlparse==0.4.4 structlog==23.2.0