IdHub/idhub/admin/forms.py

349 lines
10 KiB
Python
Raw Normal View History

2023-11-08 10:24:37 +00:00
import csv
import json
2024-01-10 12:53:43 +00:00
import base64
2024-01-12 20:32:26 +00:00
import copy
2023-11-08 10:24:37 +00:00
import pandas as pd
2024-01-10 12:53:43 +00:00
from pyhanko.sign import signers
2023-10-30 12:53:19 +00:00
from django import forms
2024-01-18 14:09:19 +00:00
from django.core.cache import cache
2023-11-13 17:09:37 +00:00
from django.utils.translation import gettext_lazy as _
2023-11-08 10:24:37 +00:00
from django.core.exceptions import ValidationError
2024-01-10 12:53:43 +00:00
from utils import credtools, certs
2023-11-08 10:24:37 +00:00
from idhub.models import (
DID,
2023-11-13 17:09:37 +00:00
File_datas,
Membership,
2023-11-08 10:24:37 +00:00
Schemas,
2023-11-14 14:55:17 +00:00
Service,
UserRol,
2023-11-08 10:24:37 +00:00
VerificableCredential,
)
from idhub_auth.models import User
2023-10-30 12:53:19 +00:00
class TermsConditionsForm(forms.Form):
accept = forms.BooleanField(
label=_("Accept terms and conditions of the service"),
required=False
)
def __init__(self, *args, **kwargs):
self.user = kwargs.pop('user', None)
super().__init__(*args, **kwargs)
def clean(self):
data = self.cleaned_data
if data.get("accept"):
self.user.accept_gdpr = True
else:
self.user.accept_gdpr = False
return data
def save(self, commit=True):
if commit:
self.user.save()
return self.user
return
2023-10-30 12:53:19 +00:00
class ImportForm(forms.Form):
2023-12-14 16:15:22 +00:00
did = forms.ChoiceField(label=_("Did"), choices=[])
2024-01-18 14:09:19 +00:00
eidas1 = forms.ChoiceField(
label=_("Signature with Eidas1"),
choices=[],
required=False
)
2023-12-14 16:15:22 +00:00
schema = forms.ChoiceField(label=_("Schema"), choices=[])
file_import = forms.FileField(label=_("File import"))
2023-11-02 09:59:15 +00:00
2023-11-08 10:24:37 +00:00
def __init__(self, *args, **kwargs):
self._schema = None
self._did = None
2024-01-18 14:09:19 +00:00
self._eidas1 = None
2023-11-08 10:24:37 +00:00
self.rows = {}
2023-11-22 10:18:47 +00:00
self.properties = {}
2023-11-08 10:24:37 +00:00
self.user = kwargs.pop('user', None)
super().__init__(*args, **kwargs)
2024-01-18 14:09:19 +00:00
dids = DID.objects.filter(user=self.user)
2023-11-08 10:24:37 +00:00
self.fields['did'].choices = [
2024-01-18 14:09:19 +00:00
(x.did, x.label) for x in dids.filter(eidas1=False)
2023-11-08 10:24:37 +00:00
]
self.fields['schema'].choices = [
(x.id, x.name()) for x in Schemas.objects.filter()
]
2024-01-18 14:09:19 +00:00
if dids.filter(eidas1=True).exists():
choices = [("", "")]
choices.extend([
(x.did, x.label) for x in dids.filter(eidas1=True)
])
self.fields['eidas1'].choices = choices
else:
self.fields.pop('eidas1')
2023-11-08 10:24:37 +00:00
2024-01-18 14:09:19 +00:00
def clean(self):
2023-11-08 10:24:37 +00:00
data = self.cleaned_data["did"]
did = DID.objects.filter(
user=self.user,
did=data
)
if not did.exists():
raise ValidationError("Did is not valid!")
self._did = did.first()
2024-01-18 14:09:19 +00:00
eidas1 = self.cleaned_data.get('eidas1')
if eidas1:
self._eidas1 = DID.objects.filter(
user=self.user,
eidas1=True,
did=eidas1
).first()
2023-11-08 10:24:37 +00:00
return data
def clean_schema(self):
data = self.cleaned_data["schema"]
schema = Schemas.objects.filter(
id=data
)
if not schema.exists():
raise ValidationError("Schema is not valid!")
self._schema = schema.first()
2023-11-22 10:18:47 +00:00
try:
self.json_schema = json.loads(self._schema.data)
2024-01-12 20:32:26 +00:00
props = [x for x in self.json_schema["allOf"] if 'properties' in x.keys()]
2023-12-18 11:00:00 +00:00
prop = props[0]['properties']
2023-11-22 10:18:47 +00:00
self.properties = prop['credentialSubject']['properties']
except Exception:
raise ValidationError("Schema is not valid!")
if not self.properties:
raise ValidationError("Schema is not valid!")
2024-01-12 20:32:26 +00:00
# TODO we need filter "$ref" of schema for can validate a csv
self.json_schema_filtered = copy.copy(self.json_schema)
allOf = [x for x in self.json_schema["allOf"] if '$ref' not in x.keys()]
self.json_schema_filtered["allOf"] = allOf
2023-11-08 10:24:37 +00:00
return data
def clean_file_import(self):
data = self.cleaned_data["file_import"]
self.file_name = data.name
if File_datas.objects.filter(file_name=self.file_name, success=True).exists():
raise ValidationError("This file already exists!")
2024-01-10 17:35:12 +00:00
# df = pd.read_csv (data, delimiter="\t", quotechar='"', quoting=csv.QUOTE_ALL)
df = pd.read_excel(data)
2023-11-08 10:24:37 +00:00
data_pd = df.fillna('').to_dict()
if not data_pd:
self.exception("This file is empty!")
2023-11-22 10:18:47 +00:00
head_row = {x: '' for x in self.properties.keys()}
2023-11-08 10:24:37 +00:00
for n in range(df.last_valid_index()+1):
2023-11-21 09:00:59 +00:00
row = head_row.copy()
2023-11-08 10:24:37 +00:00
for k in data_pd.keys():
2023-11-20 18:18:00 +00:00
row[k] = data_pd[k][n] or ''
2023-11-08 10:24:37 +00:00
user = self.validate_jsonld(n, row)
self.rows[user] = row
return data
def save(self, commit=True):
table = []
for k, v in self.rows.items():
table.append(self.create_credential(k, v))
if commit:
for cred in table:
cred.save()
File_datas.objects.create(file_name=self.file_name)
return table
return
def validate_jsonld(self, line, row):
try:
2024-01-12 20:32:26 +00:00
check = credtools.validate_json(row, self.json_schema_filtered)
if check is not True:
raise ValidationError("Not valid row")
2023-11-08 10:24:37 +00:00
except Exception as e:
msg = "line {}: {}".format(line+1, e)
self.exception(msg)
user = User.objects.filter(email=row.get('email'))
if not user:
2023-11-13 09:15:52 +00:00
txt = _('The user does not exist!')
2023-11-08 10:24:37 +00:00
msg = "line {}: {}".format(line+1, txt)
self.exception(msg)
return user.first()
def create_credential(self, user, row):
return VerificableCredential(
verified=False,
user=user,
2023-11-14 17:50:23 +00:00
csv_data=json.dumps(row),
2023-11-15 10:43:13 +00:00
issuer_did=self._did,
2023-11-14 17:50:23 +00:00
schema=self._schema,
2024-01-18 14:09:19 +00:00
eidas1_did=self._eidas1
2023-11-08 10:24:37 +00:00
)
def exception(self, msg):
File_datas.objects.create(file_name=self.file_name, success=False)
raise ValidationError(msg)
2023-11-02 09:59:15 +00:00
class SchemaForm(forms.Form):
2023-12-14 16:59:40 +00:00
file_template = forms.FileField(label=_("File template"))
2023-11-13 17:09:37 +00:00
class MembershipForm(forms.ModelForm):
class Meta:
model = Membership
fields = ['type', 'start_date', 'end_date']
def clean_end_date(self):
data = super().clean()
start_date = data['start_date']
end_date = data.get('end_date')
2023-11-14 14:55:17 +00:00
members = Membership.objects.filter(
type=data['type'],
user=self.instance.user
)
if self.instance.id:
members = members.exclude(id=self.instance.id)
2023-11-16 13:17:19 +00:00
if members.filter(start_date__lte=start_date, end_date=None).exists():
msg = _("This membership already exists!")
raise forms.ValidationError(msg)
2023-11-13 17:09:37 +00:00
if (start_date and end_date):
if start_date > end_date:
msg = _("The end date is less than the start date")
raise forms.ValidationError(msg)
2023-11-14 14:55:17 +00:00
members = members.filter(
2023-11-13 17:09:37 +00:00
start_date__lte=end_date,
end_date__gte=start_date,
)
2023-11-14 14:55:17 +00:00
if members.exists():
2023-11-13 17:09:37 +00:00
msg = _("This membership already exists!")
raise forms.ValidationError(msg)
2023-11-16 13:17:19 +00:00
if not end_date:
members = members.filter(
start_date__gte=start_date,
)
if members.exists():
msg = _("This membership already exists!")
raise forms.ValidationError(msg)
2023-11-13 17:09:37 +00:00
return end_date
2023-11-14 14:55:17 +00:00
class UserRolForm(forms.ModelForm):
class Meta:
model = UserRol
fields = ['service']
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
if not self.instance.id:
user = self.instance.user
choices = self.fields['service'].choices
choices.queryset = choices.queryset.exclude(users__user=user)
self.fields['service'].choices = choices
def clean_service(self):
data = super().clean()
service = UserRol.objects.filter(
service=data['service'],
user=self.instance.user
)
if service.exists():
msg = _("Is not possible to have a duplicate role")
raise forms.ValidationError(msg)
return data['service']
2024-01-10 12:53:43 +00:00
class ImportCertificateForm(forms.Form):
label = forms.CharField(label=_("Label"))
password = forms.CharField(
label=_("Password of certificate"),
widget=forms.PasswordInput
)
file_import = forms.FileField(label=_("File import"))
def __init__(self, *args, **kwargs):
self._did = None
self._s = None
self._label = None
self.user = kwargs.pop('user', None)
super().__init__(*args, **kwargs)
def clean(self):
data = super().clean()
file_import = data.get('file_import')
self.pfx_file = file_import.read()
self.file_name = file_import.name
self._pss = data.get('password')
self._label = data.get('label')
if not self.pfx_file or not self._pss:
msg = _("Is not a valid certificate")
raise forms.ValidationError(msg)
self.signer_init()
if not self._s:
msg = _("Is not a valid certificate")
raise forms.ValidationError(msg)
self.new_did()
return data
def new_did(self):
cert = self.pfx_file
keys = {
"cert": base64.b64encode(self.pfx_file).decode('utf-8'),
"passphrase": self._pss
}
key_material = json.dumps(keys)
self._did = DID(
key_material=key_material,
did=self.file_name,
label=self._label,
eidas1=True,
2024-01-18 14:09:19 +00:00
user=self.user,
type=DID.Types.KEY
2024-01-10 12:53:43 +00:00
)
2024-01-18 14:09:19 +00:00
pw = cache.get("KEY_DIDS")
self._did.set_key_material(key_material, pw)
2024-01-10 12:53:43 +00:00
def save(self, commit=True):
if commit:
self._did.save()
return self._did
return
def signer_init(self):
self._s = certs.load_cert(
self.pfx_file, self._pss.encode('utf-8')
)