Skip to content
Snippets Groups Projects
Commit ee6873d5 authored by Tomáš Valenta's avatar Tomáš Valenta
Browse files

permission based counters

parent 9f996c98
Branches
No related tags found
No related merge requests found
Pipeline #12011 passed
...@@ -11,6 +11,32 @@ from shared.models import NameStrMixin ...@@ -11,6 +11,32 @@ from shared.models import NameStrMixin
from users.models import User from users.models import User
class ContractCountMixin(models.Model):
def get_contract_count(self, user) -> None:
filter = {"is_approved": True}
if not user.has_perm("contract.view_confidential"):
filter["is_public"] = True
return self.contracts.filter(**filter).count()
class Meta:
abstract = True
class SignatureCountMixin(models.Model):
def get_signature_count(self, user) -> None:
filter = {"contract__is_approved": True}
if not user.has_perm("contract.view_confidential"):
filter["contract__is_approved"] = True
return self.signatures.filter(**filter).count()
class Meta:
abstract = True
class RepresentativeMixin: class RepresentativeMixin:
@property @property
def name(self): def name(self):
...@@ -29,7 +55,7 @@ class RepresentativeMixin: ...@@ -29,7 +55,7 @@ class RepresentativeMixin:
return result return result
class Signee(models.Model): class Signee(SignatureCountMixin, models.Model):
name = models.CharField( name = models.CharField(
max_length=256, max_length=256,
verbose_name="Jméno", verbose_name="Jméno",
...@@ -100,12 +126,6 @@ class Signee(models.Model): ...@@ -100,12 +126,6 @@ class Signee(models.Model):
verbose_name="Role", verbose_name="Role",
) )
class Meta:
app_label = "contracts"
verbose_name = "Jiná smluvní strana"
verbose_name_plural = "Ostatní smluvní strany"
@property @property
def url(self) -> str: def url(self) -> str:
return reverse("contracts:view_signee", args=(self.id,)) return reverse("contracts:view_signee", args=(self.id,))
...@@ -131,8 +151,14 @@ class Signee(models.Model): ...@@ -131,8 +151,14 @@ class Signee(models.Model):
return result return result
class Meta:
app_label = "contracts"
verbose_name = "Jiná smluvní strana"
verbose_name_plural = "Ostatní smluvní strany"
class Contractee(models.Model):
class Contractee(SignatureCountMixin, models.Model):
name = models.CharField( name = models.CharField(
max_length=256, max_length=256,
default=settings.DEFAULT_CONTRACTEE_NAME, default=settings.DEFAULT_CONTRACTEE_NAME,
...@@ -189,12 +215,6 @@ class Contractee(models.Model): ...@@ -189,12 +215,6 @@ class Contractee(models.Model):
def url(self) -> str: def url(self) -> str:
return reverse("contracts:view_contractee", args=(self.id,)) return reverse("contracts:view_contractee", args=(self.id,))
class Meta:
app_label = "contracts"
verbose_name = "Naše smluvní strana"
verbose_name_plural = "Naše smluvní strany"
def __str__(self) -> str: def __str__(self) -> str:
result = self.name result = self.name
...@@ -203,8 +223,14 @@ class Contractee(models.Model): ...@@ -203,8 +223,14 @@ class Contractee(models.Model):
return result return result
class Meta:
app_label = "contracts"
verbose_name = "Naše smluvní strana"
verbose_name_plural = "Naše smluvní strany"
class ContractType(NameStrMixin, models.Model): class ContractType(ContractCountMixin, NameStrMixin, models.Model):
name = models.CharField( name = models.CharField(
max_length=32, max_length=32,
verbose_name="Jméno", verbose_name="Jméno",
...@@ -221,7 +247,7 @@ class ContractType(NameStrMixin, models.Model): ...@@ -221,7 +247,7 @@ class ContractType(NameStrMixin, models.Model):
verbose_name_plural = "Typy smluv" verbose_name_plural = "Typy smluv"
class ContractIssue(NameStrMixin, models.Model): class ContractIssue(ContractCountMixin, NameStrMixin, models.Model):
name = models.CharField( name = models.CharField(
max_length=32, max_length=32,
verbose_name="Jméno", verbose_name="Jméno",
...@@ -238,7 +264,7 @@ class ContractIssue(NameStrMixin, models.Model): ...@@ -238,7 +264,7 @@ class ContractIssue(NameStrMixin, models.Model):
verbose_name_plural = "Problémy se smlouvami" verbose_name_plural = "Problémy se smlouvami"
class ContractFilingArea(NameStrMixin, models.Model): class ContractFilingArea(ContractCountMixin, NameStrMixin, models.Model):
name = models.CharField( name = models.CharField(
max_length=32, max_length=32,
verbose_name="Jméno", verbose_name="Jméno",
...@@ -448,17 +474,6 @@ class Contract(NameStrMixin, models.Model): ...@@ -448,17 +474,6 @@ class Contract(NameStrMixin, models.Model):
help_text="Poznámky jsou viditelné pro všechny, kteří mohou smlouvu spravovat a pro tajné čtenáře.", help_text="Poznámky jsou viditelné pro všechny, kteří mohou smlouvu spravovat a pro tajné čtenáře.",
) )
class Meta:
app_label = "contracts"
verbose_name = "Smlouva"
verbose_name_plural = "Smlouvy"
permissions = (
("approve", "Schválit / zrušit schválení"),
("view_confidential", "Zobrazit tajné informace"),
)
@property @property
def primary_contract_url(self) -> typing.Union[None, str]: def primary_contract_url(self) -> typing.Union[None, str]:
if self.primary_contract is None: if self.primary_contract is None:
...@@ -516,6 +531,17 @@ class Contract(NameStrMixin, models.Model): ...@@ -516,6 +531,17 @@ class Contract(NameStrMixin, models.Model):
self.save() self.save()
class Meta:
app_label = "contracts"
verbose_name = "Smlouva"
verbose_name_plural = "Smlouvy"
permissions = (
("approve", "Schválit / zrušit schválení"),
("view_confidential", "Zobrazit tajné informace"),
)
class ContractFile(NameStrMixin, models.Model): class ContractFile(NameStrMixin, models.Model):
name = models.CharField( name = models.CharField(
...@@ -575,15 +601,15 @@ class ContracteeSignature(models.Model): ...@@ -575,15 +601,15 @@ class ContracteeSignature(models.Model):
verbose_name="Datum podpisu", verbose_name="Datum podpisu",
) )
def __str__(self) -> str:
return f"{str(self.contractee)} - {self.date}"
class Meta: class Meta:
app_label = "contracts" app_label = "contracts"
verbose_name = "Podpis naší smluvní strany" verbose_name = "Podpis naší smluvní strany"
verbose_name_plural = "Podpisy našich smluvních stran" verbose_name_plural = "Podpisy našich smluvních stran"
def __str__(self) -> str:
return f"{str(self.contractee)} - {self.date}"
class SigneeSignature(models.Model): class SigneeSignature(models.Model):
signee = models.ForeignKey( signee = models.ForeignKey(
...@@ -604,15 +630,15 @@ class SigneeSignature(models.Model): ...@@ -604,15 +630,15 @@ class SigneeSignature(models.Model):
verbose_name="Datum podpisu", verbose_name="Datum podpisu",
) )
def __str__(self) -> str:
return f"{str(self.signee)} - {self.date}"
class Meta: class Meta:
app_label = "contracts" app_label = "contracts"
verbose_name = "Podpis jiné smluvní strany" verbose_name = "Podpis jiné smluvní strany"
verbose_name_plural = "Podpisy jiných smluvních stran" verbose_name_plural = "Podpisy jiných smluvních stran"
def __str__(self) -> str:
return f"{str(self.signee)} - {self.date}"
class ContracteeSignatureRepresentative(RepresentativeMixin, models.Model): class ContracteeSignatureRepresentative(RepresentativeMixin, models.Model):
contractee_signature = models.ForeignKey( contractee_signature = models.ForeignKey(
......
{% extends "shared/includes/base.html" %} {% extends "shared/includes/base.html" %}
{% load counters %}
{% block content %} {% block content %}
<div class="flex gap-4 mb-10"> <div class="flex gap-4 mb-10">
...@@ -30,7 +31,7 @@ ...@@ -30,7 +31,7 @@
{{ filing_area.person_responsible }} {{ filing_area.person_responsible }}
</td> </td>
<td> <td>
{{ filing_area.contracts.count }} {{ filing_area|contract_count:user }}
</td> </td>
</tr> </tr>
{% endfor %} {% endfor %}
......
{% extends "shared/includes/base.html" %} {% extends "shared/includes/base.html" %}
{% load counters %}
{% block content %} {% block content %}
<div class="flex gap-4 mb-10"> <div class="flex gap-4 mb-10">
...@@ -38,7 +39,7 @@ ...@@ -38,7 +39,7 @@
>{{ issue.name }}</a> >{{ issue.name }}</a>
</td> </td>
<td> <td>
{{ issue.contracts.count }} {{ issue|contract_count:user }}
</td> </td>
</tr> </tr>
{% endfor %} {% endfor %}
......
{% extends "shared/includes/base.html" %} {% extends "shared/includes/base.html" %}
{% load counters %}
{% block content %} {% block content %}
<div class="flex gap-4 mb-10"> <div class="flex gap-4 mb-10">
...@@ -26,7 +27,7 @@ ...@@ -26,7 +27,7 @@
>{{ type.name }}</a> >{{ type.name }}</a>
</td> </td>
<td> <td>
{{ type.contracts.count }} {{ type|contract_count:user }}
</td> </td>
</tr> </tr>
{% endfor %} {% endfor %}
......
{% extends "shared/includes/base.html" %} {% extends "shared/includes/base.html" %}
{% load counters %}
{% block content %} {% block content %}
<div class="flex gap-4 mb-10"> <div class="flex gap-4 mb-10">
...@@ -34,7 +35,7 @@ ...@@ -34,7 +35,7 @@
</a> </a>
</td> </td>
<td> <td>
{{ contractee.signatures.count }} {{ contractee|signature_count:user }}
</td> </td>
</tr> </tr>
{% endfor %} {% endfor %}
......
{% extends "shared/includes/base.html" %} {% extends "shared/includes/base.html" %}
{% load counters %}
{% block content %} {% block content %}
<div class="flex gap-4 mb-10"> <div class="flex gap-4 mb-10">
...@@ -34,7 +35,7 @@ ...@@ -34,7 +35,7 @@
</a> </a>
</td> </td>
<td> <td>
{{ signee.signatures.count }} {{ signee|signature_count:user }}
</td> </td>
</tr> </tr>
{% endfor %} {% endfor %}
......
from django import template
register = template.Library()
@register.filter
def contract_count(model, user) -> int:
return model.get_contract_count(user)
@register.filter
def signature_count(model, user) -> int:
return model.get_signature_count(user)
...@@ -3,6 +3,6 @@ from django import template ...@@ -3,6 +3,6 @@ from django import template
register = template.Library() register = template.Library()
@register.filter(name="subtract") @register.filter
def subtract(value, arg): def subtract(value, arg):
return value - arg return value - arg
...@@ -17,7 +17,7 @@ class RegistryOIDCAuthenticationBackend(PiratesOIDCAuthenticationBackend): ...@@ -17,7 +17,7 @@ class RegistryOIDCAuthenticationBackend(PiratesOIDCAuthenticationBackend):
user_groups = user.groups.all() user_groups = user.groups.all()
for group in access_token["groups"]: for group in access_token["groups"]:
if group.startswith("_"): if group.startswith("_"): # Ignore internal Keycloak groups
continue continue
group_name = f"sso_{group}" group_name = f"sso_{group}"
......
...@@ -15,17 +15,26 @@ class User(pirates_models.AbstractUser): ...@@ -15,17 +15,26 @@ class User(pirates_models.AbstractUser):
), ),
) )
def set_unusable_password(self) -> None: @property
# Purely for compatibility with Guardian def can_approve_contracts(self) -> bool:
pass return self.has_perm("contracts.approve")
def get_username(self) -> str: @property
first_name = self.first_name def can_create_contracts(self) -> bool:
return self.has_perm("contracts.add")
if len(first_name) != 0: @property
first_name += " " def can_view_confidential(self) -> bool:
return self.has_perm("contracts.view_confidential")
return f"{first_name}{self.last_name}" @property
def contracts_to_approve_count(self) -> int:
if not self.can_approve_contracts:
return 0
from contracts.models import Contract
return Contract.objects.filter(is_approved=False).count()
# https://docs.djangoproject.com/en/4.1/ref/models/instances/#customizing-model-loading # https://docs.djangoproject.com/en/4.1/ref/models/instances/#customizing-model-loading
@classmethod @classmethod
...@@ -53,6 +62,18 @@ class User(pirates_models.AbstractUser): ...@@ -53,6 +62,18 @@ class User(pirates_models.AbstractUser):
return instance return instance
def set_unusable_password(self) -> None:
# Purely for compatibility with Guardian
pass
def get_username(self) -> str:
first_name = self.first_name
if len(first_name) != 0:
first_name += " "
return f"{first_name}{self.last_name}"
def save(self, *args, saved_by_auth: bool = False, **kwargs): def save(self, *args, saved_by_auth: bool = False, **kwargs):
if ( if (
not self._state.adding not self._state.adding
...@@ -70,27 +91,6 @@ class User(pirates_models.AbstractUser): ...@@ -70,27 +91,6 @@ class User(pirates_models.AbstractUser):
self.is_staff_based_on_group = True self.is_staff_based_on_group = True
self.is_staff = self.groups.filter(name=settings.DEFAULT_STAFF_GROUP).exists() self.is_staff = self.groups.filter(name=settings.DEFAULT_STAFF_GROUP).exists()
@property
def can_approve_contracts(self) -> bool:
return self.has_perm("contracts.approve")
@property
def can_create_contracts(self) -> bool:
return self.has_perm("contracts.add")
@property
def can_view_confidential(self) -> bool:
return self.has_perm("contracts.view_confidential")
@property
def contracts_to_approve_count(self) -> int:
if not self.can_approve_contracts:
return 0
from contracts.models import Contract
return Contract.objects.filter(is_approved=False).count()
class Meta: class Meta:
app_label = "users" app_label = "users"
verbose_name = "Uživatel" verbose_name = "Uživatel"
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment