diff options
author | Stevan Radaković <stevan.radakovic@linaro.org> | 2015-10-19 18:37:41 +0200 |
---|---|---|
committer | Linaro Code Review <review@review.linaro.org> | 2015-10-22 12:24:24 +0000 |
commit | 8758fa331c971c9dd9c6ebe63c990ec3ad068dc5 (patch) | |
tree | 28aedaa88d26d5cd6ceb204e5d3398697f7c6d3f | |
parent | 397e0a12ca9008997c4d123e4545bfbc63ac5347 (diff) |
Query app visibility rules.
Add new manager/queryset classes for testjob, testsuite and
testcase and the respective view classes.
Add new queryset method visible_by_user which can be directly
applied to the db views' querysets.
Change-Id: I657db8a0296b263f54d9ebea7d573876fb4b334c
-rw-r--r-- | lava_results_app/models.py | 33 | ||||
-rw-r--r-- | lava_results_app/views/query/views.py | 10 | ||||
-rw-r--r-- | lava_scheduler_app/managers.py | 88 | ||||
-rw-r--r-- | lava_scheduler_app/models.py | 9 | ||||
-rwxr-xr-x | setup.py | 2 |
5 files changed, 131 insertions, 11 deletions
diff --git a/lava_results_app/models.py b/lava_results_app/models.py index fc829817d..c9961e759 100644 --- a/lava_results_app/models.py +++ b/lava_results_app/models.py @@ -49,6 +49,12 @@ from lava_scheduler_app.models import ( Device, DeviceType ) +from lava_scheduler_app.managers import ( + RestrictedTestJobQuerySet, + RestrictedTestCaseQuerySet, + RestrictedTestSuiteQuerySet +) + from lava_results_app.utils import help_max_length # TODO: this may need to be ported - clashes if redefined @@ -117,6 +123,9 @@ class TestSuite(models.Model): Top level grouping of results from a job. Directly linked to a single TestJob, the job can have multiple TestSets. """ + + objects = models.Manager.from_queryset(RestrictedTestSuiteQuerySet)() + job = models.ForeignKey( TestJob, ) @@ -180,6 +189,9 @@ class TestCase(models.Model): Result of an individual test case. lava-test-case or action result """ + + objects = models.Manager.from_queryset(RestrictedTestCaseQuerySet)() + RESULT_PASS = 0 RESULT_FAIL = 1 RESULT_SKIP = 2 @@ -490,6 +502,8 @@ def TestJobViewFactory(query): class TestJobMaterializedView(QueryMaterializedView, TestJob): + objects = models.Manager.from_queryset(RestrictedTestJobQuerySet)() + class Meta(QueryMaterializedView.Meta): db_table = '%s%s' % (QueryMaterializedView.QUERY_VIEW_PREFIX, query.id) @@ -501,6 +515,8 @@ def TestCaseViewFactory(query): class TestCaseMaterializedView(QueryMaterializedView, TestCase): + objects = models.Manager.from_queryset(RestrictedTestCaseQuerySet)() + class Meta(QueryMaterializedView.Meta): db_table = '%s%s' % (QueryMaterializedView.QUERY_VIEW_PREFIX, query.id) @@ -512,6 +528,8 @@ def TestSuiteViewFactory(query): class TestSuiteMaterializedView(QueryMaterializedView, TestSuite): + objects = models.Manager.from_queryset(RestrictedTestSuiteQuerySet)() + class Meta(QueryMaterializedView.Meta): db_table = '%s%s' % (QueryMaterializedView.QUERY_VIEW_PREFIX, query.id) @@ -592,10 +610,10 @@ class Query(models.Model): def __unicode__(self): return "<Query ~%s/%s>" % (self.owner.username, self.name) - def get_results(self): + def get_results(self, user): if self.is_live: return Query.get_queryset(self.content_type, - self.querycondition_set.all()) + self.querycondition_set.all()).visible_by_user(user) else: if self.content_type.model_class() == TestJob: view = TestJobViewFactory(self) @@ -604,10 +622,15 @@ class Query(models.Model): elif self.content_type.model_class() == TestSuite: view = TestSuiteViewFactory(self) - return view.__class__.objects.all() + return view.__class__.objects.all().visible_by_user(user) @classmethod def get_queryset(cls, content_type, conditions): + """ Return list of QuerySet objects for class 'content_type'. + + Be mindful when using this method directly as it does not apply the + visibility rules. + """ logger = logging.getLogger('lava_results_app') filters = {} @@ -731,8 +754,8 @@ class Query(models.Model): super(Query, self).delete(*args, **kwargs) def is_accessible_by(self, user): - if user.is_superuser or query.user == user or \ - query.group in user.groups.all(): + if user.is_superuser or self.owner == user or \ + self.group in user.groups.all(): return True return False diff --git a/lava_results_app/views/query/views.py b/lava_results_app/views/query/views.py index 2af7563ee..a0a3aaed8 100644 --- a/lava_results_app/views/query/views.py +++ b/lava_results_app/views/query/views.py @@ -142,7 +142,8 @@ class QueryCustomResultView(LavaView): super(QueryCustomResultView, self).__init__(request, **kwargs) def get_queryset(self): - return Query.get_queryset(self.content_type, self.conditions) + return Query.get_queryset(self.content_type, + self.conditions).visible_by_user(user) class QueryResultView(LavaView): @@ -153,7 +154,7 @@ class QueryResultView(LavaView): super(QueryResultView, self).__init__(request, **kwargs) def get_queryset(self): - return self.query.get_results() + return self.query.get_results(self.request.user) @BreadCrumb("Queries", parent=index) @@ -437,7 +438,7 @@ def query_export(request, username, name): """ query = get_object_or_404(Query, owner__username=username, name=name) - results = query.get_results() + results = query.get_results(request.user) filename = "query_%s_%s_export" % (query.owner.username, query.name) return _export_query(results, query.content_type, filename) @@ -463,7 +464,8 @@ def query_export_custom(request): filename = "query_%s_export" % (content_type) try: - results = Query.get_queryset(content_type, conditions) + results = Query.get_queryset(content_type, conditions).visible_by_user( + user) except FieldError: raise InvalidConditionsError("Conditions URL incorrect: Field does " "not exist. Please refer to query docs.") diff --git a/lava_scheduler_app/managers.py b/lava_scheduler_app/managers.py new file mode 100644 index 000000000..640c019da --- /dev/null +++ b/lava_scheduler_app/managers.py @@ -0,0 +1,88 @@ +# Copyright (C) 2015 Linaro Limited +# +# Author: Stevan Radakovic <stevan.radakovic@linaro.org> +# +# This file is part of Lava Server. +# +# Lava Server is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License version 3 +# as published by the Free Software Foundation +# +# Lava Server is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with Lava Server. If not, see <http://www.gnu.org/licenses/>. + +from django.db import models +from django.db.models import Q + +from django_restricted_resource.managers import RestrictedResourceQuerySet + +from lava_scheduler_app import utils + + +class RestrictedTestJobQuerySet(RestrictedResourceQuerySet): + + def visible_by_user(self, user): + + from lava_scheduler_app.models import TestJob + # Legacy jobs. + conditions_legacy = Q(is_pipeline=False) + if not user: + conditions_legacy &= Q(is_public=True) + elif not user.is_superuser and not user.has_perm('lava_scheduler_app.cancel_resubmit_testjob'): + # continue adding conditions only if user is not superuser and + # does not have admin permission for jobs. + conditions_legacy &= (Q(is_public=True) | + Q(user=user) | + Q(submitter=user) | + Q(group__in=user.groups.all())) + + # Pipeline jobs. + conditions = Q(is_pipeline=True) + if not user: + conditions_legacy &= Q(is_public=True) + elif not user.is_superuser and not user.has_perm('lava_scheduler_app.cancel_resubmit_testjob') and not user.has_perm('lava_scheduler_app.change_device'): + # continue adding conditions only if user is not superuser and + # does not have admin permission for jobs or devices. + conditions &= ( + Q(is_public=True) | + Q(submitter=user) | + (~Q(actual_device=None) & Q(actual_device__user=user)) | + Q(visibility=TestJob.VISIBLE_PUBLIC) | + Q(visibility=TestJob.VISIBLE_PERSONAL, submitter=user) | + # NOTE: this supposedly does OR and we need user to be in + # all the visibility groups if we allow multiple groups in + # field viewing groups. + Q(visibility=TestJob.VISIBLE_GROUP, + viewing_groups__in=user.groups.all()) + ) + + conditions |= conditions_legacy + queryset = self.filter(conditions) + + return queryset + + +class RestrictedTestCaseQuerySet(RestrictedResourceQuerySet): + + def visible_by_user(self, user): + + from lava_scheduler_app.models import TestJob + jobs = TestJob.objects.filter( + testsuite__testcase__in=self).visible_by_user(user) + + return self.filter(suite__job__in=jobs) + + +class RestrictedTestSuiteQuerySet(models.QuerySet): + + def visible_by_user(self, user): + + from lava_scheduler_app.models import TestJob + jobs = TestJob.objects.filter(testsuite__in=self).visible_by_user(user) + + return self.filter(job__in=jobs) diff --git a/lava_scheduler_app/models.py b/lava_scheduler_app/models.py index 6338b693d..14475fa60 100644 --- a/lava_scheduler_app/models.py +++ b/lava_scheduler_app/models.py @@ -30,7 +30,12 @@ from django_kvstore import models as kvmodels from django_kvstore import get_kvstore from django.utils import timezone -from django_restricted_resource.models import RestrictedResource +from django_restricted_resource.models import ( + RestrictedResource, + RestrictedResourceManager +) +from lava_scheduler_app.managers import RestrictedTestJobQuerySet + from dashboard_app.models import Bundle, BundleStream @@ -1359,6 +1364,8 @@ class TestJob(RestrictedResource): """ A test job is a test process that will be run on a Device. """ + objects = RestrictedResourceManager.from_queryset( + RestrictedTestJobQuerySet)() SUBMITTED = 0 RUNNING = 1 @@ -55,7 +55,7 @@ setup( install_requires=[ 'django >= 1.6.1', 'django-openid-auth >= 0.5', - 'django-restricted-resource >= 0.2.7', + 'django-restricted-resource >= 2015.09', 'django-tables2 >= 0.13.0', 'docutils >= 0.6', 'lava-tool >= 0.2', |