From a7457957df62dd96644202a321b0c064f39b4128 Mon Sep 17 00:00:00 2001 From: Glauber Costa Vila-Verde Date: Mon, 24 May 2021 11:43:37 -0300 Subject: [PATCH] =?UTF-8?q?=E2=80=A6=20(#1364)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * A new model was created that allows to associate a user group to a release. The queries for the release and dataset views have been changed so that only records related to public releases or releases associated with the group that the user belongs to are returned. An additional get_user_releases method was created for the User models, this method returns all the release ids that the user is allowed to access. Closed #1363 * minor fix --- api/coadd/admin.py | 11 +++- .../migrations/0005_release_rls_is_public.py | 18 ++++++ .../migrations/0006_releasegrouppermission.py | 22 +++++++ .../migrations/0007_auto_20210520_1849.py | 19 ++++++ api/coadd/models.py | 62 ++++++++++++++++++- api/coadd/serializers.py | 1 + api/coadd/views.py | 29 ++++++++- api/common/models.py | 2 +- api/common/views.py | 4 +- api/dri/urls.py | 2 +- 10 files changed, 161 insertions(+), 9 deletions(-) create mode 100644 api/coadd/migrations/0005_release_rls_is_public.py create mode 100644 api/coadd/migrations/0006_releasegrouppermission.py create mode 100644 api/coadd/migrations/0007_auto_20210520_1849.py diff --git a/api/coadd/admin.py b/api/coadd/admin.py index a1f4d4d7..53a33ae8 100644 --- a/api/coadd/admin.py +++ b/api/coadd/admin.py @@ -1,16 +1,20 @@ from django.contrib import admin -from .models import Release, Tile, Tag, Dataset, Survey +from .models import Release, ReleaseGroupPermission, Tile, Tag, Dataset, Survey class ReleaseAdmin(admin.ModelAdmin): list_display = ('id', 'rls_name', 'rls_display_name', 'rls_version', 'rls_date', 'rls_description', 'rls_doc_url', - 'rls_default', 'rls_disabled') + 'rls_default', 'rls_disabled', 'rls_is_public') list_display_links = ('id', 'rls_name', 'rls_display_name', 'rls_version', 'rls_date', 'rls_description', 'rls_doc_url', 'rls_default',) - search_fields = ('id', 'rls_name', 'rls_display_name',) + search_fields = ('id', 'rls_name', 'rls_display_name', ) + + +class ReleaseGroupPermissionAdmin(admin.ModelAdmin): + list_display = ('id', 'rgp_release', 'rgp_user_group', ) class TileAdmin(admin.ModelAdmin): @@ -51,6 +55,7 @@ class SurveyAdmin(admin.ModelAdmin): admin.site.register(Release, ReleaseAdmin) +admin.site.register(ReleaseGroupPermission, ReleaseGroupPermissionAdmin) admin.site.register(Tile, TileAdmin) admin.site.register(Tag, TagAdmin) admin.site.register(Dataset, DatasetAdmin) diff --git a/api/coadd/migrations/0005_release_rls_is_public.py b/api/coadd/migrations/0005_release_rls_is_public.py new file mode 100644 index 00000000..5065dc19 --- /dev/null +++ b/api/coadd/migrations/0005_release_rls_is_public.py @@ -0,0 +1,18 @@ +# Generated by Django 2.2.17 on 2021-05-19 14:25 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('coadd', '0004_release_rls_disabled'), + ] + + operations = [ + migrations.AddField( + model_name='release', + name='rls_is_public', + field=models.BooleanField(default=False, help_text='Mark the release as public so that it is available to all users. uncheck it to make it available only to groups that have permission.', verbose_name='Is Public'), + ), + ] diff --git a/api/coadd/migrations/0006_releasegrouppermission.py b/api/coadd/migrations/0006_releasegrouppermission.py new file mode 100644 index 00000000..e0ccfeb7 --- /dev/null +++ b/api/coadd/migrations/0006_releasegrouppermission.py @@ -0,0 +1,22 @@ +# Generated by Django 2.2.17 on 2021-05-20 18:29 + +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + dependencies = [ + ('coadd', '0005_release_rls_is_public'), + ] + + operations = [ + migrations.CreateModel( + name='ReleaseGroupPermission', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('rgp_release', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='release_group_permission', to='coadd.Release', verbose_name='Release')), + ('rgp_user_group', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='coadd.Release', verbose_name='User Group')), + ], + ), + ] diff --git a/api/coadd/migrations/0007_auto_20210520_1849.py b/api/coadd/migrations/0007_auto_20210520_1849.py new file mode 100644 index 00000000..28d55548 --- /dev/null +++ b/api/coadd/migrations/0007_auto_20210520_1849.py @@ -0,0 +1,19 @@ +# Generated by Django 2.2.17 on 2021-05-20 18:49 + +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + dependencies = [ + ('coadd', '0006_releasegrouppermission'), + ] + + operations = [ + migrations.AlterField( + model_name='releasegrouppermission', + name='rgp_user_group', + field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='auth.Group', verbose_name='User Group'), + ), + ] diff --git a/api/coadd/models.py b/api/coadd/models.py index 382fc28f..c1b8d1c3 100644 --- a/api/coadd/models.py +++ b/api/coadd/models.py @@ -1,12 +1,14 @@ import logging +from django.contrib.auth.models import Group, User from django.db import models +from django.db.models import Q logger = logging.getLogger(__name__) -# Create your models here. class Release(models.Model): + rls_name = models.CharField( max_length=60, verbose_name='Internal Name') rls_display_name = models.CharField( @@ -26,10 +28,29 @@ class Release(models.Model): default=False, verbose_name='Disabled', help_text='Mark this release as Disabled so that the interfaces cant select this release.') + rls_is_public = models.BooleanField( + default=False, verbose_name='Is Public', + help_text='Mark the release as public so that it is available to all users. uncheck it to make it available only to groups that have permission.') + def __str__(self): return self.rls_display_name +class ReleaseGroupPermission(models.Model): + rgp_release = models.ForeignKey( + Release, + related_name='release_group_permission', + on_delete=models.CASCADE, + verbose_name='Release' + ) + + rgp_user_group = models.ForeignKey( + Group, + on_delete=models.CASCADE, + verbose_name='User Group' + ) + + class Tile(models.Model): tli_tilename = models.CharField( db_index=True, max_length=20, unique=True, verbose_name='Tilename') @@ -165,3 +186,42 @@ class Survey(models.Model): def __str__(self): return str(self.srv_display_name) + + +def get_user_releases(self): + """Esta função é adicionada ao model User, + ela retorna os ids de todos os releases que o usuario tem permisão de acessar. + + 1 - Se o usuario é um staff do admin, retorna todos os releases HABILITADOS (rls_disabled=False) + + 2 - Para os demais usuarios, retorna todos os releases publicos (rls_is_public=True) e OU filtra pelos grupos dos usuarios, + esses grupos devem estar associados aos releases no model ReleaseGroupPermission. + + Returns: + [list]: Lista de ids dos releases que o usuario pode ter acesso. + """ + + releases = list() + # Se for um usuario Admin do django retorna todos os releases Habilitados. + if self.is_staff: + releases = Release.objects.filter(rls_disabled=False) + else: + # IDs dos grupos que o usuario faz parte + a_groups = [] + for group in self.groups.all(): + a_groups.append(group.pk) + + # Todos os Releases Publicos + os Releases relacionados aos grupos que o usuario pertence. + releases = Release.objects.filter( + Q(rls_disabled=False) & Q( + Q(rls_is_public=True) | Q(release_group_permission__rgp_user_group__in=a_groups)) + ) + + ids = list() + for release in releases: + ids.append(release.pk) + + return ids + + +User.add_to_class('get_user_releases', get_user_releases) diff --git a/api/coadd/serializers.py b/api/coadd/serializers.py index 91cdcf5c..41711c35 100644 --- a/api/coadd/serializers.py +++ b/api/coadd/serializers.py @@ -24,6 +24,7 @@ class Meta: 'rls_description', 'rls_default', 'rls_disabled', + 'rls_is_public', 'tags_count', 'tiles_count', ) diff --git a/api/coadd/views.py b/api/coadd/views.py index 435579ac..e932e7b5 100644 --- a/api/coadd/views.py +++ b/api/coadd/views.py @@ -18,6 +18,7 @@ TileSerializer) from common.desaccess import DesAccessApi +from django.db.models import Q class ReleaseViewSet(viewsets.ModelViewSet): @@ -25,7 +26,7 @@ class ReleaseViewSet(viewsets.ModelViewSet): API endpoint that allows releases to be viewed or edited """ - queryset = Release.objects.filter(rls_disabled=False) + # queryset = Release.objects.filter(rls_disabled=False) serializer_class = ReleaseSerializer @@ -35,6 +36,20 @@ class ReleaseViewSet(viewsets.ModelViewSet): ordering_fields = '__all__' + def get_queryset(self): + + # Se o usuario for admin do Django retorna todos os releases Habilitados + if self.request.user.is_staff: + return Release.objects.filter(rls_disabled=False) + else: + # Retorna os IDs de todos os releases que o usuario tem permissão de acessar. + perm_releases = self.request.user.get_user_releases() + + # Todos os Releases Publicos + os Releases relacionados aos grupos que o usuario pertence. + queryset = Release.objects.filter(pk__in=perm_releases) + + return queryset + class TagViewSet(viewsets.ModelViewSet): """ @@ -165,7 +180,7 @@ def filter_inspected(self, queryset, name, value): class DatasetViewSet(viewsets.ModelViewSet): - queryset = Dataset.objects.select_related().all().prefetch_related('comments').prefetch_related('inspected') + # queryset = Dataset.objects.select_related().all().prefetch_related('comments').prefetch_related('inspected') serializer_class = DatasetSerializer @@ -179,6 +194,16 @@ class DatasetViewSet(viewsets.ModelViewSet): ordering = ('tile__tli_tilename',) + def get_queryset(self): + + # Recuperar os releases que o usuario tem acesso + releases = self.request.user.get_user_releases() + + # Filtra a tabela de datasets pelo id dos releases que o usuario tem acesso. + queryset = Dataset.objects.select_related().all().prefetch_related('comments').prefetch_related('inspected').filter(tag__tag_release__pk__in=releases) + + return queryset + @action(detail=True) def desaccess_tile_info(self, request, pk=None): """Search DESaccess for tilename and return a list of tile files already filtered by the dataset release. diff --git a/api/common/models.py b/api/common/models.py index 4b0bff9e..a4af1698 100755 --- a/api/common/models.py +++ b/api/common/models.py @@ -1,6 +1,6 @@ # Create your models here. -from django.db import models from django.contrib.auth.models import User +from django.db import models from django.db.models.signals import post_save from django.dispatch import receiver diff --git a/api/common/views.py b/api/common/views.py index bda3dff5..3d453218 100755 --- a/api/common/views.py +++ b/api/common/views.py @@ -349,4 +349,6 @@ def get_ncsa_signup(request): def teste(request): if request.method == 'GET': - return Response(dict({'status': "success"})) + releases = request.user.get_user_releases() + + return Response(dict({'status': "success", "releases": releases})) diff --git a/api/dri/urls.py b/api/dri/urls.py index 99e7abb3..0c521c56 100644 --- a/api/dri/urls.py +++ b/api/dri/urls.py @@ -37,7 +37,7 @@ router.register(r'logged', common_views.LoggedUserViewSet, basename='logged') router.register(r'users_same_group', common_views.UsersInSameGroupViewSet, basename='users_same_group') -router.register(r'releases', coadd_views.ReleaseViewSet) +router.register(r'releases', coadd_views.ReleaseViewSet, basename='releases') router.register(r'tags', coadd_views.TagViewSet) router.register(r'tiles', coadd_views.TileViewSet) router.register(r'dataset', coadd_views.DatasetViewSet, basename='dataset')