Commit 0ab38431 authored by Hervé  MENAGER's avatar Hervé MENAGER
Browse files

control compound visibility in query mode

compounds are visible only if validated or if the user is the creator
or an admin.
WIP on #67
parent e29e9a82
Pipeline #20789 failed with stages
in 6 minutes and 14 seconds
......@@ -477,19 +477,17 @@ class PpiComplex(models.Model):
return "PPI {}, Complex {} ({})".format(self.ppi, self.complex, self.cc_nb)
class ValidatedCompoundsManager(models.Manager):
"""
ValidatedCompoundManager filters only compounds from validated
contributions (or not coming from contributions) in the results
of the database query
"""
def get_queryset(self):
return (
super()
.get_queryset()
.exclude(compoundaction__ppi__contribution__validated=False)
)
class CompoundsManager(models.Manager):
def for_user(self, current_user):
qs = self.get_queryset()
if current_user.is_anonymous:
qs = qs.exclude(compoundaction__ppi__contribution__validated=False)
elif not current_user.is_superuser:
qs = qs.exclude(
Q(compoundaction__ppi__contribution__validated=False),
~Q(compoundaction__ppi__contribution__contributor=current_user),
)
return qs
class Compound(AutoFillableModel):
......@@ -497,8 +495,7 @@ class Compound(AutoFillableModel):
Chemical compound
"""
objects = models.Manager()
validated = ValidatedCompoundsManager()
objects = CompoundsManager()
canonical_smile = models.TextField(verbose_name="Canonical Smiles", unique=True)
is_macrocycle = models.BooleanField(
......
......@@ -3,6 +3,7 @@ iPPI-DB unit tests
"""
import re
from django.contrib.auth import get_user_model
from django.core.management import call_command
from django.test import TestCase
from django.urls import reverse
......@@ -16,6 +17,9 @@ from .models import (
CompoundTanimoto,
create_tanimoto,
update_compound_cached_properties,
CompoundAction,
Ppi,
Contribution,
)
from .models import DrugBankCompound, Protein
from .utils import FingerPrinter, mol2smi, smi2mol, smi2inchi, smi2inchikey
......@@ -405,6 +409,150 @@ class QueryCompoundViewsTestCase(TestCase):
self.assertEqual(response.status_code, 200)
def create_dummy_user(login, password, admin=False):
User = get_user_model()
if admin:
user = User.objects.create_superuser(username=login, email=f"{login}@ippidb.test", password=password)
else:
user = User.objects.create_user(username=login, email=f"{login}@ippidb.test", password=password)
return user
def create_dummy_contribution(compound_id, smiles, user, symmetry, validate=False):
c = create_dummy_compound(compound_id, smiles)
ppi = Ppi()
ppi.symmetry = symmetry
ppi.save()
ca = CompoundAction()
ca.nb_copy_compounds = 1
ca.compound = c
ca.ppi = ppi
ca.save()
co = Contribution()
co.ppi = ppi
co.contributor = user
co.validated = validate
co.save()
return c
class QueryCompoundViewsAccessTestCase(TestCase):
"""
Test the visibility of compounds belonging to
validated or unvalidated contributions
The "visibility matrix" is the following:
============================================================================
|Validation status / User| Anonymous | Creator | Another user | Admin user |
| Unvalidated | No | Yes | No | Yes |
| Validated | Yes | Yes | Yes | Yes |
============================================================================
"""
@classmethod
def setUpTestData(cls):
symmetry = models.Symmetry()
symmetry.code = "AS"
symmetry.description = "asymmetric"
symmetry.save()
# create contributor 1
cls.user_c1 = create_dummy_user("contributor1", "test1")
# create contributor 2
cls.user_c2 = create_dummy_user("contributor2", "test2")
# create admin
cls.user_cA = create_dummy_user("admin", "testA", True)
# WHAT ARE THE USE CASES TO BE TESTED?
# user is anonymous, contributor, another contributor, admin
# compound is not validated, validated
create_dummy_contribution(1, "CC", cls.user_c1, symmetry, False)
create_dummy_contribution(2, "CCC", cls.user_c1, symmetry, True)
call_command("lle_le")
call_command("pca")
def test_compound_detail_unvalidated_unlogged(self):
"""
Unvalidated compound should not be visible
if unlogged
"""
url = reverse("compound_card", kwargs={"pk": 1})
response = self.client.get(url)
self.assertEqual(response.status_code, 404)
def test_compound_detail_unvalidated_logged_creator(self):
"""
Unvalidated compound should be visible
if logged as the creator
"""
url = reverse("compound_card", kwargs={"pk": 1})
self.client.force_login(self.user_c1)
response = self.client.get(url)
self.assertEqual(response.status_code, 200)
self.client.logout()
def test_compound_detail_unvalidated_logged_user(self):
"""
Unvalidated compound should not be visible
if logged as another user
"""
url = reverse("compound_card", kwargs={"pk": 1})
self.client.force_login(self.user_c2)
response = self.client.get(url)
self.assertEqual(response.status_code, 404)
self.client.logout()
def test_compound_detail_unvalidated_logged_admin(self):
"""
Unvalidated compound should be visible
if logged as an admin user
"""
url = reverse("compound_card", kwargs={"pk": 1})
self.client.force_login(self.user_cA)
response = self.client.get(url)
self.assertEqual(response.status_code, 200)
self.client.logout()
def test_compound_detail_validated_unlogged(self):
"""
Validated compound should be visible
if unlogged
"""
url = reverse("compound_card", kwargs={"pk": 2})
response = self.client.get(url)
self.assertEqual(response.status_code, 200)
def test_compound_detail_validated_logged_creator(self):
"""
Validated compound should be visible
if logged as the creator
"""
url = reverse("compound_card", kwargs={"pk": 2})
self.client.force_login(self.user_c1)
response = self.client.get(url)
self.assertEqual(response.status_code, 200)
self.client.logout()
def test_compound_detail_validated_logged_user(self):
"""
Validated compound should be visible
if logged as another user
"""
url = reverse("compound_card", kwargs={"pk": 2})
self.client.force_login(self.user_c2)
response = self.client.get(url)
self.assertEqual(response.status_code, 200)
self.client.logout()
def test_compound_detail_validated_logged_admin(self):
"""
Validated compound should be visible
if logged as an admin user
"""
url = reverse("compound_card", kwargs={"pk": 2})
self.client.force_login(self.user_cA)
response = self.client.get(url)
self.assertEqual(response.status_code, 200)
self.client.logout()
class TestGetDoiInfo(TestCase):
"""
Test retrieving information for a DOI entry
......
......@@ -561,19 +561,12 @@ class CompoundListView(ListView):
return context
def get_queryset(self):
# compounds can be accessed only if they are validated or
# if the current user is an admin OR their contributor
self.queryset = self.model.objects.for_user(self.request.user)
self.filter_context = {}
# get queryset
qs = super().get_queryset()
# compounds can be accessed only if they are validated or
# if the current user is an admin OR their contributor
current_user = self.request.user
if current_user.is_anonymous:
qs = qs.exclude(compoundaction__ppi__contribution__validated=False)
elif not current_user.is_superuser:
qs = qs.exclude(
Q(compoundaction__ppi__contribution__validated=False),
~Q(compoundaction__ppi__contribution__contributor=current_user),
)
# add filters
self.filter_context[
"disabled"
......@@ -745,6 +738,9 @@ class CompoundDetailView(DetailView):
model = Compound
template_name = "compound_card.html"
def get_queryset(self):
return self.model.objects.for_user(self.request.user)
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context["le_lle_biplot_data"] = LeLleBiplotData.objects.get().le_lle_biplot_data
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment