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.contrib.auth.models import User
from idhub.models import Rol
class ProfileForm(forms.ModelForm):
MANDATORY_FIELDS = ['first_name', 'last_name', 'email', 'username']
class Meta:
model = User
fields = ('first_name', 'last_name', 'email')
class ImportForm(forms.Form):
file_import = forms.FileField()
class MembershipForm(forms.ModelForm):
MANDATORY_FIELDS = ['type']
class RolForm(forms.ModelForm):
MANDATORY_FIELDS = ['name']
class ServiceForm(forms.ModelForm):
MANDATORY_FIELDS = ['domain', 'rol']
class UserRolForm(forms.ModelForm):
MANDATORY_FIELDS = ['service']
class SchemaForm(forms.Form):
file_template = forms.FileField()

View File

@ -1,22 +1,35 @@
import os
import csv
import json
import copy
import logging
import pandas as pd
from pathlib import Path
from jsonschema import validate
from smtplib import SMTPException
from django.conf import settings
from django.utils.translation import gettext_lazy as _
from django.views.generic.base import TemplateView
from django.views.generic.edit import UpdateView, CreateView
from django.contrib.auth.models import User
from django.views.generic.edit import UpdateView, CreateView, DeleteView
from django.shortcuts import get_object_or_404, redirect
from django.urls import reverse_lazy
from django.http import HttpResponse
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.email.views import NotifyActivateUserByEmail
from idhub.admin.forms import (
ProfileForm,
MembershipForm,
RolForm,
ServiceForm,
UserRolForm
from idhub.admin.forms import ImportForm, SchemaForm
from idhub.models import (
DID,
File_datas,
Membership,
Rol,
Service,
Schemas,
UserRol,
VerificableCredential,
)
@ -42,9 +55,9 @@ class Credentials(AdminView, TemplateView):
section = "Credentials"
class Schemes(AdminView, TemplateView):
title = _("Schemes Management")
section = "Schemes"
class SchemasMix(AdminView, TemplateView):
title = _("Templates Management")
section = "Templates"
class ImportExport(AdminView, TemplateView):
@ -118,8 +131,7 @@ class AdminPeopleDeleteView(AdminPeopleView):
class AdminPeopleEditView(AdminPeopleView, UpdateView):
template_name = "idhub/admin/user_edit.html"
from_class = ProfileForm
fields = ('first_name', 'last_name', 'email', 'username')
fields = ('first_name', 'last_name', 'email')
success_url = reverse_lazy('idhub:admin_people_list')
@ -128,8 +140,7 @@ class AdminPeopleRegisterView(NotifyActivateUserByEmail, People, CreateView):
subtitle = _('People Register')
icon = 'bi bi-person'
model = User
from_class = ProfileForm
fields = ('first_name', 'last_name', 'email', 'username')
fields = ('first_name', 'last_name', 'email')
success_url = reverse_lazy('idhub:admin_people_list')
def get_success_url(self):
@ -155,7 +166,6 @@ class AdminPeopleMembershipRegisterView(People, CreateView):
subtitle = _('People add membership')
icon = 'bi bi-person'
model = Membership
from_class = MembershipForm
fields = ('type', 'start_date', 'end_date')
success_url = reverse_lazy('idhub:admin_people_list')
@ -193,7 +203,6 @@ class AdminPeopleMembershipEditView(People, CreateView):
subtitle = _('People add membership')
icon = 'bi bi-person'
model = Membership
from_class = MembershipForm
fields = ('type', 'start_date', 'end_date')
success_url = reverse_lazy('idhub:admin_people_list')
@ -232,7 +241,6 @@ class AdminPeopleRolRegisterView(People, CreateView):
subtitle = _('Add Rol to User')
icon = 'bi bi-person'
model = UserRol
from_class = UserRolForm
fields = ('service',)
def get(self, request, *args, **kwargs):
@ -263,7 +271,6 @@ class AdminPeopleRolEditView(People, CreateView):
subtitle = _('Edit Rol to User')
icon = 'bi bi-person'
model = UserRol
from_class = UserRolForm
fields = ('service',)
def get_form_kwargs(self):
@ -311,7 +318,6 @@ class AdminRolRegisterView(AccessControl, CreateView):
subtitle = _('Add Rol')
icon = ''
model = Rol
from_class = RolForm
fields = ('name',)
success_url = reverse_lazy('idhub:admin_roles')
object = None
@ -322,7 +328,6 @@ class AdminRolEditView(AccessControl, CreateView):
subtitle = _('Edit Rol')
icon = ''
model = Rol
from_class = RolForm
fields = ('name',)
success_url = reverse_lazy('idhub:admin_roles')
@ -362,7 +367,6 @@ class AdminServiceRegisterView(AccessControl, CreateView):
subtitle = _('Add Service')
icon = ''
model = Service
from_class = ServiceForm
fields = ('domain', 'description', 'rol')
success_url = reverse_lazy('idhub:admin_services')
object = None
@ -373,7 +377,6 @@ class AdminServiceEditView(AccessControl, CreateView):
subtitle = _('Edit Service')
icon = ''
model = Service
from_class = ServiceForm
fields = ('domain', 'description', 'rol')
success_url = reverse_lazy('idhub:admin_services')
@ -401,11 +404,31 @@ class AdminCredentialsView(Credentials):
subtitle = _('Credentials list')
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"
subtitle = _('Issuance of Credentials')
subtitle = _('Change status of Credential')
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):
@ -414,12 +437,89 @@ class AdminRevokeCredentialsView(Credentials):
icon = ''
class AdminWalletIdentitiesView(Credentials):
template_name = "idhub/admin/wallet_identities.html"
class AdminDidsView(Credentials):
template_name = "idhub/admin/dids.html"
subtitle = _('Organization Identities (DID)')
icon = 'bi bi-patch-check-fill'
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):
template_name = "idhub/admin/wallet_credentials.html"
@ -435,22 +535,136 @@ class AdminWalletConfigIssuesView(Credentials):
wallet = True
class AdminSchemesView(Schemes):
template_name = "idhub/admin/schemes.html"
subtitle = _('Schemes List')
class AdminSchemasView(SchemasMix):
template_name = "idhub/admin/schemas.html"
subtitle = _('Template List')
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"
subtitle = _('Import Schemes')
class AdminSchemasDeleteView(SchemasMix):
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 = ''
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context.update({
'schemas': self.get_schemas(),
})
return context
class AdminSchemesExportView(Schemes):
template_name = "idhub/admin/schemes_export.html"
subtitle = _('Export Schemes')
icon = ''
def get_schemas(self):
schemas_files = os.listdir(settings.SCHEMAS_DIR)
schemas = [x for x in schemas_files
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):
@ -458,8 +672,114 @@ class AdminImportView(ImportExport):
subtitle = _('Import')
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"
subtitle = _('Export')
class AdminImportStep2View(ImportExport):
template_name = "idhub/admin/import_step2.html"
subtitle = _('Import')
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.db import migrations, models
@ -14,115 +14,247 @@ class Migration(migrations.Migration):
operations = [
migrations.CreateModel(
name="VCTemplate",
name='File_datas',
fields=[
(
"id",
'id',
models.BigAutoField(
auto_created=True,
primary_key=True,
serialize=False,
verbose_name="ID",
verbose_name='ID',
),
),
("wkit_template_id", models.CharField(max_length=250)),
("data", models.TextField()),
('file_name', models.CharField(max_length=250)),
('success', models.BooleanField(default=True)),
('created_at', models.DateTimeField(auto_now=True)),
],
),
migrations.CreateModel(
name="VerifiableCredential",
name='Organization',
fields=[
(
"id",
'id',
models.BigAutoField(
auto_created=True,
primary_key=True,
serialize=False,
verbose_name="ID",
verbose_name='ID',
),
),
("id_string", 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()),
('name', models.CharField(max_length=250)),
(
"user",
models.ForeignKey(
on_delete=django.db.models.deletion.CASCADE,
related_name="vcredentials",
to=settings.AUTH_USER_MODEL,
'url',
models.CharField(
help_text='Url where to send the presentation', max_length=250
),
),
],
),
migrations.CreateModel(
name="Membership",
name='Rol',
fields=[
(
"id",
'id',
models.BigAutoField(
auto_created=True,
primary_key=True,
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(
choices=[(1, "Beneficiary"), (2, "Employee"), (3, "Partner")],
verbose_name="Type of membership",
choices=[
(1, 'Enabled'),
(2, 'Issued'),
(3, 'Revoked'),
(4, 'Expired'),
],
default=1,
),
),
(
"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",
'user',
models.ForeignKey(
on_delete=django.db.models.deletion.CASCADE,
related_name="memberships",
related_name='vcredentials',
to=settings.AUTH_USER_MODEL,
),
),
],
),
migrations.CreateModel(
name="DID",
name='UserRol',
fields=[
(
"id",
'id',
models.BigAutoField(
auto_created=True,
primary_key=True,
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(
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,
),
),

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):
def get(self, request, *args, **kwargs):
if not request.user.is_superuser:
if not request.user.is_admin:
url = reverse_lazy('idhub:user_dashboard')
return redirect(url)

View File

@ -1,15 +1,8 @@
import json
import requests
from django.db import models
from django.utils.translation import gettext_lazy as _
from django.contrib.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
from idhub_auth.models import User
# class Event(models.Model):
@ -20,35 +13,103 @@ from django.contrib.auth.models import User
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)
user = models.ForeignKey(
User,
on_delete=models.CASCADE,
related_name='dids',
null=True,
)
# 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)
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_subject = models.CharField(max_length=250)
data = models.TextField()
status = models.PositiveSmallIntegerField(
choices=Status.choices,
default=Status.ENABLED
)
user = models.ForeignKey(
User,
on_delete=models.CASCADE,
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):
wkit_template_id = models.CharField(max_length=250)
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):
"""
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()])
def __str__(self):
return "{} -> {}".format(self.domain, self.rol.name)
return "{} -> {}".format(self.domain, self.get_roles())
class UserRol(models.Model):
@ -114,3 +175,18 @@ class UserRol(models.Model):
on_delete=models.CASCADE,
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>
{{ 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"><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 %}

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>
{{ 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 '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 %}

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 %}
{% block content %}
<div class="row">
<div class="col">
<h3>
<i class="{{ icon }}"></i>
{{ subtitle }}
</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 %}

View File

@ -12,7 +12,7 @@
<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-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 'Role' %}</button></th>
<th scope="col"></th>
@ -23,7 +23,7 @@
<tr>
<td>{{ user.last_name }}</td>
<td>{{ user.first_name }}</td>
<td>{{ user.username }}</td>
<td>{{ user.email }}</td>
<td>
{% for m in user.memberships.all %}
{{ 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-content">
<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>
</div>
<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>
<ul class="flex-column mb-2 ul_sidebar">
<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)
</a>
</li>
@ -110,8 +110,8 @@
</a>
</li>
<li class="nav-item">
<a class="nav-link {% if path == 'user_credentials_required' %}active2{% endif %}" href="{% url 'idhub:user_credentials_required' %}">
Credentials required
<a class="nav-link {% if path == 'user_credentials_request' %}active2{% endif %}" href="{% url 'idhub:user_credentials_request' %}">
Credentials request
</a>
</li>
<li class="nav-item">
@ -144,10 +144,6 @@
</div>
</div>
<h3>
<i class="{{ icon }}"></i>
{{ subtitle }}
</h3>
{% block content %}
{% endblock content %}

View File

@ -117,23 +117,13 @@
Credentials list
</a>
</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">
<a id="wallet" class="nav-link" data-bs-toggle="collapse" data-bs-target="#lwallet" aria-expanded="false" aria-controls="lwallet" href="javascript:void()">
Wallet
</a>
<ul class="flex-column mb-2 accordion-collapse {% if wallet %}expanded{% else %}collapse{% endif %}" id="lwallet" data-bs-parent="#wallet">
<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)
</a>
</li>
@ -152,45 +142,16 @@
</ul>
</li>
<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>
Schemes
</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
Templates
</a>
</li>
<li class="nav-item">
<a class="nav-link{% if path == 'admin_schemes_import' %} active2{% endif %}" href="{% url 'idhub:admin_schemes_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()">
<a class="admin nav-link {% if section == 'ImportExport' %}active {% endif %}fw-bold" href="{% url 'idhub:admin_import' %}">
<i class="bi bi-arrow-down-square icon_sidebar"></i>
Imports/Exports
Import Datas
</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>
</ul>
</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 %}
{% 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 %}

View File

@ -2,4 +2,33 @@
{% 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 'Send' %}" />
</div>
</form>
{% 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 %}
{% block content %}
<h3>
<i class="{{ icon }}"></i>
{{ subtitle }}
</h3>
<div class="table-responsive">
<table class="table table-striped table-sm">
<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 %}
{% block content %}
<h3>
<i class="{{ icon }}"></i>
{{ subtitle }}
</h3>
{% endblock %}

View File

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

View File

@ -2,6 +2,18 @@
{% load i18n %}
{% 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 %}
<form role="form" method="post">
{% csrf_token %}
@ -25,4 +37,36 @@
</div>
</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 %}

View File

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

View File

@ -67,13 +67,23 @@ urlpatterns = [
name='user_roles'),
path('user/gdpr/', views_user.UserGDPRView.as_view(),
name='user_gdpr'),
path('user/identities/', views_user.UserIdentitiesView.as_view(),
name='user_identities'),
path('user/identities/', views_user.UserDidsView.as_view(),
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(),
name='user_credentials'),
path('user/credentials_required/',
views_user.UserCredentialsRequiredView.as_view(),
name='user_credentials_required'),
path('user/credentials/<int:pk>', views_user.UserCredentialView.as_view(),
name='user_credential'),
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/',
views_user.UserCredentialsPresentationView.as_view(),
name='user_credentials_presentation'),
@ -123,26 +133,40 @@ urlpatterns = [
name='admin_service_del'),
path('admin/credentials/', views_admin.AdminCredentialsView.as_view(),
name='admin_credentials'),
path('admin/credentials/new/', views_admin.AdminIssueCredentialsView.as_view(),
name='admin_credentials_new'),
path('admin/credentials/<int:pk>/', views_admin.AdminCredentialView.as_view(),
name='admin_credential'),
path('admin/credentials/revoke/', views_admin.AdminRevokeCredentialsView.as_view(),
name='admin_credentials_revoke'),
path('admin/wallet/identities/', views_admin.AdminWalletIdentitiesView.as_view(),
name='admin_wallet_identities'),
path('admin/wallet/identities/', views_admin.AdminDidsView.as_view(),
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(),
name='admin_wallet_credentials'),
path('admin/wallet/config/issue/', views_admin.AdminWalletConfigIssuesView.as_view(),
name='admin_wallet_config_issue'),
path('admin/wallet/config/issue/', views_admin.AdminWalletConfigIssuesView.as_view(),
name='admin_wallet_config_issue'),
path('admin/schemes/', views_admin.AdminSchemesView.as_view(),
name='admin_schemes'),
path('admin/schemes/import', views_admin.AdminSchemesImportView.as_view(),
name='admin_schemes_import'),
path('admin/schemes/export/', views_admin.AdminSchemesExportView.as_view(),
name='admin_schemes_export'),
path('admin/schemas/', views_admin.AdminSchemasView.as_view(),
name='admin_schemas'),
path('admin/schemas/<int:pk>/del/', views_admin.AdminSchemasDeleteView.as_view(),
name='admin_schemas_del'),
path('admin/schemas/<int:pk>/', views_admin.AdminSchemasDownloadView.as_view(),
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(),
name='admin_import'),
path('admin/export/', views_admin.AdminExportView.as_view(),
name='admin_export'),
path('admin/import/new', views_admin.AdminImportStep2View.as_view(),
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.contrib.auth.models import User
from idhub_auth.models import User
from idhub.models import DID, VerificableCredential, Organization
class ProfileForm(forms.ModelForm):
@ -8,3 +10,85 @@ class ProfileForm(forms.ModelForm):
class Meta:
model = User
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
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.shortcuts import get_object_or_404, redirect
from django.urls import reverse_lazy
from django.http import HttpResponse
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.models import DID, VerificableCredential
class MyProfile(UserView):
@ -14,7 +23,7 @@ class MyProfile(UserView):
section = "MyProfile"
class MyWallet(UserView, TemplateView):
class MyWallet(UserView):
title = _("My Wallet")
section = "MyWallet"
@ -51,25 +60,178 @@ class UserGDPRView(MyProfile, TemplateView):
icon = 'bi bi-file-earmark-medical'
class UserIdentitiesView(MyWallet):
template_name = "idhub/user/identities.html"
subtitle = _('Identities (DID)')
icon = 'bi bi-patch-check-fill'
class UserCredentialsView(MyWallet):
class UserCredentialsView(MyWallet, TemplateView):
template_name = "idhub/user/credentials.html"
subtitle = _('Credentials')
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"
subtitle = _('Credentials required')
class UserCredentialView(MyWallet, TemplateView):
template_name = "idhub/user/credential.html"
subtitle = _('Credential')
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"
subtitle = _('Credentials Presentation')
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
black==23.9.1
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_extensions',
'django_bootstrap5',
'idhub_auth',
'idhub'
]
@ -160,6 +161,7 @@ MEDIA_URL = '/media/'
STATIC_ROOT = config('STATIC_ROOT')
MEDIA_ROOT = config('MEDIA_ROOT', default="idhub/upload")
FIXTURE_DIRS = (os.path.join(BASE_DIR, 'fixtures'),)
SCHEMAS_DIR = os.path.join(BASE_DIR, 'schemas')
# Default primary key field type
# https://docs.djangoproject.com/en/4.2/ref/settings/#default-auto-field
@ -176,3 +178,4 @@ MESSAGE_TAGS = {
messages.ERROR: 'alert-danger',
}
AUTH_USER_MODEL = 'idhub_auth.User'