From 821b6d3889f7c1d79aa52dd5161abd6282a226e7 Mon Sep 17 00:00:00 2001 From: Cayo Puigdefabregas Date: Mon, 20 Nov 2023 19:18:00 +0100 Subject: [PATCH] fix credentials <-> schemas --- examples/membership-card.csv | 2 + idhub/admin/forms.py | 6 +- idhub/admin/views.py | 2 +- idhub/models.py | 16 ++- .../credentials/membership-card.json | 101 ++++++++++++++++++ schemas/membership-card.json | 64 +++++++++++ 6 files changed, 185 insertions(+), 6 deletions(-) create mode 100644 examples/membership-card.csv create mode 100644 idhub/templates/credentials/membership-card.json create mode 100644 schemas/membership-card.json diff --git a/examples/membership-card.csv b/examples/membership-card.csv new file mode 100644 index 0000000..5148727 --- /dev/null +++ b/examples/membership-card.csv @@ -0,0 +1,2 @@ +name surnames email typeOfPerson membershipType organisation validFrom validUntil identityDocType identityNumber +Pepe Gómez user1@example.org individual Member Pangea 01-01-2023 diff --git a/idhub/admin/forms.py b/idhub/admin/forms.py index a219a0f..7b1bbd7 100644 --- a/idhub/admin/forms.py +++ b/idhub/admin/forms.py @@ -1,11 +1,11 @@ import csv import json import pandas as pd -from jsonschema import validate from django import forms from django.utils.translation import gettext_lazy as _ from django.core.exceptions import ValidationError +from utils import credtools from idhub.models import ( DID, File_datas, @@ -78,7 +78,7 @@ class ImportForm(forms.Form): for n in range(df.last_valid_index()+1): row = {} for k in data_pd.keys(): - row[k] = data_pd[k][n] + row[k] = data_pd[k][n] or '' user = self.validate_jsonld(n, row) self.rows[user] = row @@ -100,7 +100,7 @@ class ImportForm(forms.Form): def validate_jsonld(self, line, row): try: - validate(instance=row, schema=self.json_schema) + credtools.validate_json(row, self.json_schema) except Exception as e: msg = "line {}: {}".format(line+1, e) self.exception(msg) diff --git a/idhub/admin/views.py b/idhub/admin/views.py index 6ee837b..aab174b 100644 --- a/idhub/admin/views.py +++ b/idhub/admin/views.py @@ -772,7 +772,7 @@ class SchemasNewView(SchemasMix): return try: data = f.read().decode('utf-8') - json.loads(data) + assert credtools.validate_schema(json.loads(data)) except Exception: messages.error(self.request, _('This is not a schema valid!')) return diff --git a/idhub/models.py b/idhub/models.py index a4e0043..53f8186 100644 --- a/idhub/models.py +++ b/idhub/models.py @@ -3,6 +3,7 @@ import pytz import requests import datetime from django.db import models +from django.conf import settings from django.template.loader import get_template from django.utils.translation import gettext_lazy as _ from utils.idhub_ssikit import ( @@ -492,10 +493,19 @@ class VerificableCredential(models.Model): return json.loads(self.data) def type(self): - return self.get_schema.get('name', '') + if self.data: + return self.get_schema.get('type')[-1] + + return self.schema.name() def description(self): - return self.get_schema.get('description', '') + if not self.data: + return self.schema.description() + + for des in self.get_schema.get('description', []): + if settings.LANGUAGE_CODE == des.get('lang'): + return des.get('value', '') + return '' def get_status(self): return self.Status(self.status).label @@ -526,6 +536,8 @@ class VerificableCredential(models.Model): 'issuer_did': self.issuer_did.did, 'subject_did': self.subject_did, 'issuance_date': issuance_date, + 'first_name': self.user.first_name, + 'last_name': self.user.last_name, } context.update(d) return context diff --git a/idhub/templates/credentials/membership-card.json b/idhub/templates/credentials/membership-card.json new file mode 100644 index 0000000..dfa6a79 --- /dev/null +++ b/idhub/templates/credentials/membership-card.json @@ -0,0 +1,101 @@ +{ + "@context": [ + "https://www.w3.org/2018/credentials/v1", + { + "individual": "https://schema.org/Person", + "Member": "https://schema.org/Member", + "startDate": "https://schema.org/startDate", + "jsonSchema": "https://schema.org/jsonSchema", + "$ref": "https://schema.org/jsonSchemaRef", + "credentialSchema": "https://gitea.pangea.org/trustchain-oc1-orchestral/schemas/contexts/vocab#credentialSchema", + "organisation": "https://gitea.pangea.org/trustchain-oc1-orchestral/schemas/contexts/vocab#organisation", + "membershipType": "https://gitea.pangea.org/trustchain-oc1-orchestral/schemas/contexts/vocab#membershipType", + "membershipId": "https://gitea.pangea.org/trustchain-oc1-orchestral/schemas/contexts/vocab#membershipId", + "typeOfPerson": "https://gitea.pangea.org/trustchain-oc1-orchestral/schemas/contexts/vocab#typeOfPerson", + "identityDocType": "https://gitea.pangea.org/trustchain-oc1-orchestral/schemas/contexts/vocab#identityDocType", + "identityNumber": "https://gitea.pangea.org/trustchain-oc1-orchestral/schemas/contexts/vocab#identityNumber", + "name": "https://gitea.pangea.org/trustchain-oc1-orchestral/schemas/contexts/vocab#name", + "description": "https://gitea.pangea.org/trustchain-oc1-orchestral/schemas/contexts/vocab#description", + "value": "https://gitea.pangea.org/trustchain-oc1-orchestral/schemas/contexts/vocab#value", + "lang": "https://gitea.pangea.org/trustchain-oc1-orchestral/schemas/contexts/vocab#lang", + "surnames": "https://gitea.pangea.org/trustchain-oc1-orchestral/schemas/contexts/vocab#surnames", + "email": "https://gitea.pangea.org/trustchain-oc1-orchestral/schemas/contexts/vocab#email", + "issued": "https://ec.europa.eu/digital-building-blocks/wikis/display/EBSIDOC/Verifiable+Attestation#issued", + "validFrom": "https://ec.europa.eu/digital-building-blocks/wikis/display/EBSIDOC/Verifiable+Attestation#validFrom", + "validUntil": "https://ec.europa.eu/digital-building-blocks/wikis/display/EBSIDOC/Verifiable+Attestation#validUntil" + } + ], + "type": [ + "VerifiableCredential", + "VerifiableAttestation", + "MembershipCard" + ], + "id": "{{ vc_id }}", + "issuer": { + "id": "{{ issuer_did }}", + "name": "Pangea", + "description": [ + { + "value": "Pangea.org is a service provider leveraging open-source technologies to provide affordable and accessible solutions for social enterprises and solidarity organisations.", + "lang": "en" + }, + { + "value": "Pangea.org és un proveïdor de serveis que aprofita les tecnologies de codi obert per oferir solucions assequibles i accessibles per a empreses socials i organitzacions solidàries.", + "lang": "ca_ES" + }, + { + "value": "Pangea.org es un proveedor de servicios que aprovecha tecnologías de código abierto para proporcionar soluciones asequibles y accesibles para empresas sociales y organizaciones solidarias.", + "lang": "es" + } + + ] + }, + "issuanceDate": "{{ issuance_date }}", + "issued": "{{ issuance_date }}", + "validFrom": "{{ issuance_date }}", + "validUntil": "{{ validUntil }}", + "name": [ + { + "value": "Membership Card", + "lang": "en" + }, + { + "value": "Carnet de soci/a", + "lang": "ca_ES" + }, + { + "value": "Carnet de socio/a", + "lang": "es" + } + ], + "description": [ + { + "value": "The membership card specifies an individual's subscription or enrollment in specific services or benefits issued by an organization.", + "lang": "en" + }, + { + "value": "El carnet de soci especifica la subscripció o la inscripció d'un individu en serveis o beneficis específics emesos per una organització.", + "lang": "ca_ES" + }, + { + "value": "El carnet de socio especifica la suscripción o inscripción de un individuo en servicios o beneficios específicos emitidos por uns organización.", + "lang": "es" + } + ], + "credentialSubject": { + "id": "{{ subject_did }}", + "organisation": "Pangea", + "membershipType": "{{ membershipType }}", + "membershipId": "{{ vc_id }}", + "AffiliatedFrom": "{{ AffiliatedFrom }}", + "AffiliatedUntil": "{{ AffiliatedUntil }}", + "typeOfPerson": "{{ typeOfPerson }}", + "name": "{{ first_name }}", + "surnames": "{{ last_name }}", + "email": "{{ email }}", + "credentialSchema": { + "id": "https://gitea.pangea.org/trustchain-oc1-orchestral/schemas/membership-card-schema.json", + "type": "JsonSchema" + } + } +} \ No newline at end of file diff --git a/schemas/membership-card.json b/schemas/membership-card.json new file mode 100644 index 0000000..dcaa00d --- /dev/null +++ b/schemas/membership-card.json @@ -0,0 +1,64 @@ +{ + "$id": "https://gitea.pangea.org/trustchain-oc1-orchestral/schemas/membership-card-schema.json", + "$schema": "https://json-schema.org/draft/2020-12/schema", + "name": "MembershipCard", + "description": "MembershipCard credential using JsonSchema", + "type": "object", + "properties": { + "credentialSubject": { + "type": "object", + "properties": { + "organisation": { + "type": "string" + }, + "membershipType": { + "type": "string" + }, + "AffiliatedFrom": { + "type": "string", + "format": "date-time" + }, + "AffiliatedUntil": { + "type": "string", + "format": "date-time" + }, + "typeOfPerson": { + "type": "string", + "enum": [ + "individual", + "org" + ] + }, + "identityDocType": { + "type": "string", + "enum": [ + "DNI", + "NIF", + "NIE", + "PASSPORT" + ] + }, + "identityNumber": { + "type": "string" + }, + "name": { + "type": "string" + }, + "surnames": { + "type": "string" + }, + "email": { + "type": "string", + "format": "email" + } + }, + "required": [ + "organisation", + "typeOfPerson", + "name", + "surnames", + "email" + ] + } + } +} \ No newline at end of file