Merge pull request 'pdf_lafede' (#191) from pdf_lafede into release

Reviewed-on: https://gitea.pangea.org/trustchain-oc1-orchestral/IdHub/pulls/191
This commit is contained in:
cayop 2024-03-15 18:29:31 +00:00
commit 22d1a7331a
13 changed files with 454 additions and 44 deletions

View File

@ -704,7 +704,7 @@ class VerificableCredential(models.Model):
cred_path = 'public/credentials' cred_path = 'public/credentials'
sid = self.hash sid = self.hash
url_id = "https://{}/{}/{}".format( url_id = "{}/{}/{}".format(
domain, domain,
cred_path, cred_path,
sid sid

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.1 KiB

View File

@ -0,0 +1,126 @@
{% load i18n static %}
<!DOCTYPE html>
<html>
<head>
<title>Certificat</title>
<meta content="text/html; charset=UTF-8" http-equiv="content-type" />
<meta name="viewport" content="width=device-width, initial-scale=1.0"/>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.11.1/font/bootstrap-icons.css">
<link rel="stylesheet" href= "https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.2/css/all.min.css">
<link href="{% static "/css/bootstrap.min.css" %}" rel="stylesheet">
<style type="text/css" media="all">
@page {
size: A4 portrait; /* can use also 'landscape' for orientation */
margin: 1.0cm 1.5cm 3.5cm 1.5cm;
font-family: "Source Sans Pro", Calibri, Candra, Sans serif;
@top {
content: element(header);
}
@bottom {
content: element(footer);
}
}
body {
width: 100% !important;
height: 100%;
background: #fff;
color: black;
font-size: 100%;
line-height: 1.65;
-webkit-font-smoothing: antialiased;
-webkit-text-size-adjust: none;
}
header {
position: running(header);
/*height: 100px;*/
font-size: 12px;
/* color: #000; */
font-family: Arial;
width: 100%;
/* position: relative;*/
}
footer {
position: running(footer);
/*height: 150px;*/
}
.body_content {
position: relative;
page-break-inside: auto;
width: 100%;
/*overflow: hidden;*/
}
img {max-height: 150px; width: auto;}
.company-logo {float: left;}
.customer-logo {float: right;}
.page-break:not(section:first-of-type) {
page-break-before: always
}
}
</style>
</head>
<body>
<div class="container body-content">
<div class="row">
<div class="col">
<img style="width: 100%; height: auto;" src="data:image/jpeg;base64,{{ image_header }}" />
</div>
</div>
<div class="row mt-3">
<div class="col-12" style="text-align: center;">
<b>
<span style="color: #ea5e0f;">LAFEDE.CAT ORGANITZACIONS PER A LA JUSTÍCIA GLOBAL</span><br />CERTIFICA QUE:</b><br />
<b>{{ firstName }} {{ lastName }}</b> amb DNI <b>{{ personalIdentifier }}</b><br/>
Ha realitzat el curs <b>{{ courseName }}</b>, a {{ address|default:"" }} / de manera {{ modeOfInstruction }}, els dies {{ issued_date }}<br />
La durada del curs ha estat de {{ courseDuration }} hores lectives corresponents a {{ courseDays }} sessions.<br />
<br />
<br />
<br />
</div>
<div class="col-12" style="text-align: left;">
I per deixar-ne constància als efectes oportuns, signo el present certificat en data de {{ issued_date }}
</div>
</div>
<div class="row" style="padding-top: 20px;">
<div class="col-12">
<img style="width: 129px; height: 88px;" src="data:image/jpeg;base64,{{ image_signature }}" />
</div>
</div>
<div class="row" style="padding-top: 20px;">
<div class="col-12">
Pepa Martínez Peyrats<br />
Directora<br />
Lafede.cat - Federació d'Organitzacions per a la Justícia Global
</div>
</div>
{% if qr %}
<div class="row" style="padding-top: 20px;">
<div class="col-12">
<img style="width: 129px; height: 129px;" src="data:image/jpeg;base64,{{ qr }}" />
</div>
</div>
{% endif %}
<div class="row" style="padding-top: 20px;">
<div class="col" style="display: flex; justify-content: space-between;">
<span style="color: #ea5e0f;">Organitza:</span>
<span style="color: #ea5e0f;">Amb el suport de:</span>
<span style="color: #ea5e0f;">Amb la col·laboració de:</span>
</div>
<div class="col">
<div class="row">
<img style="width: auto; height: 50px;" src="data:image/jpeg;base64,{{ image_footer }}" />
</div>
</div>
</div>
</div>
</body>
</html>

View File

@ -0,0 +1,126 @@
{% load i18n static %}
<!DOCTYPE html>
<html>
<head>
<title>Certificado</title>
<meta content="text/html; charset=UTF-8" http-equiv="content-type" />
<meta name="viewport" content="width=device-width, initial-scale=1.0"/>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.11.1/font/bootstrap-icons.css">
<link rel="stylesheet" href= "https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.2/css/all.min.css">
<link href="{% static "/css/bootstrap.min.css" %}" rel="stylesheet">
<style type="text/css" media="all">
@page {
size: A4 portrait; /* can use also 'landscape' for orientation */
margin: 1.0cm 1.5cm 3.5cm 1.5cm;
font-family: "Source Sans Pro", Calibri, Candra, Sans serif;
@top {
content: element(header);
}
@bottom {
content: element(footer);
}
}
body {
width: 100% !important;
height: 100%;
background: #fff;
color: black;
font-size: 100%;
line-height: 1.65;
-webkit-font-smoothing: antialiased;
-webkit-text-size-adjust: none;
}
header {
position: running(header);
/*height: 100px;*/
font-size: 12px;
/* color: #000; */
font-family: Arial;
width: 100%;
/* position: relative;*/
}
footer {
position: running(footer);
/*height: 150px;*/
}
.body_content {
position: relative;
page-break-inside: auto;
width: 100%;
/*overflow: hidden;*/
}
img {max-height: 150px; width: auto;}
.company-logo {float: left;}
.customer-logo {float: right;}
.page-break:not(section:first-of-type) {
page-break-before: always
}
}
</style>
</head>
<body>
<div class="container body-content">
<div class="row">
<div class="col">
<img style="width: 100%; height: auto;" src="data:image/jpeg;base64,{{ image_header }}" />
</div>
</div>
<div class="row mt-3">
<div class="col-12" style="text-align: center;">
<b>
<span style="color: #ea5e0f;">LAFEDE.CAT ORGANIZACIONES PARA LA JUSTÍCIA GLOBAL</span><br />CERTIFICA QUE:</b><br />
<b>{{ firstName }} {{ lastName }}</b> con DNI <b>{{ personalIdentifier }}</b><br/>
Ha realizado el curso <b>{{ courseName }}</b>, en {{ address }} / de manera {{ modeOfInstruction }}, los días {{ issued_date }}<br />
La duración del curso ha sido de {{ courseDuration }} horas lectivas correspondientes a {{ courseDays }} sessiones.<br />
<br />
<br />
<br />
</div>
<div class="col-12" style="text-align: left;">
Y para dejar constancia a los efectos oportunos, firmo el presente certificado en fecha de {{ issued_date }}
</div>
</div>
<div class="row" style="padding-top: 20px;">
<div class="col-12">
<img style="width: 129px; height: 88px;" src="data:image/jpeg;base64,{{ image_signature }}" />
</div>
</div>
<div class="row" style="padding-top: 20px;">
<div class="col-12">
Pepa Martínez Peyrats<br />
Directora<br />
Lafede.cat - Federación de Organizaciones por la Justícia Global
</div>
</div>
{% if qr %}
<div class="row" style="padding-top: 20px;">
<div class="col-12">
<img style="width: 129px; height: 129px;" src="data:image/jpeg;base64,{{ qr }}" />
</div>
</div>
{% endif %}
<div class="row" style="padding-top: 20px;">
<div class="col" style="display: flex; justify-content: space-between;">
<span style="color: #ea5e0f;">Organiza:</span>
<span style="color: #ea5e0f;">Con el soporte de:</span>
<span style="color: #ea5e0f;">Con la colaboración de:</span>
</div>
<div class="col">
<div class="row">
<img style="width: auto; height: 50px;" src="data:image/jpeg;base64,{{ image_footer }}" />
</div>
</div>
</div>
</div>
</body>
</html>

View File

@ -2,7 +2,7 @@
<!DOCTYPE html> <!DOCTYPE html>
<html> <html>
<head> <head>
<title>Certificado</title> <title>Certificat</title>
<meta content="text/html; charset=UTF-8" http-equiv="content-type" /> <meta content="text/html; charset=UTF-8" http-equiv="content-type" />
<meta name="viewport" content="width=device-width, initial-scale=1.0"/> <meta name="viewport" content="width=device-width, initial-scale=1.0"/>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.11.1/font/bootstrap-icons.css"> <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.11.1/font/bootstrap-icons.css">
@ -73,12 +73,23 @@
<img style="width: 100%; height: auto;" src="data:image/jpeg;base64,{{ image_header }}" /> <img style="width: 100%; height: auto;" src="data:image/jpeg;base64,{{ image_header }}" />
</div> </div>
</div> </div>
<div class="row mt-3">
<div class="col-12">
<p>A qui correspongui,</p>
</p>
Pepa Martínez Peyrats, com a directora de Lafede.cat - <strong>Federació d'Organitzacions per a la Justícia Global</strong>,
</p>
</div>
</div>
<div class="row mt-3"> <div class="row mt-3">
<div class="col-12 text-center"> <div class="col-12 text-center">
<span style="color: #ea5e0f;">LAFEDE.CAT ORGANITZACIONS PER A LA JUSTÍCIA GLOBAL</span><br />CERTIFICA QUE:<br /> <strong>CERTIFICA</strong><br />
{{ first_name }} {{ last_name }} amb DNI {{ document_id }}<br/> <ul>
Ha realitzat el curs {{ course }}, a {{ address }} / de manera virtual/presencial, els dies {{ date_course }}<br /> <li class="text-justify">
La durada del curs ha estat de {{ n_hours }} hores lectives corresponents a {{ n_lections }} sessions.<br /> Que lentitat <b>{{ legalName }}</b>, amb NIF <b>{{ taxReference }}</b> i domicili a {{ streetAddress }} {{ postCode }} {{ city }} forma part com a entitat membre de {{ federation }} (ple dret/observadora) de <b>Lafede.cat - Federació d'Organitzacions per a la Justícia Global</b>, des de lAssemblea General Ordinària celebrada el {{ issue_date }}
</li>
</ul>
<br /> <br />
<br /> <br />
<br /> <br />

View File

@ -0,0 +1,122 @@
{% load i18n static %}
<!DOCTYPE html>
<html>
<head>
<title>Certificado</title>
<meta content="text/html; charset=UTF-8" http-equiv="content-type" />
<meta name="viewport" content="width=device-width, initial-scale=1.0"/>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.11.1/font/bootstrap-icons.css">
<link rel="stylesheet" href= "https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.2/css/all.min.css">
<link href="{% static "/css/bootstrap.min.css" %}" rel="stylesheet">
<style type="text/css" media="all">
@page {
size: A4 portrait; /* can use also 'landscape' for orientation */
margin: 1.0cm 1.5cm 3.5cm 1.5cm;
font-family: "Source Sans Pro", Calibri, Candra, Sans serif;
@top {
content: element(header);
}
@bottom {
content: element(footer);
}
}
body {
width: 100% !important;
height: 100%;
background: #fff;
color: black;
font-size: 100%;
line-height: 1.65;
-webkit-font-smoothing: antialiased;
-webkit-text-size-adjust: none;
}
header {
position: running(header);
/*height: 100px;*/
font-size: 12px;
/* color: #000; */
font-family: Arial;
width: 100%;
/* position: relative;*/
}
footer {
position: running(footer);
/*height: 150px;*/
}
.body_content {
position: relative;
page-break-inside: auto;
width: 100%;
/*overflow: hidden;*/
}
img {max-height: 150px; width: auto;}
.company-logo {float: left;}
.customer-logo {float: right;}
.page-break:not(section:first-of-type) {
page-break-before: always
}
}
</style>
</head>
<body>
<div class="container body-content">
<div class="row">
<div class="col">
<img style="width: 100%; height: auto;" src="data:image/jpeg;base64,{{ image_header }}" />
</div>
</div>
<div class="row mt-3">
<div class="col-12">
<p>A quién corresponda,</p>
</p>
Pepa Martínez Peyrats, como directora de Lafede.cat - <strong>Federación de Organizaciones para la Justícia Global</strong>,
</p>
</div>
</div>
<div class="row mt-3">
<div class="col-12 text-center">
<strong>CERTIFICA</strong><br />
<ul>
<li class="text-justify">
Que la entidad <b>{{ legalName }}</b>, con NIF <b>{{ taxReference }}</b> y domicilio {{ streetAddress }} {{ postCode }} {{ city }} forma parte como entidad miembro de {{ federation }} (por el derecho/observadora) de <b>Lafede.cat - Federación de Organizaciones para la Justícia Global</b>, desde la Asamblea General Ordinaria celebrada el {{ issue_date }}
</li>
</ul>
<br />
<br />
<br />
Y para dejar constancia a los efectos oportunos, firmo el presente certificado en fecha de {{ issue_date }}
</div>
</div>
<div class="row" style="padding-top: 20px;">
<div class="col-12">
<img style="width: 129px; height: 88px;" src="data:image/jpeg;base64,{{ image_signature }}" />
</div>
</div>
<div class="row" style="padding-top: 20px;">
<div class="col-12">
Pepa Martínez Peyrats<br />
Directora<br />
Lafede.cat - Federació d'Organitzacions per a la Justícia Global
</div>
</div>
{% if qr %}
<div class="row" style="padding-top: 20px;">
<div class="col-12">
<img style="width: 129px; height: 129px;" src="data:image/jpeg;base64,{{ qr }}" />
</div>
</div>
{% endif %}
</div>
</body>
</html>

View File

@ -9,19 +9,24 @@
{{ subtitle }} {{ subtitle }}
</h3> </h3>
</div> </div>
<div class="col text-end"> {% if object.get_status == 'Issued' %}
{% if object.get_status == 'Issued' %} {% if object.eidas1_did and admin_validated %}
<div class="col"> <div class="col text-end">
{% if object.eidas1_did and admin_validated %} <a class="btn btn-green-user me-2" href="{{ url_ca }}">{% trans 'Download as PDF (Catalan)' %}</a>
<a class="btn btn-green-user me-2" href="{% url 'idhub:user_credential_pdf' object.id %}">{% trans 'Download as PDF' %}</a> </div>
{% endif %} <div class="col text-end">
<a class="btn btn-green-user" href="{% url 'idhub:user_credential_json' object.id %}">{% trans 'Download as JSON' %}</a> <a class="btn btn-green-user me-2" href="{{ url_es }}">{% trans 'Download as PDF (Spanish)' %}</a>
</div> </div>
{% endif %} {% endif %}
{% endif %}
<div class="col text-end">
{% if object.get_status == 'Issued' %}
{% if object.eidas1_did and admin_validated %}
{% endif %}
<a class="btn btn-green-user" href="{% url 'idhub:user_credential_json' object.id %}">{% trans 'Download as JSON' %}</a>
{% endif %}
{% if object.get_status == 'Enabled' %} {% if object.get_status == 'Enabled' %}
<div class="col">
<a class="btn btn-green-user" href="{% url 'idhub:user_credentials_request' %}">{% trans 'Request credential' %}</a> <a class="btn btn-green-user" href="{% url 'idhub:user_credentials_request' %}">{% trans 'Request credential' %}</a>
</div>
{% endif %} {% endif %}
</div> </div>
</div> </div>

View File

@ -73,7 +73,7 @@ urlpatterns = [
name='user_credentials'), name='user_credentials'),
path('user/credentials/<int:pk>', views_user.CredentialView.as_view(), path('user/credentials/<int:pk>', views_user.CredentialView.as_view(),
name='user_credential'), name='user_credential'),
path('user/credentials/<int:pk>/pdf', views_user.CredentialPdfView.as_view(), path('user/credentials/<int:pk>/pdf/<str:lang>', views_user.CredentialPdfView.as_view(),
name='user_credential_pdf'), name='user_credential_pdf'),
path('credentials/<int:pk>/', views_user.CredentialJsonView.as_view(), path('credentials/<int:pk>/', views_user.CredentialJsonView.as_view(),
name='user_credential_json'), name='user_credential_json'),

View File

@ -209,14 +209,19 @@ class CredentialView(MyWallet, TemplateView):
def get_context_data(self, **kwargs): def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs) context = super().get_context_data(**kwargs)
url_ca = reverse_lazy('idhub:user_credential_pdf', args=[self.object.id, 'ca'])
url_es = reverse_lazy('idhub:user_credential_pdf', args=[self.object.id, 'es'])
context.update({ context.update({
'object': self.object, 'object': self.object,
'url_ca': url_ca,
'url_es': url_es,
}) })
return context return context
class CredentialPdfView(MyWallet, TemplateView): class CredentialPdfView(MyWallet, TemplateView):
template_name = "certificates/4_Model_Certificat.html" template_name = "certificates/{}_{}.html"
template_name = "certificates/{}_{}.html"
subtitle = _('Credential management') subtitle = _('Credential management')
icon = 'bi bi-patch-check-fill' icon = 'bi bi-patch-check-fill'
file_name = "certificate.pdf" file_name = "certificate.pdf"
@ -225,6 +230,7 @@ class CredentialPdfView(MyWallet, TemplateView):
if not cache.get("KEY_DIDS"): if not cache.get("KEY_DIDS"):
return redirect(reverse_lazy('idhub:user_dashboard')) return redirect(reverse_lazy('idhub:user_dashboard'))
pk = kwargs['pk'] pk = kwargs['pk']
lang = kwargs.get('lang', 'ca')
self.user = self.request.user self.user = self.request.user
self.object = get_object_or_404( self.object = get_object_or_404(
VerificableCredential, VerificableCredential,
@ -232,6 +238,11 @@ class CredentialPdfView(MyWallet, TemplateView):
eidas1_did__isnull=False, eidas1_did__isnull=False,
user=self.request.user user=self.request.user
) )
self.credential_type = self.object.schema.file_schema.split(".json")[0]
self.template_name = self.template_name.format(
self.credential_type,
lang
)
self.url_id = "{}://{}/public/credentials/{}".format( self.url_id = "{}://{}/public/credentials/{}".format(
self.request.scheme, self.request.scheme,
self.request.get_host(), self.request.get_host(),
@ -247,49 +258,54 @@ class CredentialPdfView(MyWallet, TemplateView):
response['Content-Disposition'] = 'attachment; filename={}'.format(self.file_name) response['Content-Disposition'] = 'attachment; filename={}'.format(self.file_name)
return response return response
def get_context_data(self, **kwargs): def get_img_sign(self):
context = super().get_context_data(**kwargs)
# this_folder = str(Path.cwd())
path_img_sig = "idhub/static/images/4_Model_Certificat_html_58d7f7eeb828cf29.jpg" path_img_sig = "idhub/static/images/4_Model_Certificat_html_58d7f7eeb828cf29.jpg"
img_signature = next(Path.cwd().glob(path_img_sig)) img_signature = next(Path.cwd().glob(path_img_sig))
with open(img_signature, 'rb') as _f: with open(img_signature, 'rb') as _f:
img_sig = base64.b64encode(_f.read()).decode('utf-8') img_sig = base64.b64encode(_f.read()).decode('utf-8')
return img_sig
def get_img_header(self):
path_img_head = "idhub/static/images/4_Model_Certificat_html_7a0214c6fc8f2309.jpg" path_img_head = "idhub/static/images/4_Model_Certificat_html_7a0214c6fc8f2309.jpg"
img_header= next(Path.cwd().glob(path_img_head)) img_header= next(Path.cwd().glob(path_img_head))
with open(img_header, 'rb') as _f: with open(img_header, 'rb') as _f:
img_head = base64.b64encode(_f.read()).decode('utf-8') img_head = base64.b64encode(_f.read()).decode('utf-8')
return img_head
def get_img_footer(self):
path_img_foot = "idhub/static/images/4_Model_Certificat_html_941e7b967953b3f3.jpg"
img_foot= next(Path.cwd().glob(path_img_foot))
with open(img_foot, 'rb') as _f:
img_foot = base64.b64encode(_f.read()).decode('utf-8')
return img_foot
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
img_sig = self.get_img_sign()
img_head = self.get_img_header()
img_foot = self.get_img_footer()
qr = self.generate_qr_code(self.url_id) qr = self.generate_qr_code(self.url_id)
issue_date_now = datetime.datetime.now()
issue_date = context.get('issuedDate', issue_date_now)
first_name = self.user.first_name and self.user.first_name.upper() or "" context.update(dict(self.object.get_datas()))
last_name = self.user.first_name and self.user.last_name.upper() or ""
document_id = "0000000-L"
course = "COURSE 1"
address = "ADDRESS"
date_course = datetime.datetime.now()
n_hours = 40
n_lections = 5
issue_date = datetime.datetime.now()
context.update({ context.update({
'object': self.object, 'object': self.object,
"image_signature": img_sig, "image_signature": img_sig,
"image_header": img_head, "image_header": img_head,
"first_name": first_name, "image_footer": img_foot,
"last_name": last_name, "issue_date_now": issue_date_now.strftime("%d/%m/%Y"),
"document_id": document_id, "issue_date": issue_date.strftime("%d/%m/%Y"),
"course": course, "qr": qr,
"address": address,
"date_course": date_course,
"n_hours": n_hours,
"n_lections": n_lections,
"issue_date": issue_date,
"qr": qr
}) })
return context return context
def build_certificate(self): def build_certificate(self):
doc = self.render_to_response(context=self.get_context_data()) try:
doc = self.render_to_response(context=self.get_context_data())
except Exception:
self.template_name = "certificates/4_Model_Certificat_ca.html"
doc = self.render_to_response(context=self.get_context_data())
doc.render() doc.render()
pdf = weasyprint.HTML(string=doc.content) pdf = weasyprint.HTML(string=doc.content)
return pdf.write_pdf() return pdf.write_pdf()
@ -340,7 +356,7 @@ class CredentialPdfView(MyWallet, TemplateView):
w = IncrementalPdfFileWriter(_buffer) w = IncrementalPdfFileWriter(_buffer)
fields.append_signature_field( fields.append_signature_field(
w, sig_field_spec=fields.SigFieldSpec( w, sig_field_spec=fields.SigFieldSpec(
'Signature', box=(150, 100, 450, 150) 'Signature', box=(150, 75, 450, 100)
) )
) )

View File

@ -319,3 +319,7 @@ class OAuth2VPToken(models.Model):
"verifiableCredential", [{}] "verifiableCredential", [{}]
)[-1].get("credentialSubject") )[-1].get("credentialSubject")
return json.dumps(self.user_info, indent=2) return json.dumps(self.user_info, indent=2)
def get_user_info_all(self):
tk = json.loads(self.vp_token)
return json.dumps(tk, indent=2)

View File

@ -219,7 +219,7 @@ class VerifyView(View):
return email_message return email_message
def get_verification(self): def get_verification(self):
return self.vp_token.get_user_info() return self.vp_token.get_user_info_all()
class AllowCodeView(View): class AllowCodeView(View):
def get(self, request, *args, **kwargs): def get(self, request, *args, **kwargs):