Skip to content

Commit

Permalink
implement permissions
Browse files Browse the repository at this point in the history
  • Loading branch information
nicokant committed Jul 25, 2024
1 parent 2b35e6a commit cba6fd2
Show file tree
Hide file tree
Showing 19 changed files with 211 additions and 58 deletions.
5 changes: 5 additions & 0 deletions src/apps/users/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,11 @@ class User(AbstractUser):

objects = UserManager()

def __str__(self) -> str:
if self.first_name and self.last_name:
return f"{self.first_name} {self.last_name}"
return self.email

def get_absolute_url(self: Self) -> str:
"""Get URL for user's detail view.
Expand Down
1 change: 1 addition & 0 deletions src/config/settings/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,7 @@
"genlab_bestilling",
"theme",
"frontend",
"nina",
]
# https://docs.djangoproject.com/en/dev/ref/settings/#installed-apps
INSTALLED_APPS = DJANGO_APPS + ADMIN_APPS + THIRD_PARTY_APPS + LOCAL_APPS
Expand Down
3 changes: 1 addition & 2 deletions src/genlab_bestilling/admin.py
Original file line number Diff line number Diff line change
Expand Up @@ -71,8 +71,7 @@ class LocationAdmin(ModelAdmin):
class GenrequestAdmin(ModelAdmin):
list_display = [
"name",
"number",
"verified",
"project",
"samples_owner",
"area",
"analysis_timerange",
Expand Down
2 changes: 1 addition & 1 deletion src/genlab_bestilling/api/serializers.py
Original file line number Diff line number Diff line change
Expand Up @@ -176,7 +176,7 @@ class Meta:
model = Genrequest
fields = (
"id",
"number",
"project",
"area",
)

Expand Down
10 changes: 9 additions & 1 deletion src/genlab_bestilling/forms.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
from formset.renderers.tailwind import FormRenderer
from formset.utils import FormMixin
from formset.widgets import DateInput, DualSortableSelector, Selectize
from nina.models import Project

from .libs.formset import ContextFormCollection
from .models import (
Expand All @@ -28,6 +29,10 @@ def __init__(self, *args, user=None, **kwargs):
super().__init__(*args, **kwargs)
self.user = user

self.fields["project"].queryset = Project.objects.filter(
memberships=user,
)

def save(self, commit=True):
obj = super().save(commit=False)
if self.user:
Expand All @@ -40,17 +45,20 @@ def save(self, commit=True):
class Meta:
model = Genrequest
fields = (
"number",
"project",
"name",
"area",
"species",
"samples_owner",
"sample_types",
"analysis_types",
"expected_total_samples",
# "analysis_timerange",
)
widgets = {
"area": Selectize(search_lookup="name_icontains"),
"samples_owner": Selectize(search_lookup="name_icontains"),
"project": Selectize(search_lookup="number_istartswith"),
"species": DualSortableSelector(
search_lookup="name_icontains",
filter_by={"area": "area__id"},
Expand Down
21 changes: 4 additions & 17 deletions src/genlab_bestilling/migrations/0001_initial.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# Generated by Django 5.0.7 on 2024-07-24 14:16
# Generated by Django 5.0.7 on 2024-07-25 08:32

import django.contrib.postgres.fields.ranges
import django.db.models.deletion
Expand All @@ -12,6 +12,7 @@ class Migration(migrations.Migration):

dependencies = [
("contenttypes", "0002_remove_content_type_name"),
("nina", "0001_initial"),
(
"taggit",
"0006_rename_taggeditem_content_type_object_id_taggit_tagg_content_8fc721_idx",
Expand Down Expand Up @@ -132,8 +133,6 @@ class Migration(migrations.Migration):
),
),
("name", models.CharField(blank=True, max_length=255, null=True)),
("number", models.CharField(verbose_name="Genrequest number")),
("verified", models.BooleanField(default=False)),
("expected_total_samples", models.IntegerField(blank=True, null=True)),
(
"analysis_timerange",
Expand Down Expand Up @@ -165,21 +164,9 @@ class Migration(migrations.Migration):
),
),
(
"members",
models.ManyToManyField(
blank=True,
related_name="genrequests_member",
to=settings.AUTH_USER_MODEL,
),
),
(
"owner",
"project",
models.ForeignKey(
blank=True,
null=True,
on_delete=django.db.models.deletion.SET_NULL,
related_name="genrequests_owned",
to=settings.AUTH_USER_MODEL,
on_delete=django.db.models.deletion.PROTECT, to="nina.project"
),
),
],
Expand Down
15 changes: 2 additions & 13 deletions src/genlab_bestilling/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -90,28 +90,17 @@ class Genrequest(models.Model):
"""

name = models.CharField(max_length=255, null=True, blank=True)
number = models.CharField(verbose_name=_("Project number"))
verified = models.BooleanField(default=False)
project = models.ForeignKey("nina.Project", on_delete=models.PROTECT)
samples_owner = models.ForeignKey(
"Organization", on_delete=models.PROTECT, blank=True, null=True
)
owner = models.ForeignKey(
"users.User",
on_delete=models.SET_NULL,
null=True,
blank=True,
related_name="genrequests_owned",
)
creator = models.ForeignKey(
"users.User",
on_delete=models.SET_NULL,
null=True,
blank=True,
related_name="genrequests_created",
)
members = models.ManyToManyField(
"users.User", blank=True, related_name="genrequests_member"
)
area = models.ForeignKey("Area", on_delete=models.PROTECT)
species = models.ManyToManyField("Species", blank=True, related_name="genrequests")
sample_types = models.ManyToManyField("SampleType", blank=True)
Expand All @@ -120,7 +109,7 @@ class Genrequest(models.Model):
analysis_timerange = DateRangeField(null=True, blank=True)

def __str__(self):
return str(self.name or self.number)
return str(self.name or self.project_id)

def get_absolute_url(self):
return reverse(
Expand Down
4 changes: 2 additions & 2 deletions src/genlab_bestilling/tables.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,12 +18,12 @@ def render_polymorphic_ctype(self, value):


class GenrequestTable(tables.Table):
number = tables.Column(linkify=True)
project_id = tables.Column(linkify=True)

class Meta:
model = Genrequest
fields = (
"number",
"project_id",
"name",
"area",
"species",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,20 +4,9 @@

{% block content %}
<div class="flex items-center mb-5 gap-2">
<h3 class="text-4xl">{{ object.name }} - {{ object.number }}</h3>
{% if genrequest.verified %}<span class="bg-green-500 px-2 rounded text-sm"
>Verified</span
>{% else %}<span class="bg-red-500 text-white px-2 rounded text-sm"
>Not verified</span
>{% endif %}
<h3 class="text-4xl">{{ object.project_id }} - {{ object.name|default_if_none:"Unnamed" }} </h3>
</div>

{% if not genrequest.verified %}
<div class="alert alert-warning">
<p>Project number needs to be verified before adding orders</p>
</div>
{% endif %}

<div>
{% object-detail object=object %}

Expand All @@ -28,7 +17,6 @@ <h3 class="text-4xl">{{ object.name }} - {{ object.number }}</h3>
<a class="btn bg-primary" href="{% url 'genrequest-update' pk=genrequest.id %}"
><i class="fas fa-edit"></i> Edit</a
>
{% if genrequest.verified %}
<a
class="btn bg-primary"
href="{% url 'genrequest-order-list' genrequest_id=genrequest.id %}"
Expand All @@ -44,7 +32,6 @@ <h3 class="text-4xl">{{ object.name }} - {{ object.number }}</h3>
href="{% url 'genrequest-analysis-create' genrequest_id=genrequest.id %}"
><i class="fas fa-plus"></i> Analysis order</a
>
{% endif %}
</div>
</div>
{% endblock %}
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
{% load render_table from django_tables2 %}

{% block content %}
<h3 class="text-4xl mb-5">Orders relative to {{ genrequest.name }} - {{genrequest.number }}</h3>
<h3 class="text-4xl mb-5">Orders relative to {{ genrequest }}</h3>
<div class="flex gap-5 mb-5">
<a class="btn bg-primary" href="{% url 'genrequest-detail' pk=genrequest.id %}"><i class="fas fa-arrow-left"></i> back</a>
<a class="btn bg-primary" href="{% url 'genrequest-equipment-create' genrequest_id=genrequest.id %}"><i class="fas fa-plus"></i> Equipment order</a>
Expand Down
35 changes: 28 additions & 7 deletions src/genlab_bestilling/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -83,15 +83,24 @@ class GenrequestListView(LoginRequiredMixin, SingleTableView):
model = Genrequest
table_class = GenrequestTable

def get_queryset(self) -> QuerySet[Any]:
return super().get_queryset().filter(project__memberships=self.request.user)


class GenrequestDetailView(LoginRequiredMixin, DetailView):
model = Genrequest

def get_queryset(self) -> QuerySet[Any]:
return super().get_queryset().filter(project__memberships=self.request.user)


class GenrequestUpdateView(FormsetUpdateView):
model = Genrequest
form_class = GenrequestEditForm

def get_queryset(self) -> QuerySet[Any]:
return super().get_queryset().filter(project__memberships=self.request.user)

def get_success_url(self):
return reverse(
"genrequest-detail",
Expand All @@ -103,6 +112,9 @@ class GenrequestCreateView(FormsetCreateView):
model = Genrequest
form_class = GenrequestForm

def get_queryset(self) -> QuerySet[Any]:
return super().get_queryset().filter(project__memberships=self.request.user)

def get_form_kwargs(self):
kwargs = super().get_form_kwargs()
kwargs["user"] = self.request.user
Expand All @@ -124,10 +136,18 @@ class GenrequestNestedMixin(LoginRequiredMixin):
and adds it to the render context.
"""

genrequest_id_accessor = "genrequest_id"
genrequest_accessor = "genrequest"

def get_genrequest(self):
return Genrequest.objects.get(id=self.kwargs["genrequest_id"], verified=True)
return Genrequest.objects.filter(project__memberships=self.request.user).get(
id=self.kwargs["genrequest_id"]
)

def get_project_filtered(self, qs):
filters = {
f"{self.genrequest_accessor}__project__memberships": self.request.user
}
return qs.filter(**filters)

def post(self, request, *args, **kwargs):
self.genrequest = self.get_genrequest()
Expand All @@ -138,8 +158,9 @@ def get(self, request, *args, **kwargs):
return super().get(request, *args, **kwargs)

def get_queryset(self) -> QuerySet[Any]:
kwargs = {self.genrequest_id_accessor: self.genrequest.id}
return super().get_queryset().filter(**kwargs)
qs = self.get_project_filtered(qs=super().get_queryset())
kwargs = {f"{self.genrequest_accessor}_id": self.genrequest.id}
return qs.filter(**kwargs)

def get_context_data(self, **kwargs: Any) -> dict[str, Any]:
ctx = super().get_context_data(**kwargs)
Expand Down Expand Up @@ -256,7 +277,7 @@ class EquipmentOrderQuantityUpdateView(GenrequestNestedMixin, BulkEditCollection
collection_class = EquipmentQuantityCollection
template_name = "genlab_bestilling/equipmentorderquantity_form.html"
model = EquimentOrderQuantity
genrequest_id_accessor = "order__genrequest_id"
genrequest_accessor = "order__genrequest"

def get_queryset(self) -> QuerySet[Any]:
return (
Expand Down Expand Up @@ -303,7 +324,7 @@ def get_queryset(self) -> QuerySet[Any]:


class SamplesListView(GenrequestNestedMixin, SingleTableView):
genrequest_id_accessor = "order__genrequest_id"
genrequest_accessor = "order__genrequest"

model = Sample
table_class = SampleTable
Expand All @@ -316,7 +337,7 @@ class SamplesUpdateView(GenrequestNestedMixin, BulkEditCollectionView):
collection_class = SamplesCollection
template_name = "genlab_bestilling/sample_form.html"
model = Sample
genrequest_id_accessor = "order__genrequest_id"
genrequest_accessor = "order__genrequest"

def get_queryset(self) -> QuerySet[Any]:
return (
Expand Down
Empty file added src/nina/__init__.py
Empty file.
29 changes: 29 additions & 0 deletions src/nina/admin.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
from django.contrib import admin
from unfold.admin import ModelAdmin

from .models import (
Project,
ProjectMembership,
)


class ProjectMembershipInline(admin.TabularInline):
model = ProjectMembership
autocomplete_fields = ["user"]


@admin.register(Project)
class ProjectAdmin(ModelAdmin):
search_fields = ["number", "name"]
list_filter = ["active"]
list_display = ["number", "name", "active"]

inlines = [ProjectMembershipInline]


@admin.register(ProjectMembership)
class ProjectMembershipAdmin(ModelAdmin):
search_fields = ["project__number", "project__name", "user__email"]
list_filter = ["role"]
list_display = ["project", "user", "role"]
autocomplete_fields = ["project", "user"]
7 changes: 7 additions & 0 deletions src/nina/apps.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
from django.apps import AppConfig as DjangoAppConfig
from django.utils.translation import gettext_lazy as _


class AppConfig(DjangoAppConfig):
name = "nina"
verbose_name = _("NINA")
Loading

0 comments on commit cba6fd2

Please sign in to comment.