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

nastenka sync, ui facelift

parent 98d130ca
No related branches found
No related tags found
No related merge requests found
Pipeline #13269 failed
import copy
import json
import logging
import typing
import requests
from admin_auto_filters.filters import AutocompleteFilterFactory
from django.conf import settings
from django.contrib import admin
from django.contrib.auth.models import Permission
from django.db import models
......@@ -33,6 +37,8 @@ from .models import (
SigneeSignatureRepresentative,
)
logger = logging.getLogger()
class IndexHiddenModelAdmin(MarkdownxGuardedModelAdmin):
def has_module_permission(self, request):
......@@ -314,6 +320,8 @@ class ContractAdmin(
return queryset
def save_model(self, request, obj, form, change):
is_new = obj.created_by is None
# Need to generate primary keys first
parent_save_response = super().save_model(request, obj, form, change)
......@@ -333,6 +341,40 @@ class ContractAdmin(
obj.valid_start_date = last_signature_date
from users.models import User
if is_new:
try:
sso_ids = []
for user in User.objects.filter(is_staff=True).all():
if user.is_superuser or user.has_perm("contracts.approve"):
sso_ids.append(user.sso_id)
requests.post(
settings.NASTENKA_API_URL,
data=json.dumps(
{
"name": f"Nová smlouva ke schválení - {obj.name}",
"description": (
obj.summary
if obj.summary is not None
else "Bez popisu."
),
"contract_id": obj.id,
"sso_ids": sso_ids,
}
),
headers={
"Authorization": f"Token {settings.NASTENKA_API_TOKEN}",
"Content-Type": "application/json",
},
)
except Exception as exception:
logger.error(
"Failed to synchronizace Nástěnka notices: %s", str(exception)
)
return parent_save_response
def has_change_permission(self, request, obj=None):
......
......@@ -4,15 +4,19 @@ from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('contracts', '0061_alter_contract_id_number'),
("contracts", "0061_alter_contract_id_number"),
]
operations = [
migrations.AddField(
model_name='contract',
name='paper_form_person_responsible',
field=models.CharField(blank=True, max_length=256, null=True, verbose_name='Osoba zodpovědná za doručení'),
model_name="contract",
name="paper_form_person_responsible",
field=models.CharField(
blank=True,
max_length=256,
null=True,
verbose_name="Osoba zodpovědná za doručení",
),
),
]
......@@ -747,10 +747,11 @@ class Contract(NameStrMixin, models.Model):
)
if (
self.paper_form_state not in (
self.paper_form_state
not in (
self.PaperFormStates.STORED,
self.PaperFormStates.SHREDDED,
self.PaperFormStates.LOST
self.PaperFormStates.LOST,
)
and not self.paper_form_person_responsible
):
......
<div class="hidden md:block">
<table class="table table-auto w-full table--striped table--bordered">
<thead>
<tr>
<td class="font-bold">Název</td>
<td>Typy</td>
<td>Platná</td>
<td class="whitespace-nowrap">Účinná od</td>
<td class="whitespace-nowrap">Účinná do</td>
<td class="whitespace-nowrap">Podepsána s</td>
</tr>
</thead>
<tbody>
{% for contract in page %}
<tr>
<td{% if not contract.is_public %} class="!bg-red-100"{% endif %}>
{% if not contract.is_public %}
{% include "contracts/includes/private_info_icon.html" %}
{% endif %}
<a
class="underline"
href="{% url "contracts:view_contract" contract.id %}"
>{{ contract.name }}</a>
</td>
<td{% if not contract.is_public %} class="!bg-red-100"{% endif %}>
<ul class="flex flex-wrap gap-1.5">
{% for type in contract.types.all %}
<li class="flex">
{% include "contracts/includes/tag.html" with url=type.url icon="ico--folder" content=type.name public=contract.is_public %}
</li>
{% endfor %}
</ul>
</td>
<td{% if not contract.is_public %} class="!bg-red-100"{% endif %}>
<i
class="{% if contract.is_valid %}ico--checkmark{% else %}ico--cross{% endif %}"
aria-label="{% if contract.is_public %}Ano{% else %}Ne{% endif %}"
></i>
</td>
<td class="whitespace-nowrap{% if not contract.is_public %} !bg-red-100{% endif %}">
{{ contract.valid_start_date }}
</td>
<td class="whitespace-nowrap{% if not contract.is_public %} !bg-red-100{% endif %}">
{% if contract.valid_end_date %}
{{ contract.valid_end_date }}
{% else %}
<span class="text-grey-200">Neurčité</span>
{% endif %}
</td>
<td{% if not contract.is_public %} class="!bg-red-100"{% endif %}>
<ul class="flex flex-wrap gap-1.5">
{% for signature in contract.signee_signatures.all %}
<li class="flex">
{% if signature.signee.entity_type == signature.signee.EntityTypes.LEGAL_ENTITY or signature.signee.entity_type == signature.signee.EntityTypes.OTHER %}
{% include "contracts/includes/tag.html" with url=signature.signee.url icon="ico--office" content=signature.signee.name public=contract.is_public %}
{% else %}
{% include "contracts/includes/tag.html" with url=signature.signee.url icon="ico--user" content=signature.signee.name public=contract.is_public %}
{% endif %}
</li>
{% endfor %}
</ul>
</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
<ul class="flex-col gap-4 flex md:hidden">
<ul class="flex-col gap-4 flex">
{% for contract in page %}
<li class="card elevation-10{% if not contract.is_public %} bg-red-100{% endif %}">
<div class="card__body p-5">
......@@ -96,7 +28,11 @@
<tr>
<td class="pt-1.5">Účinná od:</td>
<td class="pt-1.5">
{% if contract.valid_start_date %}
{{ contract.valid_start_date }}
{% else %}
<span class="text-grey-200">Neurčité</span>
{% endif %}
</td>
</tr>
<tr>
......
......@@ -20,3 +20,6 @@ DEFAULT_CONTRACTEE_DISTRICT="Praha 2"
DEFAULT_CONTRACTEE_ICO_NUMBER="71339698"
DEFAULT_STAFF_GROUPS="sso_cen:f,sso_cen:neverejni,sso_cen:smlouvy_ao,sso_cen:smlouvy_po,sso_cen:registr_smluv"
NASTENKA_API_URL=http://localhost:8009/contracts/api/notices
NASTENKA_API_TOKEN=cirno
......@@ -53,6 +53,7 @@ class RegistryOIDCAuthenticationBackend(PiratesOIDCAuthenticationBackend):
access_token, options={"verify_signature": False}
)
user.preferred_username = decoded_access_token["preferred_username"]
user_groups = user.groups.all()
self._remove_old_user_groups(
......
......@@ -244,6 +244,9 @@ if SENTRY_DSN != "":
## App-specific
NASTENKA_API_URL = env.str("NASTENKA_API_URL")
NASTENKA_API_TOKEN = env.str("NASTENKA_API_TOKEN")
DEFAULT_CONTRACTEE_NAME = env.str("DEFAULT_CONTRACTEE_NAME")
DEFAULT_CONTRACTEE_STREET = env.str("DEFAULT_CONTRACTEE_STREET")
DEFAULT_CONTRACTEE_ZIP = env.str("DEFAULT_CONTRACTEE_ZIP")
......
......@@ -21,3 +21,4 @@ Markdown==3.4.3
postal==1.1.10
PyJWT==2.6.0
PyYAML==6.0
requests==2.31.0
# Generated by Django 4.1.4 on 2023-06-15 05:52
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
("users", "0003_alter_user_is_staff_based_on_group"),
]
operations = [
migrations.AddField(
model_name="user",
name="preferred_username",
field=models.CharField(
blank=True,
max_length=64,
null=True,
verbose_name="Username v Chobotnici",
),
),
migrations.AlterField(
model_name="user",
name="sso_id",
field=models.CharField(max_length=128, verbose_name="SSO ID"),
),
]
import uuid
from django.conf import settings
from django.contrib.auth.models import Group as AuthGroup
from django.contrib.auth.models import Permission
......@@ -18,6 +20,18 @@ class Group:
class User(pirates_models.AbstractUser):
preferred_username = models.CharField(
max_length=64,
verbose_name="Username v Chobotnici",
blank=True,
null=True,
)
sso_id = models.CharField(
"SSO ID",
max_length=128,
)
is_staff_based_on_group = models.BooleanField(
default=True,
verbose_name="Administrační přístup dle členství ve skupině",
......@@ -28,6 +42,8 @@ class User(pirates_models.AbstractUser):
),
)
USERNAME_FIELD = "preferred_username"
@property
def can_approve_contracts(self) -> bool:
return self.has_perm("contracts.approve")
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment