Merge pull request 'feature/templates' (#71) from feature/templates into main

Reviewed-on: https://gitea.pangea.org/trustchain-oc1-orchestral/IdHub/pulls/71
This commit is contained in:
cayop 2023-11-03 12:34:06 +00:00
commit b32c0b8e20
59 changed files with 1913 additions and 396 deletions

17
apiregiter.py Normal file
View File

@ -0,0 +1,17 @@
import uuid
import hashlib
class Iota:
"""
Framework for simulate the comunication with IOTA DLT
"""
def issue_did(self):
u = str(uuid.uuid4()).encode()
d = hashlib.sha3_256(u).hexdigest()
did = "did:iota:{}".format(d)
return did
iota = Iota()

View File

@ -0,0 +1,2 @@
name email membershipType
Pepe user1@example.org individual
1 name email membershipType
2 Pepe user1@example.org individual

View File

@ -1,5 +0,0 @@
from django.contrib import admin
from .models import AppUser
admin.site.register(AppUser)

View File

@ -1,27 +1,9 @@
from django import forms from django import forms
from django.contrib.auth.models import User
from idhub.models import Rol
class ProfileForm(forms.ModelForm): class ImportForm(forms.Form):
MANDATORY_FIELDS = ['first_name', 'last_name', 'email', 'username'] file_import = forms.FileField()
class Meta:
model = User
fields = ('first_name', 'last_name', 'email')
class MembershipForm(forms.ModelForm): class SchemaForm(forms.Form):
MANDATORY_FIELDS = ['type'] file_template = forms.FileField()
class RolForm(forms.ModelForm):
MANDATORY_FIELDS = ['name']
class ServiceForm(forms.ModelForm):
MANDATORY_FIELDS = ['domain', 'rol']
class UserRolForm(forms.ModelForm):
MANDATORY_FIELDS = ['service']

View File

@ -1,22 +1,35 @@
import os
import csv
import json
import copy
import logging import logging
import pandas as pd
from pathlib import Path
from jsonschema import validate
from smtplib import SMTPException from smtplib import SMTPException
from django.conf import settings
from django.utils.translation import gettext_lazy as _ from django.utils.translation import gettext_lazy as _
from django.views.generic.base import TemplateView from django.views.generic.base import TemplateView
from django.views.generic.edit import UpdateView, CreateView from django.views.generic.edit import UpdateView, CreateView, DeleteView
from django.contrib.auth.models import User
from django.shortcuts import get_object_or_404, redirect from django.shortcuts import get_object_or_404, redirect
from django.urls import reverse_lazy from django.urls import reverse_lazy
from django.http import HttpResponse
from django.contrib import messages from django.contrib import messages
from idhub.models import Membership, Rol, Service, UserRol from apiregiter import iota
from idhub_auth.models import User
from idhub.mixins import AdminView from idhub.mixins import AdminView
from idhub.email.views import NotifyActivateUserByEmail from idhub.email.views import NotifyActivateUserByEmail
from idhub.admin.forms import ( from idhub.admin.forms import ImportForm, SchemaForm
ProfileForm, from idhub.models import (
MembershipForm, DID,
RolForm, File_datas,
ServiceForm, Membership,
UserRolForm Rol,
Service,
Schemas,
UserRol,
VerificableCredential,
) )
@ -42,9 +55,9 @@ class Credentials(AdminView, TemplateView):
section = "Credentials" section = "Credentials"
class Schemes(AdminView, TemplateView): class SchemasMix(AdminView, TemplateView):
title = _("Schemes Management") title = _("Templates Management")
section = "Schemes" section = "Templates"
class ImportExport(AdminView, TemplateView): class ImportExport(AdminView, TemplateView):
@ -118,8 +131,7 @@ class AdminPeopleDeleteView(AdminPeopleView):
class AdminPeopleEditView(AdminPeopleView, UpdateView): class AdminPeopleEditView(AdminPeopleView, UpdateView):
template_name = "idhub/admin/user_edit.html" template_name = "idhub/admin/user_edit.html"
from_class = ProfileForm fields = ('first_name', 'last_name', 'email')
fields = ('first_name', 'last_name', 'email', 'username')
success_url = reverse_lazy('idhub:admin_people_list') success_url = reverse_lazy('idhub:admin_people_list')
@ -128,8 +140,7 @@ class AdminPeopleRegisterView(NotifyActivateUserByEmail, People, CreateView):
subtitle = _('People Register') subtitle = _('People Register')
icon = 'bi bi-person' icon = 'bi bi-person'
model = User model = User
from_class = ProfileForm fields = ('first_name', 'last_name', 'email')
fields = ('first_name', 'last_name', 'email', 'username')
success_url = reverse_lazy('idhub:admin_people_list') success_url = reverse_lazy('idhub:admin_people_list')
def get_success_url(self): def get_success_url(self):
@ -155,7 +166,6 @@ class AdminPeopleMembershipRegisterView(People, CreateView):
subtitle = _('People add membership') subtitle = _('People add membership')
icon = 'bi bi-person' icon = 'bi bi-person'
model = Membership model = Membership
from_class = MembershipForm
fields = ('type', 'start_date', 'end_date') fields = ('type', 'start_date', 'end_date')
success_url = reverse_lazy('idhub:admin_people_list') success_url = reverse_lazy('idhub:admin_people_list')
@ -193,7 +203,6 @@ class AdminPeopleMembershipEditView(People, CreateView):
subtitle = _('People add membership') subtitle = _('People add membership')
icon = 'bi bi-person' icon = 'bi bi-person'
model = Membership model = Membership
from_class = MembershipForm
fields = ('type', 'start_date', 'end_date') fields = ('type', 'start_date', 'end_date')
success_url = reverse_lazy('idhub:admin_people_list') success_url = reverse_lazy('idhub:admin_people_list')
@ -232,7 +241,6 @@ class AdminPeopleRolRegisterView(People, CreateView):
subtitle = _('Add Rol to User') subtitle = _('Add Rol to User')
icon = 'bi bi-person' icon = 'bi bi-person'
model = UserRol model = UserRol
from_class = UserRolForm
fields = ('service',) fields = ('service',)
def get(self, request, *args, **kwargs): def get(self, request, *args, **kwargs):
@ -263,7 +271,6 @@ class AdminPeopleRolEditView(People, CreateView):
subtitle = _('Edit Rol to User') subtitle = _('Edit Rol to User')
icon = 'bi bi-person' icon = 'bi bi-person'
model = UserRol model = UserRol
from_class = UserRolForm
fields = ('service',) fields = ('service',)
def get_form_kwargs(self): def get_form_kwargs(self):
@ -311,7 +318,6 @@ class AdminRolRegisterView(AccessControl, CreateView):
subtitle = _('Add Rol') subtitle = _('Add Rol')
icon = '' icon = ''
model = Rol model = Rol
from_class = RolForm
fields = ('name',) fields = ('name',)
success_url = reverse_lazy('idhub:admin_roles') success_url = reverse_lazy('idhub:admin_roles')
object = None object = None
@ -322,7 +328,6 @@ class AdminRolEditView(AccessControl, CreateView):
subtitle = _('Edit Rol') subtitle = _('Edit Rol')
icon = '' icon = ''
model = Rol model = Rol
from_class = RolForm
fields = ('name',) fields = ('name',)
success_url = reverse_lazy('idhub:admin_roles') success_url = reverse_lazy('idhub:admin_roles')
@ -362,7 +367,6 @@ class AdminServiceRegisterView(AccessControl, CreateView):
subtitle = _('Add Service') subtitle = _('Add Service')
icon = '' icon = ''
model = Service model = Service
from_class = ServiceForm
fields = ('domain', 'description', 'rol') fields = ('domain', 'description', 'rol')
success_url = reverse_lazy('idhub:admin_services') success_url = reverse_lazy('idhub:admin_services')
object = None object = None
@ -373,7 +377,6 @@ class AdminServiceEditView(AccessControl, CreateView):
subtitle = _('Edit Service') subtitle = _('Edit Service')
icon = '' icon = ''
model = Service model = Service
from_class = ServiceForm
fields = ('domain', 'description', 'rol') fields = ('domain', 'description', 'rol')
success_url = reverse_lazy('idhub:admin_services') success_url = reverse_lazy('idhub:admin_services')
@ -401,11 +404,31 @@ class AdminCredentialsView(Credentials):
subtitle = _('Credentials list') subtitle = _('Credentials list')
icon = '' icon = ''
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context.update({
'credentials': VerificableCredential.objects,
})
return context
class AdminIssueCredentialsView(Credentials):
class AdminCredentialView(Credentials):
template_name = "idhub/admin/issue_credentials.html" template_name = "idhub/admin/issue_credentials.html"
subtitle = _('Issuance of Credentials') subtitle = _('Change status of Credential')
icon = '' icon = ''
model = VerificableCredential
def get(self, request, *args, **kwargs):
self.pk = kwargs['pk']
self.object = get_object_or_404(self.model, pk=self.pk)
return super().get(request, *args, **kwargs)
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context.update({
'object': self.object,
})
return context
class AdminRevokeCredentialsView(Credentials): class AdminRevokeCredentialsView(Credentials):
@ -414,12 +437,89 @@ class AdminRevokeCredentialsView(Credentials):
icon = '' icon = ''
class AdminWalletIdentitiesView(Credentials): class AdminDidsView(Credentials):
template_name = "idhub/admin/wallet_identities.html" template_name = "idhub/admin/dids.html"
subtitle = _('Organization Identities (DID)') subtitle = _('Organization Identities (DID)')
icon = 'bi bi-patch-check-fill' icon = 'bi bi-patch-check-fill'
wallet = True wallet = True
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context.update({
'dids': DID.objects,
})
return context
class AdminDidRegisterView(Credentials, CreateView):
template_name = "idhub/admin/did_register.html"
subtitle = _('Add a new Organization Identities (DID)')
icon = 'bi bi-patch-check-fill'
wallet = True
model = DID
fields = ('did', 'label')
success_url = reverse_lazy('idhub:admin_dids')
object = None
def get_form_kwargs(self):
kwargs = super().get_form_kwargs()
kwargs['initial'] = {
'did': iota.issue_did()
}
return kwargs
def get_form(self):
form = super().get_form()
form.fields['did'].required = False
form.fields['did'].disabled = True
return form
def form_valid(self, form):
form.save()
messages.success(self.request, _('DID created successfully'))
return super().form_valid(form)
class AdminDidEditView(Credentials, UpdateView):
template_name = "idhub/admin/did_register.html"
subtitle = _('Organization Identities (DID)')
icon = 'bi bi-patch-check-fill'
wallet = True
model = DID
fields = ('did', 'label')
success_url = reverse_lazy('idhub:admin_dids')
def get(self, request, *args, **kwargs):
self.pk = kwargs['pk']
self.object = get_object_or_404(self.model, pk=self.pk)
return super().get(request, *args, **kwargs)
def get_form(self):
form = super().get_form()
form.fields['did'].required = False
form.fields['did'].disabled = True
return form
def form_valid(self, form):
user = form.save()
messages.success(self.request, _('DID updated successfully'))
return super().form_valid(form)
class AdminDidDeleteView(Credentials, DeleteView):
subtitle = _('Organization Identities (DID)')
icon = 'bi bi-patch-check-fill'
wallet = True
model = DID
success_url = reverse_lazy('idhub:admin_dids')
def get(self, request, *args, **kwargs):
self.pk = kwargs['pk']
self.object = get_object_or_404(self.model, pk=self.pk)
self.object.delete()
messages.success(self.request, _('DID delete successfully'))
return redirect(self.success_url)
class AdminWalletCredentialsView(Credentials): class AdminWalletCredentialsView(Credentials):
template_name = "idhub/admin/wallet_credentials.html" template_name = "idhub/admin/wallet_credentials.html"
@ -435,22 +535,136 @@ class AdminWalletConfigIssuesView(Credentials):
wallet = True wallet = True
class AdminSchemesView(Schemes): class AdminSchemasView(SchemasMix):
template_name = "idhub/admin/schemes.html" template_name = "idhub/admin/schemas.html"
subtitle = _('Schemes List') subtitle = _('Template List')
icon = '' icon = ''
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context.update({
'schemas': Schemas.objects,
})
return context
class AdminSchemesImportView(Schemes):
template_name = "idhub/admin/schemes_import.html" class AdminSchemasDeleteView(SchemasMix):
subtitle = _('Import Schemes')
def get(self, request, *args, **kwargs):
self.pk = kwargs['pk']
self.object = get_object_or_404(Schemas, pk=self.pk)
self.object.delete()
return redirect('idhub:admin_schemas')
class AdminSchemasDownloadView(SchemasMix):
def get(self, request, *args, **kwargs):
self.pk = kwargs['pk']
self.object = get_object_or_404(Schemas, pk=self.pk)
response = HttpResponse(self.object.data, content_type="application/json")
response['Content-Disposition'] = 'inline; filename={}'.format(self.object.file_schema)
return response
class AdminSchemasNewView(SchemasMix):
template_name = "idhub/admin/schemas_new.html"
subtitle = _('Upload Template')
icon = ''
success_url = reverse_lazy('idhub:admin_schemas')
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context.update({
'form': SchemaForm(),
})
return context
def post(self, request, *args, **kwargs):
form = SchemaForm(request.POST, request.FILES)
if form.is_valid():
schema = self.handle_uploaded_file()
if not schema:
messages.error(request, _("There are some errors in the file"))
return super().get(request, *args, **kwargs)
return redirect(self.success_url)
else:
return super().get(request, *args, **kwargs)
return super().post(request, *args, **kwargs)
def handle_uploaded_file(self):
f = self.request.FILES.get('file_template')
if not f:
return
file_name = f.name
if Schemas.objects.filter(file_schema=file_name).exists():
messages.error(self.request, _("This template already exists!"))
return
try:
data = f.read().decode('utf-8')
json.loads(data)
except Exception:
messages.error(self.request, _('This is not a schema valid!'))
return
schema = Schemas.objects.create(file_schema=file_name, data=data)
schema.save()
return schema
class AdminSchemasImportView(SchemasMix):
template_name = "idhub/admin/schemas_import.html"
subtitle = _('Import Template')
icon = '' icon = ''
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context.update({
'schemas': self.get_schemas(),
})
return context
class AdminSchemesExportView(Schemes): def get_schemas(self):
template_name = "idhub/admin/schemes_export.html" schemas_files = os.listdir(settings.SCHEMAS_DIR)
subtitle = _('Export Schemes') schemas = [x for x in schemas_files
icon = '' if not Schemas.objects.filter(file_schema=x).exists()]
return schemas
class AdminSchemasImportAddView(SchemasMix):
def get(self, request, *args, **kwargs):
file_name = kwargs['file_schema']
schemas_files = os.listdir(settings.SCHEMAS_DIR)
if not file_name in schemas_files:
messages.error(self.request, f"The schema {file_name} not exist!")
return redirect('idhub:admin_schemas_import')
schema = self.create_schema(file_name)
if schema:
messages.success(self.request, _("The schema add successfully!"))
return redirect('idhub:admin_schemas_import')
def create_schema(self, file_name):
data = self.open_file(file_name)
try:
json.loads(data)
except Exception:
messages.error(self.request, _('This is not a schema valid!'))
return
schema = Schemas.objects.create(file_schema=file_name, data=data)
schema.save()
return schema
def open_file(self, file_name):
data = ''
filename = Path(settings.SCHEMAS_DIR).joinpath(file_name)
with filename.open() as schema_file:
data = schema_file.read()
return data
class AdminImportView(ImportExport): class AdminImportView(ImportExport):
@ -458,8 +672,114 @@ class AdminImportView(ImportExport):
subtitle = _('Import') subtitle = _('Import')
icon = '' icon = ''
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context.update({
'dates': File_datas.objects,
})
return context
class AdminExportView(ImportExport):
template_name = "idhub/admin/export.html" class AdminImportStep2View(ImportExport):
subtitle = _('Export') template_name = "idhub/admin/import_step2.html"
subtitle = _('Import')
icon = '' icon = ''
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context.update({
'schemas': Schemas.objects,
})
return context
class AdminImportStep3View(ImportExport):
template_name = "idhub/admin/import_step3.html"
subtitle = _('Import')
icon = ''
success_url = reverse_lazy('idhub:admin_import')
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context.update({
'form': ImportForm(),
})
return context
def post(self, request, *args, **kwargs):
self.pk = kwargs['pk']
self.schema = get_object_or_404(Schemas, pk=self.pk)
form = ImportForm(request.POST, request.FILES)
if form.is_valid():
result = self.handle_uploaded_file()
if not result:
messages.error(request, _("There are some errors in the file"))
return super().get(request, *args, **kwargs)
return redirect(self.success_url)
else:
return super().get(request, *args, **kwargs)
return super().post(request, *args, **kwargs)
def handle_uploaded_file(self):
f = self.request.FILES.get('file_import')
if not f:
messages.error(self.request, _("There aren't file"))
return
file_name = f.name
if File_datas.objects.filter(file_name=file_name, success=True).exists():
messages.error(self.request, _("This file already exists!"))
return
self.json_schema = json.loads(self.schema.data)
df = pd.read_csv (f, delimiter="\t", quotechar='"', quoting=csv.QUOTE_ALL)
data_pd = df.fillna('').to_dict()
rows = {}
if not data_pd:
File_datas.objects.create(file_name=file_name, success=False)
return
for n in range(df.last_valid_index()+1):
row = {}
for k in data_pd.keys():
row[k] = data_pd[k][n]
user = self.validate(n, row)
if not user:
File_datas.objects.create(file_name=file_name, success=False)
return
rows[user] = row
File_datas.objects.create(file_name=file_name)
for k, v in rows.items():
self.create_credential(k, v)
return True
def validate(self, line, row):
try:
validate(instance=row, schema=self.json_schema)
except Exception as e:
messages.error(self.request, "line {}: {}".format(line+1, e))
return
user = User.objects.filter(email=row.get('email'))
if not user:
txt = _('The user not exist!')
messages.error(self.request, "line {}: {}".format(line+1, txt))
return
return user.first()
def create_credential(self, user, row):
d = copy.copy(self.json_schema)
d['instance'] = row
return VerificableCredential.objects.create(
verified=False,
user=user,
data=json.dumps(d)
)

View File

View File

View File

@ -0,0 +1,39 @@
from django.core.management.base import BaseCommand, CommandError
from django.contrib.auth import get_user_model
from idhub.models import Organization
User = get_user_model()
class Command(BaseCommand):
help = "Insert minimum datas for the project"
def handle(self, *args, **kwargs):
admin = 'admin@example.org'
pw_admin = '1234'
user = 'user1@example.org'
pw_user = '1234'
organization = [
("ExO", "https://verify.exo.cat"),
("Somos Connexión", "https://verify.somosconexion.coop")
]
# self.create_admin_users(admin, pw_admin)
self.create_users(user, pw_user)
for o in organization:
self.create_organizations(*o)
def create_admin_users(self, email, password):
User.objects.create_superuser(email=email, password=password)
def create_users(self, email, password):
u= User.objects.create(email=email, password=password)
u.set_password(password)
u.save()
def create_organizations(self, name, url):
Organization.objects.create(name=name, url=url)

View File

@ -1,4 +1,4 @@
# Generated by Django 4.2.5 on 2023-10-16 09:41 # Generated by Django 4.2.5 on 2023-11-02 15:08
from django.conf import settings from django.conf import settings
from django.db import migrations, models from django.db import migrations, models
@ -14,115 +14,247 @@ class Migration(migrations.Migration):
operations = [ operations = [
migrations.CreateModel( migrations.CreateModel(
name="VCTemplate", name='File_datas',
fields=[ fields=[
( (
"id", 'id',
models.BigAutoField( models.BigAutoField(
auto_created=True, auto_created=True,
primary_key=True, primary_key=True,
serialize=False, serialize=False,
verbose_name="ID", verbose_name='ID',
), ),
), ),
("wkit_template_id", models.CharField(max_length=250)), ('file_name', models.CharField(max_length=250)),
("data", models.TextField()), ('success', models.BooleanField(default=True)),
('created_at', models.DateTimeField(auto_now=True)),
], ],
), ),
migrations.CreateModel( migrations.CreateModel(
name="VerifiableCredential", name='Organization',
fields=[ fields=[
( (
"id", 'id',
models.BigAutoField( models.BigAutoField(
auto_created=True, auto_created=True,
primary_key=True, primary_key=True,
serialize=False, serialize=False,
verbose_name="ID", verbose_name='ID',
), ),
), ),
("id_string", models.CharField(max_length=250)), ('name', models.CharField(max_length=250)),
("verified", models.BooleanField()),
("created_on", models.DateTimeField()),
("did_issuer", models.CharField(max_length=250)),
("did_subject", models.CharField(max_length=250)),
("data", models.TextField()),
( (
"user", 'url',
models.ForeignKey( models.CharField(
on_delete=django.db.models.deletion.CASCADE, help_text='Url where to send the presentation', max_length=250
related_name="vcredentials",
to=settings.AUTH_USER_MODEL,
), ),
), ),
], ],
), ),
migrations.CreateModel( migrations.CreateModel(
name="Membership", name='Rol',
fields=[ fields=[
( (
"id", 'id',
models.BigAutoField( models.BigAutoField(
auto_created=True, auto_created=True,
primary_key=True, primary_key=True,
serialize=False, serialize=False,
verbose_name="ID", verbose_name='ID',
), ),
), ),
('name', models.CharField(max_length=250)),
],
),
migrations.CreateModel(
name='Schemas',
fields=[
( (
"type", 'id',
models.BigAutoField(
auto_created=True,
primary_key=True,
serialize=False,
verbose_name='ID',
),
),
('file_schema', models.CharField(max_length=250)),
('data', models.TextField()),
('created_at', models.DateTimeField(auto_now=True)),
],
),
migrations.CreateModel(
name='Service',
fields=[
(
'id',
models.BigAutoField(
auto_created=True,
primary_key=True,
serialize=False,
verbose_name='ID',
),
),
('domain', models.CharField(max_length=250)),
('description', models.CharField(max_length=250)),
('rol', models.ManyToManyField(to='idhub.rol')),
],
),
migrations.CreateModel(
name='VCTemplate',
fields=[
(
'id',
models.BigAutoField(
auto_created=True,
primary_key=True,
serialize=False,
verbose_name='ID',
),
),
('wkit_template_id', models.CharField(max_length=250)),
('data', models.TextField()),
],
),
migrations.CreateModel(
name='VerificableCredential',
fields=[
(
'id',
models.BigAutoField(
auto_created=True,
primary_key=True,
serialize=False,
verbose_name='ID',
),
),
('id_string', models.CharField(max_length=250)),
('verified', models.BooleanField()),
('created_on', models.DateTimeField(auto_now=True)),
('issuer_on', models.DateTimeField(null=True)),
('did_issuer', models.CharField(max_length=250)),
('did_subject', models.CharField(max_length=250)),
('data', models.TextField()),
(
'status',
models.PositiveSmallIntegerField( models.PositiveSmallIntegerField(
choices=[(1, "Beneficiary"), (2, "Employee"), (3, "Partner")], choices=[
verbose_name="Type of membership", (1, 'Enabled'),
(2, 'Issued'),
(3, 'Revoked'),
(4, 'Expired'),
],
default=1,
), ),
), ),
( (
"start_date", 'user',
models.DateField(
blank=True,
help_text="What date did the membership start?",
null=True,
verbose_name="Start date",
),
),
(
"end_date",
models.DateField(
blank=True,
help_text="What date did the membership end?",
null=True,
verbose_name="End date",
),
),
(
"user",
models.ForeignKey( models.ForeignKey(
on_delete=django.db.models.deletion.CASCADE, on_delete=django.db.models.deletion.CASCADE,
related_name="memberships", related_name='vcredentials',
to=settings.AUTH_USER_MODEL, to=settings.AUTH_USER_MODEL,
), ),
), ),
], ],
), ),
migrations.CreateModel( migrations.CreateModel(
name="DID", name='UserRol',
fields=[ fields=[
( (
"id", 'id',
models.BigAutoField( models.BigAutoField(
auto_created=True, auto_created=True,
primary_key=True, primary_key=True,
serialize=False, serialize=False,
verbose_name="ID", verbose_name='ID',
), ),
), ),
("did_string", models.CharField(max_length=250)),
("label", models.CharField(max_length=50)),
( (
"user", 'service',
models.ForeignKey( models.ForeignKey(
on_delete=django.db.models.deletion.CASCADE, on_delete=django.db.models.deletion.CASCADE,
related_name="dids", related_name='users',
to='idhub.service',
),
),
(
'user',
models.ForeignKey(
on_delete=django.db.models.deletion.CASCADE,
related_name='roles',
to=settings.AUTH_USER_MODEL,
),
),
],
),
migrations.CreateModel(
name='Membership',
fields=[
(
'id',
models.BigAutoField(
auto_created=True,
primary_key=True,
serialize=False,
verbose_name='ID',
),
),
(
'type',
models.PositiveSmallIntegerField(
choices=[(1, 'Beneficiary'), (2, 'Employee'), (3, 'Partner')],
verbose_name='Type of membership',
),
),
(
'start_date',
models.DateField(
blank=True,
help_text='What date did the membership start?',
null=True,
verbose_name='Start date',
),
),
(
'end_date',
models.DateField(
blank=True,
help_text='What date did the membership end?',
null=True,
verbose_name='End date',
),
),
(
'user',
models.ForeignKey(
on_delete=django.db.models.deletion.CASCADE,
related_name='memberships',
to=settings.AUTH_USER_MODEL,
),
),
],
),
migrations.CreateModel(
name='DID',
fields=[
(
'id',
models.BigAutoField(
auto_created=True,
primary_key=True,
serialize=False,
verbose_name='ID',
),
),
('created_at', models.DateTimeField(auto_now=True)),
('did', models.CharField(max_length=250, unique=True)),
('label', models.CharField(max_length=50)),
(
'user',
models.ForeignKey(
null=True,
on_delete=django.db.models.deletion.CASCADE,
related_name='dids',
to=settings.AUTH_USER_MODEL, to=settings.AUTH_USER_MODEL,
), ),
), ),

View File

@ -1,27 +0,0 @@
# Generated by Django 4.2.5 on 2023-10-17 11:28
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
("idhub", "0001_initial"),
]
operations = [
migrations.CreateModel(
name="Rol",
fields=[
(
"id",
models.BigAutoField(
auto_created=True,
primary_key=True,
serialize=False,
verbose_name="ID",
),
),
("name", models.CharField(max_length=250)),
],
),
]

View File

@ -1,37 +0,0 @@
# Generated by Django 4.2.5 on 2023-10-17 13:29
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
("idhub", "0002_rol"),
]
operations = [
migrations.CreateModel(
name="Service",
fields=[
(
"id",
models.BigAutoField(
auto_created=True,
primary_key=True,
serialize=False,
verbose_name="ID",
),
),
("domain", models.CharField(max_length=250)),
("description", models.CharField(max_length=250)),
(
"rol",
models.ForeignKey(
on_delete=django.db.models.deletion.CASCADE,
related_name="services",
to="idhub.rol",
),
),
],
),
]

View File

@ -1,45 +0,0 @@
# Generated by Django 4.2.5 on 2023-10-17 14:24
from django.conf import settings
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
("idhub", "0003_service"),
]
operations = [
migrations.CreateModel(
name="UserRol",
fields=[
(
"id",
models.BigAutoField(
auto_created=True,
primary_key=True,
serialize=False,
verbose_name="ID",
),
),
(
"service",
models.ForeignKey(
on_delete=django.db.models.deletion.CASCADE,
related_name="users",
to="idhub.service",
),
),
(
"user",
models.ForeignKey(
on_delete=django.db.models.deletion.CASCADE,
related_name="roles",
to=settings.AUTH_USER_MODEL,
),
),
],
),
]

View File

@ -1,21 +0,0 @@
# Generated by Django 4.2.5 on 2023-10-19 13:01
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
("idhub", "0004_userrol"),
]
operations = [
migrations.RemoveField(
model_name="service",
name="rol",
),
migrations.AddField(
model_name="service",
name="rol",
field=models.ManyToManyField(to="idhub.rol"),
),
]

View File

@ -26,7 +26,7 @@ class UserView(LoginRequiredMixin):
class AdminView(UserView): class AdminView(UserView):
def get(self, request, *args, **kwargs): def get(self, request, *args, **kwargs):
if not request.user.is_superuser: if not request.user.is_admin:
url = reverse_lazy('idhub:user_dashboard') url = reverse_lazy('idhub:user_dashboard')
return redirect(url) return redirect(url)

View File

@ -1,15 +1,8 @@
import json
import requests
from django.db import models from django.db import models
from django.utils.translation import gettext_lazy as _ from django.utils.translation import gettext_lazy as _
from django.contrib.auth.models import User from idhub_auth.models import User
# class AppUser(models.Model):
# Ya incluye "first_name", "last_name", "email", y "date_joined" heredando de la clase User de django.
# Falta ver que más información hay que añadir a nuestros usuarios, como los roles etc.
# django_user = models.OneToOneField(DjangoUser, on_delete=models.CASCADE)
# Extra data, segun entidad/organizacion
# pass
# class Event(models.Model): # class Event(models.Model):
@ -20,35 +13,103 @@ from django.contrib.auth.models import User
class DID(models.Model): class DID(models.Model):
did_string = models.CharField(max_length=250) created_at = models.DateTimeField(auto_now=True)
did = models.CharField(max_length=250, unique=True)
label = models.CharField(max_length=50) label = models.CharField(max_length=50)
user = models.ForeignKey( user = models.ForeignKey(
User, User,
on_delete=models.CASCADE, on_delete=models.CASCADE,
related_name='dids', related_name='dids',
null=True,
) )
# kind = "KEY|WEB" # kind = "KEY|WEB"
@property
def is_organization_did(self):
if not self.user:
return True
return False
class Schemas(models.Model):
file_schema = models.CharField(max_length=250)
data = models.TextField()
created_at = models.DateTimeField(auto_now=True)
@property
def get_schema(self):
if not self.data:
return {}
return json.loads(self.data)
def name(self):
return self.get_schema.get('name', '')
def description(self):
return self.get_schema.get('description', '')
class VerificableCredential(models.Model):
"""
Definition of Verificable Credentials
"""
class Status(models.IntegerChoices):
ENABLED = 1, _("Enabled")
ISSUED = 2, _("Issued")
REVOKED = 3, _("Revoked")
EXPIRED = 4, _("Expired")
class VerifiableCredential(models.Model):
id_string = models.CharField(max_length=250) id_string = models.CharField(max_length=250)
verified = models.BooleanField() verified = models.BooleanField()
created_on = models.DateTimeField() created_on = models.DateTimeField(auto_now=True)
issuer_on = models.DateTimeField(null=True)
did_issuer = models.CharField(max_length=250) did_issuer = models.CharField(max_length=250)
did_subject = models.CharField(max_length=250) did_subject = models.CharField(max_length=250)
data = models.TextField()
status = models.PositiveSmallIntegerField(
choices=Status.choices,
default=Status.ENABLED
)
user = models.ForeignKey( user = models.ForeignKey(
User, User,
on_delete=models.CASCADE, on_delete=models.CASCADE,
related_name='vcredentials', related_name='vcredentials',
) )
data = models.TextField()
@property
def get_schema(self):
if not self.data:
return {}
return json.loads(self.data)
def type(self):
return self.get_schema.get('name', '')
def description(self):
return self.get_schema.get('description', '')
def get_status(self):
return self.Status(self.status).label
def get_datas(self):
data = json.loads(self.data).get('instance').items()
return data
def get_issued(self, did):
self.status = self.Status.ISSUED
self.did_subject = did
class VCTemplate(models.Model): class VCTemplate(models.Model):
wkit_template_id = models.CharField(max_length=250) wkit_template_id = models.CharField(max_length=250)
data = models.TextField() data = models.TextField()
class File_datas(models.Model):
file_name = models.CharField(max_length=250)
success = models.BooleanField(default=True)
created_at = models.DateTimeField(auto_now=True)
class Membership(models.Model): class Membership(models.Model):
""" """
This model represent the relation of this user with the ecosystem. This model represent the relation of this user with the ecosystem.
@ -100,7 +161,7 @@ class Service(models.Model):
return ", ".join([x.name for x in self.rol.all()]) return ", ".join([x.name for x in self.rol.all()])
def __str__(self): def __str__(self):
return "{} -> {}".format(self.domain, self.rol.name) return "{} -> {}".format(self.domain, self.get_roles())
class UserRol(models.Model): class UserRol(models.Model):
@ -114,3 +175,18 @@ class UserRol(models.Model):
on_delete=models.CASCADE, on_delete=models.CASCADE,
related_name='users', related_name='users',
) )
class Organization(models.Model):
name = models.CharField(max_length=250)
url = models.CharField(
help_text=_("Url where to send the presentation"),
max_length=250
)
def __str__(self):
return self.name
def send(self, cred):
return
requests.post(self.url, data=cred.data)

View File

@ -6,4 +6,34 @@
<i class="{{ icon }}"></i> <i class="{{ icon }}"></i>
{{ subtitle }} {{ subtitle }}
</h3> </h3>
<div class="row mt-5">
<div class="col">
<div class="table-responsive">
<table class="table table-striped table-sm">
<thead>
<tr>
<th scope="col"><button type="button" class="btn btn-grey border border-dark">{% trans 'Type' %}</button></th>
<th scope="col"><button type="button" class="btn btn-grey border border-dark">{% trans 'Details' %}</button></th>
<th scope="col"><button type="button" class="btn btn-grey border border-dark">{% trans 'Issue' %}</button></th>
<th scope="col"><button type="button" class="btn btn-grey border border-dark">{% trans 'Status' %}</button></th>
<th scope="col"><button type="button" class="btn btn-grey border border-dark">{% trans 'User' %}</button></th>
<th scope="col"></th>
</tr>
</thead>
<tbody>
{% for f in credentials.all %}
<tr style="font-size:15px;">
<td>{{ f.type }}</td>
<td>{{ f.description }}</td>
<td>{{ f.issue_on }}</td>
<td>{{ f.get_status }}</td>
<td>{{ f.user.email }}</td>
<td><a href="{% url 'idhub:admin_credential' f.id %}" class="btn btn-green-admin">{% trans 'View' %}</a></td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
</div>
</div>
{% endblock %} {% endblock %}

View File

@ -0,0 +1,34 @@
{% extends "idhub/base_admin.html" %}
{% load i18n %}
{% block content %}
<h3>
<i class="{{ icon }}"></i>
{{ subtitle }}
</h3>
{% load django_bootstrap5 %}
<form role="form" method="post">
{% csrf_token %}
{% if form.errors %}
<div class="alert alert-danger alert-icon alert-icon-border alert-dismissible" role="alert">
<div class="icon"><span class="mdi mdi-close-circle-o"></span></div>
<div class="message">
{% for field, error in form.errors.items %}
{{ error }}<br />
{% endfor %}
<button class="btn-close" type="button" data-dismiss="alert" aria-label="Close"></button>
</div>
</div>
{% endif %}
<div class="row">
<div class="col-sm-4">
{% bootstrap_form form %}
</div>
</div>
<div class="form-actions-no-box">
<a class="btn btn-grey" href="{% url 'idhub:admin_dids' %}">{% translate "Cancel" %}</a>
<input class="btn btn-green-admin" type="submit" name="submit" value="{% translate 'Save' %}" />
</div>
</form>
{% endblock %}

View File

@ -0,0 +1,60 @@
{% extends "idhub/base_admin.html" %}
{% load i18n %}
{% block content %}
<h3>
<i class="{{ icon }}"></i>
{{ subtitle }}
</h3>
<div class="row mt-5">
<div class="col">
<div class="table-responsive">
<table class="table table-striped table-sm">
<thead>
<tr>
<th scope="col"><button type="button" class="btn btn-grey border border-dark">{% trans 'Date' %}</button></th>
<th scope="col"><button type="button" class="btn btn-grey border border-dark">{% trans 'Label' %}</button></th>
<th scope="col"><button type="button" class="btn btn-grey border border-dark">ID</button></th>
<th scope="col"></th>
<th scope="col"></th>
</tr>
</thead>
<tbody>
{% for d in dids.all %}
<tr style="font-size:15px;">
<td>{{ d.created_at }}</td>
<td>{{ d.label }}</td>
<td>{{ d.did }}</td>
<td><a class="text-primary" href="{% url 'idhub:admin_dids_edit' d.id %}" title="{% trans 'Edit' %}"><i class="bi bi-pencil-square"></i></a></td>
<td><a class="text-danger" href="jacascript:void()" data-bs-toggle="modal" data-bs-target="#confirm-delete-{{ d.id }}" title="{% trans 'Remove' %}"><i class="bi bi-x-circle"></i></a></td>
</tr>
{% endfor %}
</tbody>
</table>
<div class="form-actions-no-box">
<a class="btn btn-green-admin" href="{% url 'idhub:admin_dids_new' %}">{% translate "Add Identity" %} <i class="bi bi-plus"></i></a>
</div>
</div>
</div>
</div>
<!-- Modal -->
{% for d in dids.all %}
<div class="modal" id="confirm-delete-{{ d.id}}" tabindex="-1" aria-labelledby="exampleModalLabel" aria-hidden="true">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="exampleModalLabel">{% trans 'Delete DID' %} {{ d.did }}</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<div class="modal-body">
{% trans 'Are you sure that you want delete this DID?' %}
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Clancel</button>
<a href="{% url 'idhub:admin_dids_del' d.id %}" type="button" class="btn btn-danger">{% trans 'Delete' %}</a>
</div>
</div>
</div>
</div>
{% endfor %}
{% endblock %}

View File

@ -6,4 +6,31 @@
<i class="{{ icon }}"></i> <i class="{{ icon }}"></i>
{{ subtitle }} {{ subtitle }}
</h3> </h3>
<div class="row mt-5">
<div class="col">
<div class="table-responsive">
<table class="table table-striped table-sm">
<thead>
<tr>
<th scope="col"><button type="button" class="btn btn-grey border border-dark">{% trans 'Created at' %}</button></th>
<th scope="col"><button type="button" class="btn btn-grey border border-dark">{% trans 'File' %}</button></th>
<th scope="col"><button type="button" class="btn btn-grey border border-dark">{% trans 'success' %}</button></th>
</tr>
</thead>
<tbody>
{% for f in dates.all %}
<tr style="font-size:15px;">
<td>{{ f.created_at }}</td>
<td>{{ f.file_name }}</td>
<td>{% if f.success %}<i class="bi bi-check-circle text-primary"></i>{% else %}<i class="bi bi-x-circle text-danger"></i>{% endif %}</td>
</tr>
{% endfor %}
</tbody>
</table>
<div class="form-actions-no-box">
<a class="btn btn-green-admin" href="{% url 'idhub:admin_import_step2' %}">{% translate "Import Datas" %} <i class="bi bi-plus"></i></a>
</div>
</div>
</div>
</div>
{% endblock %} {% endblock %}

View File

@ -0,0 +1,34 @@
{% extends "idhub/base_admin.html" %}
{% load i18n %}
{% block content %}
<h3>
<i class="{{ icon }}"></i>
{{ subtitle }}
</h3>
<div class="row mt-5">
<div class="col">
<div class="table-responsive">
<table class="table table-striped table-sm">
<thead>
<tr>
<th scope="col"><button type="button" class="btn btn-grey border border-dark">{% trans 'Created at' %}</button></th>
<th scope="col"><button type="button" class="btn btn-grey border border-dark">{% trans 'Template file' %}</button></th>
<th scope="col"></th>
<th scope="col"></th>
</tr>
</thead>
<tbody>
{% for schema in schemas.all %}
<tr style="font-size:15px;">
<td>{{ schema.created_at }}</td>
<td>{{ schema.file_schema }}</td>
<td><a class="btn btn-green-admin" href="{% url 'idhub:admin_import_step3' schema.id %}" title="{% trans 'Import Dates' %}">{% trans 'Import Dates' %}</a></td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
</div>
</div>
{% endblock %}

View File

@ -0,0 +1,32 @@
{% extends "idhub/base_admin.html" %}
{% load i18n %}
{% block content %}
<h3>
<i class="{{ icon }}"></i>
{{ subtitle }}
</h3>
{% load django_bootstrap5 %}
<form role="form" method="post" enctype="multipart/form-data">
{% csrf_token %}
{% if form.errors %}
<div class="alert alert-danger alert-icon alert-icon-border alert-dismissible" role="alert">
<div class="icon"><span class="mdi mdi-close-circle-o"></span></div>
<div class="message">
<button class="close" type="button" data-dismiss="alert" aria-label="Close">
<span class="mdi mdi-close" aria-hidden="true"></span>
</button>
{% for field, error in form.errors.items %}
{{ error }}
{% endfor %}
</div>
</div>
{% endif %}
{% bootstrap_form form %}
<div class="form-actions-no-box">
<a class="btn btn-grey" href="{% url 'idhub:admin_import' %}">{% translate "Cancel" %}</a>
<input class="btn btn-green-admin" type="submit" name="submit" value="{% translate 'Save' %}" />
</div>
</form>
{% endblock %}

View File

@ -2,8 +2,55 @@
{% load i18n %} {% load i18n %}
{% block content %} {% block content %}
<h3> <div class="row">
<div class="col">
<h3>
<i class="{{ icon }}"></i> <i class="{{ icon }}"></i>
{{ subtitle }} {{ subtitle }}
</h3> </h3>
</div>
<div class="col text-end">
{% if object.get_status == 'Issued' %}
<a class="btn btn-yellow" href="{% url 'idhub:user_credential_json' object.id %}">{% trans 'Revoke' %}</a>
<a class="btn btn-orange" href="{% url 'idhub:user_credential_json' object.id %}">{% trans 'Delete' %}</a>
{% endif %}
</div>
</div>
<div class="row">
<div class="col-3">
</div>
<div class="col">
{% for k, v in object.get_datas %}
<div class="row mt-3">
<div class="col-3 text-end">
<strong>{{ k|capfirst }}:</strong>
</div>
<div class="col bg-light text-secondary">
{{ v }}
</div>
</div>
{% endfor %}
<div class="row mt-3">
<div class="col-3 text-end">
<strong>Date of Issue:</strong>
</div>
<div class="col bg-light text-secondary">
{{ object.issuer_on|default_if_none:"" }}
</div>
</div>
<div class="row mt-3">
<div class="col-3 text-end">
<strong>Status:</strong>
</div>
<div class="col bg-light text-secondary">
{{ object.get_status}}
</div>
</div>
<div class="row mt-3">
<div class="col text-center">
<a class="btn btn-green-user" href="{% url 'idhub:user_credential_json' object.id %}">{% trans 'View in JSON format' %}</a>
</div>
</div>
</div>
</div>
{% endblock %} {% endblock %}

View File

@ -12,7 +12,7 @@
<tr> <tr>
<th scope="col"><button type="button" class="btn btn-green-admin border border-dark">{% trans 'Last name' %}</button></th> <th scope="col"><button type="button" class="btn btn-green-admin border border-dark">{% trans 'Last name' %}</button></th>
<th scope="col"><button type="button" class="btn btn-grey border border-dark">{% trans 'First name' %}</button></th> <th scope="col"><button type="button" class="btn btn-grey border border-dark">{% trans 'First name' %}</button></th>
<th scope="col"><button type="button" class="btn btn-grey border border-dark">Username</button></th> <th scope="col"><button type="button" class="btn btn-grey border border-dark">Email</button></th>
<th scope="col"><button type="button" class="btn btn-grey border border-dark">{% trans 'Membership' %}</button></th> <th scope="col"><button type="button" class="btn btn-grey border border-dark">{% trans 'Membership' %}</button></th>
<th scope="col"><button type="button" class="btn btn-grey border border-dark">{% trans 'Role' %}</button></th> <th scope="col"><button type="button" class="btn btn-grey border border-dark">{% trans 'Role' %}</button></th>
<th scope="col"></th> <th scope="col"></th>
@ -23,7 +23,7 @@
<tr> <tr>
<td>{{ user.last_name }}</td> <td>{{ user.last_name }}</td>
<td>{{ user.first_name }}</td> <td>{{ user.first_name }}</td>
<td>{{ user.username }}</td> <td>{{ user.email }}</td>
<td> <td>
{% for m in user.memberships.all %} {% for m in user.memberships.all %}
{{ m.get_type }} {{ m.get_type }}

View File

@ -0,0 +1,62 @@
{% extends "idhub/base_admin.html" %}
{% load i18n %}
{% block content %}
<h3>
<i class="{{ icon }}"></i>
{{ subtitle }}
</h3>
<div class="row mt-5">
<div class="col">
<div class="table-responsive">
<table class="table table-striped table-sm">
<thead>
<tr>
<th scope="col"><button type="button" class="btn btn-grey border border-dark">{% trans 'Created at' %}</button></th>
<th scope="col"><button type="button" class="btn btn-grey border border-dark">{% trans 'Template file' %}</button></th>
<th scope="col"><button type="button" class="btn btn-grey border border-dark">{% trans 'Name' %}</button></th>
<th scope="col"><button type="button" class="btn btn-grey border border-dark">{% trans 'Description' %}</button></th>
<th scope="col"></th>
<th scope="col"></th>
</tr>
</thead>
<tbody>
{% for schema in schemas.all %}
<tr style="font-size:15px;">
<td>{{ schema.created_at }}</td>
<td>{{ schema.file_schema }}</td>
<td>{{ schema.name }}</td>
<td>{{ schema.description }}</td>
<td><a class="btn btn-green-admin" href="{% url 'idhub:admin_schemas_download' schema.id %}" target="_blank" title="{% trans 'View' %}">{% trans 'View' %}</a></td>
<td><a class="text-danger" href="jacascript:void()" data-bs-toggle="modal" data-bs-target="#confirm-delete-{{ schema.id }}" title="{% trans 'Remove' %}"><i class="bi bi-x-circle"></i></a></td>
</tr>
{% endfor %}
</tbody>
</table>
<div class="form-actions-no-box">
<a class="btn btn-green-admin" href="{% url 'idhub:admin_schemas_import' %}">{% translate "Add Template" %} <i class="bi bi-plus"></i></a>
</div>
</div>
</div>
</div>
<!-- Modal -->
{% for schema in schemas.all %}
<div class="modal" id="confirm-delete-{{ schema.id}}" tabindex="-1" aria-labelledby="exampleModalLabel" aria-hidden="true">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="exampleModalLabel">{% trans 'Delete Template' %} {{ schema.file_schema }}</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<div class="modal-body">
{% trans 'Are you sure that you want delete this template?' %}
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Clancel</button>
<a href="{% url 'idhub:admin_schemas_del' schema.id %}" type="button" class="btn btn-danger">{% trans 'Delete' %}</a>
</div>
</div>
</div>
</div>
{% endfor %}
{% endblock %}

View File

@ -0,0 +1,34 @@
{% extends "idhub/base_admin.html" %}
{% load i18n %}
{% block content %}
<h3>
<i class="{{ icon }}"></i>
{{ subtitle }}
</h3>
<div class="row mt-5">
<div class="col">
<div class="table-responsive">
<table class="table table-striped table-sm">
<thead>
<tr>
<th scope="col"><button type="button" class="btn btn-grey border border-dark">{% trans 'Template available' %}</button></th>
<th scope="col"></th>
</tr>
</thead>
<tbody>
{% for schema in schemas %}
<tr style="font-size:15px;">
<td>{{ schema }}</td>
<td><a class="text-primary" href="{% url 'idhub:admin_schemas_import_add' schema %}" title="{% trans 'Add' %}"><i class="bi bi-plus-circle"></i></a></td>
</tr>
{% endfor %}
</tbody>
</table>
<div class="form-actions-no-box">
<a class="btn btn-green-admin" href="{% url 'idhub:admin_schemas_new' %}">{% translate "Add template" %} <i class="bi bi-plus"></i></a>
</div>
</div>
</div>
</div>
{% endblock %}

View File

@ -0,0 +1,32 @@
{% extends "idhub/base_admin.html" %}
{% load i18n %}
{% block content %}
<h3>
<i class="{{ icon }}"></i>
{{ subtitle }}
</h3>
{% load django_bootstrap5 %}
<form role="form" method="post" enctype="multipart/form-data">
{% csrf_token %}
{% if form.errors %}
<div class="alert alert-danger alert-icon alert-icon-border alert-dismissible" role="alert">
<div class="icon"><span class="mdi mdi-close-circle-o"></span></div>
<div class="message">
<button class="close" type="button" data-dismiss="alert" aria-label="Close">
<span class="mdi mdi-close" aria-hidden="true"></span>
</button>
{% for field, error in form.errors.items %}
{{ error }}
{% endfor %}
</div>
</div>
{% endif %}
{% bootstrap_form form %}
<div class="form-actions-no-box">
<a class="btn btn-grey" href="{% url 'idhub:admin_schemas_import' %}">{% translate "Cancel" %}</a>
<input class="btn btn-green-admin" type="submit" name="submit" value="{% translate 'Save' %}" />
</div>
</form>
{% endblock %}

View File

@ -1,9 +0,0 @@
{% extends "idhub/base_admin.html" %}
{% load i18n %}
{% block content %}
<h3>
<i class="{{ icon }}"></i>
{{ subtitle }}
</h3>
{% endblock %}

View File

@ -1,9 +0,0 @@
{% extends "idhub/base_admin.html" %}
{% load i18n %}
{% block content %}
<h3>
<i class="{{ icon }}"></i>
{{ subtitle }}
</h3>
{% endblock %}

View File

@ -109,7 +109,7 @@
<div class="modal-dialog"> <div class="modal-dialog">
<div class="modal-content"> <div class="modal-content">
<div class="modal-header"> <div class="modal-header">
<h5 class="modal-title" id="exampleModalLabel">{% trans 'Delete user' %} {{ object.username }}</h5> <h5 class="modal-title" id="exampleModalLabel">{% trans 'Delete user' %} {{ object.email }}</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button> <button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
</div> </div>
<div class="modal-body"> <div class="modal-body">

View File

@ -1,9 +0,0 @@
{% extends "idhub/base_admin.html" %}
{% load i18n %}
{% block content %}
<h3>
<i class="{{ icon }}"></i>
{{ subtitle }}
</h3>
{% endblock %}

View File

@ -100,7 +100,7 @@
</span> </span>
<ul class="flex-column mb-2 ul_sidebar"> <ul class="flex-column mb-2 ul_sidebar">
<li class="nav-item"> <li class="nav-item">
<a class="nav-link {% if path == 'user_identities' %}active2{% endif %}" href="{% url 'idhub:user_identities' %}"> <a class="nav-link {% if path == 'user_dids' %}active2{% endif %}" href="{% url 'idhub:user_dids' %}">
Identities (DID) Identities (DID)
</a> </a>
</li> </li>
@ -110,8 +110,8 @@
</a> </a>
</li> </li>
<li class="nav-item"> <li class="nav-item">
<a class="nav-link {% if path == 'user_credentials_required' %}active2{% endif %}" href="{% url 'idhub:user_credentials_required' %}"> <a class="nav-link {% if path == 'user_credentials_request' %}active2{% endif %}" href="{% url 'idhub:user_credentials_request' %}">
Credentials required Credentials request
</a> </a>
</li> </li>
<li class="nav-item"> <li class="nav-item">
@ -144,10 +144,6 @@
</div> </div>
</div> </div>
<h3>
<i class="{{ icon }}"></i>
{{ subtitle }}
</h3>
{% block content %} {% block content %}
{% endblock content %} {% endblock content %}

View File

@ -117,23 +117,13 @@
Credentials list Credentials list
</a> </a>
</li> </li>
<li class="nav-item">
<a class="nav-link{% if path == 'admin_credentials_new' %} active2{% endif %}" href="{% url 'idhub:admin_credentials_new' %}">
Issue credentials
</a>
</li>
<li class="nav-item">
<a class="nav-link{% if path == 'admin_credentials_revoke' %} active2{% endif %}" href="{% url 'idhub:admin_credentials_revoke' %}">
Revoke Credentials
</a>
</li>
<li class="nav-item"> <li class="nav-item">
<a id="wallet" class="nav-link" data-bs-toggle="collapse" data-bs-target="#lwallet" aria-expanded="false" aria-controls="lwallet" href="javascript:void()"> <a id="wallet" class="nav-link" data-bs-toggle="collapse" data-bs-target="#lwallet" aria-expanded="false" aria-controls="lwallet" href="javascript:void()">
Wallet Wallet
</a> </a>
<ul class="flex-column mb-2 accordion-collapse {% if wallet %}expanded{% else %}collapse{% endif %}" id="lwallet" data-bs-parent="#wallet"> <ul class="flex-column mb-2 accordion-collapse {% if wallet %}expanded{% else %}collapse{% endif %}" id="lwallet" data-bs-parent="#wallet">
<li class="nav-item"> <li class="nav-item">
<a class="nav-link{% if path == 'admin_wallet_identities' %} active2{% endif %}" href="{% url 'idhub:admin_wallet_identities' %}"> <a class="nav-link{% if path == 'admin_dids' %} active2{% endif %}" href="{% url 'idhub:admin_dids' %}">
Identities (DID) Identities (DID)
</a> </a>
</li> </li>
@ -152,45 +142,16 @@
</ul> </ul>
</li> </li>
<li class="nav-item"> <li class="nav-item">
<a class="admin nav-link {% if section == 'Schemes' %}active {% endif %}fw-bold" data-bs-toggle="collapse" data-bs-target="#schemes" aria-expanded="false" aria-controls="schemes" href="javascript:void()"> <a class="admin nav-link {% if section == 'Templates' %}active {% endif %}fw-bold" href="{% url 'idhub:admin_schemas' %}">
<i class="bi bi-file-earmark-text icon_sidebar"></i> <i class="bi bi-file-earmark-text icon_sidebar"></i>
Schemes Templates
</a>
<ul class="flex-column mb-2 ul_sidebar accordion-collapse {% if section == 'Schemes' %}expanded{% else %}collapse{% endif %}" id="schemes" data-bs-parent="#sidebarMenu">
<li class="nav-item">
<a class="nav-link{% if path == 'admin_schemes' %} active2{% endif %}" href="{% url 'idhub:admin_schemes' %}">
List of schemes
</a> </a>
</li> </li>
<li class="nav-item"> <li class="nav-item">
<a class="nav-link{% if path == 'admin_schemes_import' %} active2{% endif %}" href="{% url 'idhub:admin_schemes_import' %}"> <a class="admin nav-link {% if section == 'ImportExport' %}active {% endif %}fw-bold" href="{% url 'idhub:admin_import' %}">
Import scheme
</a>
</li>
<li class="nav-item">
<a class="nav-link{% if path == 'admin_schemes_export' %} active2{% endif %}" href="{% url 'idhub:admin_schemes_export' %}">
Export scheme
</a>
</li>
</ul>
</li>
<li class="nav-item">
<a class="admin nav-link {% if section == 'ImportExport' %}active {% endif %}fw-bold" data-bs-toggle="collapse" data-bs-target="#import-export" aria-expanded="false" aria-controls="import-export" href="javascript:void()">
<i class="bi bi-arrow-down-square icon_sidebar"></i> <i class="bi bi-arrow-down-square icon_sidebar"></i>
Imports/Exports Import Datas
</a> </a>
<ul class="flex-column mb-2 ul_sidebar accordion-collapse {% if section == 'ImportExport' %}expanded{% else %}collapse{% endif %}" id="import-export" data-bs-parent="#sidebarMenu">
<li class="nav-item">
<a class="nav-link{% if path == 'admin_import' %} active2{% endif %}" href="{% url 'idhub:admin_import' %}">
Import
</a>
</li>
<li class="nav-item">
<a class="nav-link{% if path == 'admin_export' %} active2{% endif %}" href="{% url 'idhub:admin_export' %}">
Export
</a>
</li>
</ul>
</li> </li>
</ul> </ul>
</div> </div>

View File

@ -0,0 +1,46 @@
{% extends "idhub/base.html" %}
{% load i18n %}
{% block content %}
<h3>
<i class="{{ icon }}"></i>
{{ subtitle }}
</h3>
<div class="row">
<div class="col-3">
</div>
<div class="col">
{% for k, v in object.get_datas %}
<div class="row mt-3">
<div class="col-3 text-end">
<strong>{{ k|capfirst }}:</strong>
</div>
<div class="col bg-light text-secondary">
{{ v }}
</div>
</div>
{% endfor %}
<div class="row mt-3">
<div class="col-3 text-end">
<strong>Date of Issue:</strong>
</div>
<div class="col bg-light text-secondary">
{{ object.issuer_on|default_if_none:"" }}
</div>
</div>
<div class="row mt-3">
<div class="col-3 text-end">
<strong>Status:</strong>
</div>
<div class="col bg-light text-secondary">
{{ object.get_status}}
</div>
</div>
<div class="row mt-3">
<div class="col text-center">
<a class="btn btn-green-user" href="{% url 'idhub:user_credential_json' object.id %}">{% trans 'View in JSON format' %}</a>
</div>
</div>
</div>
</div>
{% endblock %}

View File

@ -2,4 +2,40 @@
{% load i18n %} {% load i18n %}
{% block content %} {% block content %}
<h3>
<i class="{{ icon }}"></i>
{{ subtitle }}
</h3>
<div class="row mt-5">
<div class="col">
<div class="table-responsive">
<table class="table table-striped table-sm">
<thead>
<tr>
<th scope="col"><button type="button" class="btn btn-grey border border-dark">{% trans 'Type' %}</button></th>
<th scope="col"><button type="button" class="btn btn-grey border border-dark">{% trans 'Details' %}</button></th>
<th scope="col"><button type="button" class="btn btn-grey border border-dark">{% trans 'Issue' %}</button></th>
<th scope="col"><button type="button" class="btn btn-grey border border-dark">{% trans 'Status' %}</button></th>
<th scope="col"></th>
</tr>
</thead>
<tbody>
{% for f in credentials.all %}
<tr style="font-size:15px;">
<td>{{ f.type }}</td>
<td>{{ f.description }}</td>
<td>{{ f.issue_on }}</td>
<td>{{ f.get_status }}</td>
<td>
<a href="{% url 'idhub:user_credential' f.id %}" class="text-primary">
<i class="bi bi-eye"></i>
</a>
</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
</div>
</div>
{% endblock %} {% endblock %}

View File

@ -2,4 +2,33 @@
{% load i18n %} {% load i18n %}
{% block content %} {% block content %}
<h3>
<i class="{{ icon }}"></i>
{{ subtitle }}
</h3>
{% load django_bootstrap5 %}
<form role="form" method="post">
{% csrf_token %}
{% if form.errors %}
<div class="alert alert-danger alert-icon alert-icon-border alert-dismissible" role="alert">
<div class="icon"><span class="mdi mdi-close-circle-o"></span></div>
<div class="message">
{% for field, error in form.errors.items %}
{{ error }}<br />
{% endfor %}
<button class="btn-close" type="button" data-dismiss="alert" aria-label="Close"></button>
</div>
</div>
{% endif %}
<div class="row">
<div class="col-sm-4">
{% bootstrap_form form %}
</div>
</div>
<div class="form-actions-no-box">
<a class="btn btn-grey" href="{% url 'idhub:user_credentials' %}">{% trans "Cancel" %}</a>
<input class="btn btn-green-user" type="submit" name="submit" value="{% trans 'Send' %}" />
</div>
</form>
{% endblock %} {% endblock %}

View File

@ -0,0 +1,34 @@
{% extends "idhub/base.html" %}
{% load i18n %}
{% block content %}
<h3>
<i class="{{ icon }}"></i>
{{ subtitle }}
</h3>
{% load django_bootstrap5 %}
<form role="form" method="post">
{% csrf_token %}
{% if form.errors %}
<div class="alert alert-danger alert-icon alert-icon-border alert-dismissible" role="alert">
<div class="icon"><span class="mdi mdi-close-circle-o"></span></div>
<div class="message">
{% for field, error in form.errors.items %}
{{ error }}<br />
{% endfor %}
<button class="btn-close" type="button" data-dismiss="alert" aria-label="Close"></button>
</div>
</div>
{% endif %}
<div class="row">
<div class="col-sm-4">
{% bootstrap_form form %}
</div>
</div>
<div class="form-actions-no-box">
<a class="btn btn-grey" href="{% url 'idhub:user_credentials' %}">{% trans "Cancel" %}</a>
<input class="btn btn-green-user" type="submit" name="submit" value="{% trans 'Request' %}" />
</div>
</form>
{% endblock %}

View File

@ -1,5 +0,0 @@
{% extends "idhub/base.html" %}
{% load i18n %}
{% block content %}
{% endblock %}

View File

@ -2,6 +2,10 @@
{% load i18n %} {% load i18n %}
{% block content %} {% block content %}
<h3>
<i class="{{ icon }}"></i>
{{ subtitle }}
</h3>
<div class="table-responsive"> <div class="table-responsive">
<table class="table table-striped table-sm"> <table class="table table-striped table-sm">
<thead> <thead>

View File

@ -0,0 +1,34 @@
{% extends "idhub/base.html" %}
{% load i18n %}
{% block content %}
<h3>
<i class="{{ icon }}"></i>
{{ subtitle }}
</h3>
{% load django_bootstrap5 %}
<form role="form" method="post">
{% csrf_token %}
{% if form.errors %}
<div class="alert alert-danger alert-icon alert-icon-border alert-dismissible" role="alert">
<div class="icon"><span class="mdi mdi-close-circle-o"></span></div>
<div class="message">
{% for field, error in form.errors.items %}
{{ error }}<br />
{% endfor %}
<button class="btn-close" type="button" data-dismiss="alert" aria-label="Close"></button>
</div>
</div>
{% endif %}
<div class="row">
<div class="col-sm-4">
{% bootstrap_form form %}
</div>
</div>
<div class="form-actions-no-box">
<a class="btn btn-grey" href="{% url 'idhub:user_dids' %}">{% trans "Cancel" %}</a>
<input class="btn btn-green-admin" type="submit" name="submit" value="{% trans 'Save' %}" />
</div>
</form>
{% endblock %}

View File

@ -0,0 +1,60 @@
{% extends "idhub/base.html" %}
{% load i18n %}
{% block content %}
<h3>
<i class="{{ icon }}"></i>
{{ subtitle }}
</h3>
<div class="row mt-5">
<div class="col">
<div class="table-responsive">
<table class="table table-striped table-sm">
<thead>
<tr>
<th scope="col"><button type="button" class="btn btn-grey border border-dark">{% trans 'Date' %}</button></th>
<th scope="col"><button type="button" class="btn btn-grey border border-dark">{% trans 'Label' %}</button></th>
<th scope="col"><button type="button" class="btn btn-grey border border-dark">ID</button></th>
<th scope="col"></th>
<th scope="col"></th>
</tr>
</thead>
<tbody>
{% for d in dids.all %}
<tr style="font-size:15px;">
<td>{{ d.created_at }}</td>
<td>{{ d.label }}</td>
<td>{{ d.did }}</td>
<td><a class="text-primary" href="{% url 'idhub:user_dids_edit' d.id %}" title="{% trans 'Edit' %}"><i class="bi bi-pencil-square"></i></a></td>
<td><a class="text-danger" href="jacascript:void()" data-bs-toggle="modal" data-bs-target="#confirm-delete-{{ d.id }}" title="{% trans 'Remove' %}"><i class="bi bi-x-circle"></i></a></td>
</tr>
{% endfor %}
</tbody>
</table>
<div class="form-actions-no-box">
<a class="btn btn-green-user" href="{% url 'idhub:user_dids_new' %}">{% translate "Add Identity" %} <i class="bi bi-plus"></i></a>
</div>
</div>
</div>
</div>
<!-- Modal -->
{% for d in dids.all %}
<div class="modal" id="confirm-delete-{{ d.id}}" tabindex="-1" aria-labelledby="exampleModalLabel" aria-hidden="true">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="exampleModalLabel">{% trans 'Delete DID' %} {{ d.did }}</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<div class="modal-body">
{% trans 'Are you sure that you want delete this DID?' %}
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Clancel</button>
<a href="{% url 'idhub:user_dids_del' d.id %}" type="button" class="btn btn-danger">{% trans 'Delete' %}</a>
</div>
</div>
</div>
</div>
{% endfor %}
{% endblock %}

View File

@ -2,4 +2,8 @@
{% load i18n %} {% load i18n %}
{% block content %} {% block content %}
<h3>
<i class="{{ icon }}"></i>
{{ subtitle }}
</h3>
{% endblock %} {% endblock %}

View File

@ -1,5 +0,0 @@
{% extends "idhub/base.html" %}
{% load i18n %}
{% block content %}
{% endblock %}

View File

@ -2,6 +2,18 @@
{% load i18n %} {% load i18n %}
{% block content %} {% block content %}
<div class="row">
<div class="col">
<h3>
<i class="{{ icon }}"></i>
{{ subtitle }}
</h3>
</div>
<div class="col text-center">
<a href="javascript:void()" type="button" class="btn btn-green-user me-3">{% trans 'ARCO Forms' %}</a>
<a href="javascript:void()" type="button" class="btn btn-green-user">{% trans 'Notice of Privacy' %}</a>
</div>
</div>
{% load django_bootstrap5 %} {% load django_bootstrap5 %}
<form role="form" method="post"> <form role="form" method="post">
{% csrf_token %} {% csrf_token %}
@ -25,4 +37,36 @@
</div> </div>
</form> </form>
<hr />
<div class="row">
<div class="col">
<div class="table-responsive">
<table class="table table-striped table-sm text-center">
<thead>
<tr>
<th scope="col"><button type="button" class="btn btn-grey border border-dark">{% trans 'Membership' %}</button></th>
<th scope="col"><button type="button" class="btn btn-grey border border-dark">{% trans 'From' %}</button></th>
<th scope="col"><button type="button" class="btn btn-grey border border-dark">{% trans 'To' %}</button></th>
<th scope="col"><button type="button" class="btn btn-grey border border-dark">{% trans 'Credentials' %}</button></th>
</tr>
</thead>
<tbody>
{% for membership in object.memberships.all %}
<tr>
<td>{{ membership.get_type }}</td>
<td>{{ membership.start_date|default:'' }}</td>
<td>{{ membership.end_date|default:'' }}</td>
<td>
<a href="javascript:void()" class="text-primary">
<i class="bi bi-eye"></i>
</a>
</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
</div>
</div>
{% endblock %} {% endblock %}

View File

@ -2,6 +2,10 @@
{% load i18n %} {% load i18n %}
{% block content %} {% block content %}
<h3>
<i class="{{ icon }}"></i>
{{ subtitle }}
</h3>
<div class="row mt-5"> <div class="row mt-5">
<div class="col"> <div class="col">
<div class="table-responsive"> <div class="table-responsive">
@ -16,7 +20,7 @@
<tbody> <tbody>
{% for rol in user.roles.all %} {% for rol in user.roles.all %}
<tr> <tr>
<td>{{ rol.service.rol.name }}</td> <td>{{ rol.service.get_roles }}</td>
<td>{{ rol.service.description }}</td> <td>{{ rol.service.description }}</td>
<td>{{ rol.service.domain }}</td> <td>{{ rol.service.domain }}</td>
</tr> </tr>

View File

@ -67,13 +67,23 @@ urlpatterns = [
name='user_roles'), name='user_roles'),
path('user/gdpr/', views_user.UserGDPRView.as_view(), path('user/gdpr/', views_user.UserGDPRView.as_view(),
name='user_gdpr'), name='user_gdpr'),
path('user/identities/', views_user.UserIdentitiesView.as_view(), path('user/identities/', views_user.UserDidsView.as_view(),
name='user_identities'), name='user_dids'),
path('user/dids/new/', views_user.UserDidRegisterView.as_view(),
name='user_dids_new'),
path('user/dids/<int:pk>/', views_user.UserDidEditView.as_view(),
name='user_dids_edit'),
path('user/dids/<int:pk>/del/', views_user.UserDidDeleteView.as_view(),
name='user_dids_del'),
path('user/credentials/', views_user.UserCredentialsView.as_view(), path('user/credentials/', views_user.UserCredentialsView.as_view(),
name='user_credentials'), name='user_credentials'),
path('user/credentials_required/', path('user/credentials/<int:pk>', views_user.UserCredentialView.as_view(),
views_user.UserCredentialsRequiredView.as_view(), name='user_credential'),
name='user_credentials_required'), path('user/credentials/<int:pk>/json', views_user.UserCredentialJsonView.as_view(),
name='user_credential_json'),
path('user/credentials/request/',
views_user.UserCredentialsRequestView.as_view(),
name='user_credentials_request'),
path('user/credentials_presentation/', path('user/credentials_presentation/',
views_user.UserCredentialsPresentationView.as_view(), views_user.UserCredentialsPresentationView.as_view(),
name='user_credentials_presentation'), name='user_credentials_presentation'),
@ -123,26 +133,40 @@ urlpatterns = [
name='admin_service_del'), name='admin_service_del'),
path('admin/credentials/', views_admin.AdminCredentialsView.as_view(), path('admin/credentials/', views_admin.AdminCredentialsView.as_view(),
name='admin_credentials'), name='admin_credentials'),
path('admin/credentials/new/', views_admin.AdminIssueCredentialsView.as_view(), path('admin/credentials/<int:pk>/', views_admin.AdminCredentialView.as_view(),
name='admin_credentials_new'), name='admin_credential'),
path('admin/credentials/revoke/', views_admin.AdminRevokeCredentialsView.as_view(), path('admin/credentials/revoke/', views_admin.AdminRevokeCredentialsView.as_view(),
name='admin_credentials_revoke'), name='admin_credentials_revoke'),
path('admin/wallet/identities/', views_admin.AdminWalletIdentitiesView.as_view(), path('admin/wallet/identities/', views_admin.AdminDidsView.as_view(),
name='admin_wallet_identities'), name='admin_dids'),
path('admin/dids/new/', views_admin.AdminDidRegisterView.as_view(),
name='admin_dids_new'),
path('admin/dids/<int:pk>/', views_admin.AdminDidEditView.as_view(),
name='admin_dids_edit'),
path('admin/dids/<int:pk>/del/', views_admin.AdminDidDeleteView.as_view(),
name='admin_dids_del'),
path('admin/wallet/credentials/', views_admin.AdminWalletCredentialsView.as_view(), path('admin/wallet/credentials/', views_admin.AdminWalletCredentialsView.as_view(),
name='admin_wallet_credentials'), name='admin_wallet_credentials'),
path('admin/wallet/config/issue/', views_admin.AdminWalletConfigIssuesView.as_view(), path('admin/wallet/config/issue/', views_admin.AdminWalletConfigIssuesView.as_view(),
name='admin_wallet_config_issue'), name='admin_wallet_config_issue'),
path('admin/wallet/config/issue/', views_admin.AdminWalletConfigIssuesView.as_view(), path('admin/wallet/config/issue/', views_admin.AdminWalletConfigIssuesView.as_view(),
name='admin_wallet_config_issue'), name='admin_wallet_config_issue'),
path('admin/schemes/', views_admin.AdminSchemesView.as_view(), path('admin/schemas/', views_admin.AdminSchemasView.as_view(),
name='admin_schemes'), name='admin_schemas'),
path('admin/schemes/import', views_admin.AdminSchemesImportView.as_view(), path('admin/schemas/<int:pk>/del/', views_admin.AdminSchemasDeleteView.as_view(),
name='admin_schemes_import'), name='admin_schemas_del'),
path('admin/schemes/export/', views_admin.AdminSchemesExportView.as_view(), path('admin/schemas/<int:pk>/', views_admin.AdminSchemasDownloadView.as_view(),
name='admin_schemes_export'), name='admin_schemas_download'),
path('admin/schemas/new', views_admin.AdminSchemasNewView.as_view(),
name='admin_schemas_new'),
path('admin/schemas/import', views_admin.AdminSchemasImportView.as_view(),
name='admin_schemas_import'),
path('admin/schemas/import/<str:file_schema>', views_admin.AdminSchemasImportAddView.as_view(),
name='admin_schemas_import_add'),
path('admin/import', views_admin.AdminImportView.as_view(), path('admin/import', views_admin.AdminImportView.as_view(),
name='admin_import'), name='admin_import'),
path('admin/export/', views_admin.AdminExportView.as_view(), path('admin/import/new', views_admin.AdminImportStep2View.as_view(),
name='admin_export'), name='admin_import_step2'),
path('admin/import/<int:pk>/', views_admin.AdminImportStep3View.as_view(),
name='admin_import_step3'),
] ]

View File

@ -1,5 +1,7 @@
from django import forms from django import forms
from django.contrib.auth.models import User from idhub_auth.models import User
from idhub.models import DID, VerificableCredential, Organization
class ProfileForm(forms.ModelForm): class ProfileForm(forms.ModelForm):
@ -8,3 +10,85 @@ class ProfileForm(forms.ModelForm):
class Meta: class Meta:
model = User model = User
fields = ('first_name', 'last_name', 'email') fields = ('first_name', 'last_name', 'email')
class RequestCredentialForm(forms.Form):
did = forms.ChoiceField(choices=[])
credential = forms.ChoiceField(choices=[])
def __init__(self, *args, **kwargs):
self.user = kwargs.pop('user', None)
super().__init__(*args, **kwargs)
self.fields['did'].choices = [
(x.did, x.label) for x in DID.objects.filter(user=self.user)
]
self.fields['credential'].choices = [
(x.id, x.type()) for x in VerificableCredential.objects.filter(
user=self.user,
status=VerificableCredential.Status.ENABLED
)
]
def save(self, commit=True):
did = DID.objects.filter(
user=self.user,
did=self.data['did']
)
cred = VerificableCredential.objects.filter(
user=self.user,
id=self.data['credential'],
status=VerificableCredential.Status.ENABLED
)
if not all([cred.exists(), did.exists()]):
return
did = did[0].did
cred = cred[0]
cred.get_issued(did)
if commit:
cred.save()
return cred
return
class CredentialPresentationForm(forms.Form):
organization = forms.ChoiceField(choices=[])
credential = forms.ChoiceField(choices=[])
def __init__(self, *args, **kwargs):
self.user = kwargs.pop('user', None)
super().__init__(*args, **kwargs)
self.fields['organization'].choices = [
(x.id, x.name) for x in Organization.objects.filter()
]
self.fields['credential'].choices = [
(x.id, x.type()) for x in VerificableCredential.objects.filter(
user=self.user,
status=VerificableCredential.Status.ISSUED
)
]
def save(self, commit=True):
org = Organization.objects.filter(
id=self.data['organization']
)
cred = VerificableCredential.objects.filter(
user=self.user,
id=self.data['credential'],
status=VerificableCredential.Status.ISSUED
)
if not all([org.exists(), cred.exists()]):
return
org =org[0]
cred = cred[0]
if commit:
org.send(cred)
return cred
return

View File

@ -1,12 +1,21 @@
import logging import logging
from django.utils.translation import gettext_lazy as _ from django.utils.translation import gettext_lazy as _
from django.views.generic.edit import UpdateView from django.views.generic.edit import (
UpdateView,
CreateView,
DeleteView,
FormView
)
from django.views.generic.base import TemplateView from django.views.generic.base import TemplateView
from django.shortcuts import get_object_or_404, redirect
from django.urls import reverse_lazy from django.urls import reverse_lazy
from django.http import HttpResponse
from django.contrib import messages from django.contrib import messages
from idhub.user.forms import ProfileForm from apiregiter import iota
from idhub.user.forms import ProfileForm, RequestCredentialForm, CredentialPresentationForm
from idhub.mixins import UserView from idhub.mixins import UserView
from idhub.models import DID, VerificableCredential
class MyProfile(UserView): class MyProfile(UserView):
@ -14,7 +23,7 @@ class MyProfile(UserView):
section = "MyProfile" section = "MyProfile"
class MyWallet(UserView, TemplateView): class MyWallet(UserView):
title = _("My Wallet") title = _("My Wallet")
section = "MyWallet" section = "MyWallet"
@ -51,25 +60,178 @@ class UserGDPRView(MyProfile, TemplateView):
icon = 'bi bi-file-earmark-medical' icon = 'bi bi-file-earmark-medical'
class UserIdentitiesView(MyWallet): class UserCredentialsView(MyWallet, TemplateView):
template_name = "idhub/user/identities.html"
subtitle = _('Identities (DID)')
icon = 'bi bi-patch-check-fill'
class UserCredentialsView(MyWallet):
template_name = "idhub/user/credentials.html" template_name = "idhub/user/credentials.html"
subtitle = _('Credentials') subtitle = _('Credentials')
icon = 'bi bi-patch-check-fill' icon = 'bi bi-patch-check-fill'
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context.update({
'credentials': VerificableCredential.objects,
})
return context
class UserCredentialsRequiredView(MyWallet):
template_name = "idhub/user/credentials_required.html" class UserCredentialView(MyWallet, TemplateView):
subtitle = _('Credentials required') template_name = "idhub/user/credential.html"
subtitle = _('Credential')
icon = 'bi bi-patch-check-fill' icon = 'bi bi-patch-check-fill'
def get(self, request, *args, **kwargs):
self.pk = kwargs['pk']
self.object = get_object_or_404(
VerificableCredential,
pk=self.pk,
user=self.request.user
)
return super().get(request, *args, **kwargs)
class UserCredentialsPresentationView(MyWallet): def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context.update({
'object': self.object,
})
return context
class UserCredentialJsonView(MyWallet, TemplateView):
def get(self, request, *args, **kwargs):
pk = kwargs['pk']
self.object = get_object_or_404(
VerificableCredential,
pk=pk,
user=self.request.user
)
response = HttpResponse(self.object.data, content_type="application/json")
response['Content-Disposition'] = 'attachment; filename={}'.format("credential.json")
return response
class UserCredentialsRequestView(MyWallet, FormView):
template_name = "idhub/user/credentials_request.html"
subtitle = _('Credentials request')
icon = 'bi bi-patch-check-fill'
form_class = RequestCredentialForm
success_url = reverse_lazy('idhub:user_credentials')
def get_form_kwargs(self):
kwargs = super().get_form_kwargs()
kwargs['user'] = self.request.user
return kwargs
def form_valid(self, form):
cred = form.save()
if cred:
messages.success(self.request, _("The credential was required successfully!"))
else:
messages.error(self.request, _("Not exists the credential!"))
return super().form_valid(form)
class UserCredentialsPresentationView(MyWallet, FormView):
template_name = "idhub/user/credentials_presentation.html" template_name = "idhub/user/credentials_presentation.html"
subtitle = _('Credentials Presentation') subtitle = _('Credentials Presentation')
icon = 'bi bi-patch-check-fill' icon = 'bi bi-patch-check-fill'
form_class = CredentialPresentationForm
success_url = reverse_lazy('idhub:user_credentials')
def get_form_kwargs(self):
kwargs = super().get_form_kwargs()
kwargs['user'] = self.request.user
return kwargs
def form_valid(self, form):
cred = form.save()
if cred:
messages.success(self.request, _("The credential was presented successfully!"))
else:
messages.error(self.request, _("Error sending credential!"))
return super().form_valid(form)
class UserDidsView(MyWallet, TemplateView):
template_name = "idhub/user/dids.html"
subtitle = _('Identities (DID)')
icon = 'bi bi-patch-check-fill'
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context.update({
'dids': self.request.user.dids,
})
return context
class UserDidRegisterView(MyWallet, CreateView):
template_name = "idhub/user/did_register.html"
subtitle = _('Add a new Identities (DID)')
icon = 'bi bi-patch-check-fill'
wallet = True
model = DID
fields = ('did', 'label')
success_url = reverse_lazy('idhub:user_dids')
object = None
def get_form_kwargs(self):
kwargs = super().get_form_kwargs()
kwargs['initial'] = {
'did': iota.issue_did(),
'user': self.request.user
}
return kwargs
def get_form(self):
form = super().get_form()
form.fields['did'].required = False
form.fields['did'].disabled = True
return form
def form_valid(self, form):
form.instance.user = self.request.user
form.save()
messages.success(self.request, _('DID created successfully'))
return super().form_valid(form)
class UserDidEditView(MyWallet, UpdateView):
template_name = "idhub/user/did_register.html"
subtitle = _('Identities (DID)')
icon = 'bi bi-patch-check-fill'
wallet = True
model = DID
fields = ('did', 'label')
success_url = reverse_lazy('idhub:user_dids')
def get(self, request, *args, **kwargs):
self.pk = kwargs['pk']
self.object = get_object_or_404(self.model, pk=self.pk)
return super().get(request, *args, **kwargs)
def get_form(self):
form = super().get_form()
form.fields['did'].required = False
form.fields['did'].disabled = True
return form
def form_valid(self, form):
user = form.save()
messages.success(self.request, _('DID updated successfully'))
return super().form_valid(form)
class UserDidDeleteView(MyWallet, DeleteView):
subtitle = _('Identities (DID)')
icon = 'bi bi-patch-check-fill'
wallet = True
model = DID
success_url = reverse_lazy('idhub:user_dids')
def get(self, request, *args, **kwargs):
self.pk = kwargs['pk']
self.object = get_object_or_404(self.model, pk=self.pk)
self.object.delete()
messages.success(self.request, _('DID delete successfully'))
return redirect(self.success_url)

0
idhub_auth/__init__.py Normal file
View File

7
idhub_auth/admin.py Normal file
View File

@ -0,0 +1,7 @@
from django.contrib import admin
from django.contrib.auth import get_user_model
User = get_user_model()
admin.site.register(User)

6
idhub_auth/apps.py Normal file
View File

@ -0,0 +1,6 @@
from django.apps import AppConfig
class AuthConfig(AppConfig):
default_auto_field = 'django.db.models.BigAutoField'
name = 'idhub_auth'

View File

@ -0,0 +1,46 @@
# Generated by Django 4.2.5 on 2023-11-02 15:08
from django.db import migrations, models
class Migration(migrations.Migration):
initial = True
dependencies = []
operations = [
migrations.CreateModel(
name='User',
fields=[
(
'id',
models.BigAutoField(
auto_created=True,
primary_key=True,
serialize=False,
verbose_name='ID',
),
),
('password', models.CharField(max_length=128, verbose_name='password')),
(
'last_login',
models.DateTimeField(
blank=True, null=True, verbose_name='last login'
),
),
(
'email',
models.EmailField(
max_length=255, unique=True, verbose_name='email address'
),
),
('is_active', models.BooleanField(default=True)),
('is_admin', models.BooleanField(default=False)),
('first_name', models.CharField(blank=True, max_length=255, null=True)),
('last_name', models.CharField(blank=True, max_length=255, null=True)),
],
options={
'abstract': False,
},
),
]

View File

74
idhub_auth/models.py Normal file
View File

@ -0,0 +1,74 @@
from django.db import models
from django.contrib.auth.models import BaseUserManager, AbstractBaseUser
class UserManager(BaseUserManager):
def create_user(self, email, password=None):
"""
Creates and saves a User with the given email, date of
birth and password.
"""
if not email:
raise ValueError("Users must have an email address")
user = self.model(
email=self.normalize_email(email),
)
user.set_password(password)
user.save(using=self._db)
return user
def create_superuser(self, email, password=None):
"""
Creates and saves a superuser with the given email, date of
birth and password.
"""
user = self.create_user(
email,
password=password,
)
user.is_admin = True
user.save(using=self._db)
return user
class User(AbstractBaseUser):
email = models.EmailField(
verbose_name="email address",
max_length=255,
unique=True,
)
is_active = models.BooleanField(default=True)
is_admin = models.BooleanField(default=False)
first_name = models.CharField(max_length=255, blank=True, null=True)
last_name = models.CharField(max_length=255, blank=True, null=True)
objects = UserManager()
USERNAME_FIELD = "email"
REQUIRED_FIELDS = []
def __str__(self):
return self.email
def has_perm(self, perm, obj=None):
"Does the user have a specific permission?"
# Simplest possible answer: Yes, always
return True
def has_module_perms(self, app_label):
"Does the user have permissions to view the app `app_label`?"
# Simplest possible answer: Yes, always
return True
@property
def is_staff(self):
"Is the user a member of staff?"
# Simplest possible answer: All admins are staff
return self.is_admin
@property
def username(self):
"Is the email of the user"
return self.email

6
pyproject.toml Normal file
View File

@ -0,0 +1,6 @@
[tool.black]
skip-string-normalization = true
target-version = ['py311']
[tool.isort]
profile = "black"

View File

@ -3,3 +3,7 @@ django-bootstrap5==23.3
django-extensions==3.2.3 django-extensions==3.2.3
black==23.9.1 black==23.9.1
python-decouple==3.8 python-decouple==3.8
jsonschema==4.19.1
pandas==2.1.1
requests==2.31.0

View File

@ -0,0 +1,21 @@
{
"$id": "https://pangea.org/schemas/member-credential-schema.json",
"$schema": "https://json-schema.org/draft/2020-12/schema",
"name": "MemberCredential",
"description": "MemberCredential using JsonSchemaCredential",
"type": "object",
"properties": {
"name": {
"type": "string"
},
"email": {
"type": "string",
"format": "email"
},
"membershipType": {
"type": "string",
"enum": ["individual", "organization"]
}
},
"required": ["name", "email", "membershipType"]
}

40
schemas/member.json Normal file
View File

@ -0,0 +1,40 @@
{
"@context": [
"https://www.w3.org/ns/credentials/v2",
"https://www.w3.org/ns/credentials/examples/v2"
],
"id": "https://example.com/credentials/3734",
"type": ["VerifiableCredential", "JsonSchemaCredential"],
"issuer": "https://pangea.org/issuers/10",
"issuanceDate": "2023-09-01T19:23:24Z",
"credentialSchema": {
"id": "https://www.w3.org/2022/credentials/v2/json-schema-credential-schema.json",
"type": "JsonSchema",
"digestSRI": "sha384-S57yQDg1MTzF56Oi9DbSQ14u7jBy0RDdx0YbeV7shwhCS88G8SCXeFq82PafhCrW"
},
"credentialSubject": {
"id": "https://pangea.org/schemas/member-credential-schema.json",
"type": "JsonSchema",
"jsonSchema": {
"$id": "https://pangea.org/schemas/member-credential-schema.json",
"$schema": "https://json-schema.org/draft/2020-12/schema",
"name": "MemberCredential",
"description": "MemberCredential using JsonSchemaCredential",
"type": "object",
"properties": {
"name": {
"type": "string"
},
"email": {
"type": "string",
"format": "email"
},
"membershipType": {
"type": "string",
"enum": ["individual", "organization"]
}
},
"required": ["name", "email", "membershipType"]
}
}
}

View File

@ -70,6 +70,7 @@ INSTALLED_APPS = [
'django.contrib.staticfiles', 'django.contrib.staticfiles',
'django_extensions', 'django_extensions',
'django_bootstrap5', 'django_bootstrap5',
'idhub_auth',
'idhub' 'idhub'
] ]
@ -160,6 +161,7 @@ MEDIA_URL = '/media/'
STATIC_ROOT = config('STATIC_ROOT') STATIC_ROOT = config('STATIC_ROOT')
MEDIA_ROOT = config('MEDIA_ROOT', default="idhub/upload") MEDIA_ROOT = config('MEDIA_ROOT', default="idhub/upload")
FIXTURE_DIRS = (os.path.join(BASE_DIR, 'fixtures'),) FIXTURE_DIRS = (os.path.join(BASE_DIR, 'fixtures'),)
SCHEMAS_DIR = os.path.join(BASE_DIR, 'schemas')
# Default primary key field type # Default primary key field type
# https://docs.djangoproject.com/en/4.2/ref/settings/#default-auto-field # https://docs.djangoproject.com/en/4.2/ref/settings/#default-auto-field
@ -176,3 +178,4 @@ MESSAGE_TAGS = {
messages.ERROR: 'alert-danger', messages.ERROR: 'alert-danger',
} }
AUTH_USER_MODEL = 'idhub_auth.User'