Merge pull request 'new_credtools' (#127) from new_credtools into main

Reviewed-on: https://gitea.pangea.org/trustchain-oc1-orchestral/IdHub/pulls/127
This commit is contained in:
cayop 2024-02-12 11:18:41 +00:00
commit 73d015ddab
11 changed files with 236 additions and 122 deletions

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View file

@ -46,7 +46,7 @@
class="btn btn-primary form-control" id="submit-id-submit"> class="btn btn-primary form-control" id="submit-id-submit">
</div> </div>
</form> </form>
<div id="login-footer" class="mt-3"> <div id="login-footer" class="mt-3 d-none">
<a href="{% url 'idhub:password_reset' %}" data-toggle="modal" data-target="#forgotPasswordModal">{% trans "Forgot your password? Click here to recover" %}</a> <a href="{% url 'idhub:password_reset' %}" data-toggle="modal" data-target="#forgotPasswordModal">{% trans "Forgot your password? Click here to recover" %}</a>
</div> </div>
{% endblock %} {% endblock %}

View file

@ -66,7 +66,7 @@
<form role="form" method="post"> <form role="form" method="post">
{% csrf_token %} {% csrf_token %}
<div class="row"> <div class="row">
<div class="col-sm-4"> <div class="col">
{% bootstrap_form form %} {% bootstrap_form form %}
</div> </div>
</div> </div>

View file

@ -66,7 +66,7 @@
<form role="form" method="post"> <form role="form" method="post">
{% csrf_token %} {% csrf_token %}
<div class="row"> <div class="row">
<div class="col-sm-4"> <div class="col">
{% bootstrap_form form %} {% bootstrap_form form %}
</div> </div>
</div> </div>

View file

@ -28,4 +28,5 @@ fontTools==4.47.0
weasyprint==60.2 weasyprint==60.2
ujson==5.9.0 ujson==5.9.0
openpyxl==3.1.2 openpyxl==3.1.2
jsonpath_ng==1.6.1
./didkit-0.3.2-cp311-cp311-manylinux_2_34_x86_64.whl ./didkit-0.3.2-cp311-cp311-manylinux_2_34_x86_64.whl

View file

@ -1,15 +1,17 @@
import pandas as pd
import json import json
#import jsonld # import jsonld
import csv import csv
import sys import sys
import jsonschema import jsonschema
from pyld import jsonld # from jsonschema import validate, ValidationError
#from jsonschema import validate, ValidationError
import requests import requests
from pyld import jsonld from pyld import jsonld
import jsonref import jsonref
from jsonpath_ng import jsonpath, parse
#def remove_null_values(dictionary):
# def remove_null_values(dictionary):
# return {k: v for k, v in dictionary.items() if v is not None} # return {k: v for k, v in dictionary.items() if v is not None}
def _remove_null_values(dictionary): def _remove_null_values(dictionary):
@ -17,6 +19,7 @@ def _remove_null_values(dictionary):
dictionary.clear() dictionary.clear()
dictionary.update(filtered) dictionary.update(filtered)
def validate_context(jsld): def validate_context(jsld):
"""Validate a @context string through expanding""" """Validate a @context string through expanding"""
context = jsld["@context"] context = jsld["@context"]
@ -30,6 +33,7 @@ def validate_context(jsld):
return False return False
return True return True
def compact_js(doc, context): def compact_js(doc, context):
"""Validate a @context string through compacting, returns compacted context""" """Validate a @context string through compacting, returns compacted context"""
try: try:
@ -40,6 +44,7 @@ def compact_js(doc, context):
return None return None
return compacted return compacted
def dereference_context_file(json_file): def dereference_context_file(json_file):
"""Dereference and return json-ld context from file""" """Dereference and return json-ld context from file"""
json_text = open(json_file).read() json_text = open(json_file).read()
@ -76,22 +81,36 @@ def dereference_context(jsonld_dict):
def validate_schema_file(json_schema_file): def validate_schema_file(json_schema_file):
"""Validate standalone schema from file""" """Validate standalone schema from file"""
try: try:
json_schema = open(json_schema_file).read() json_schema = json.loads(open(json_schema_file).read())
validate_schema(json_schema) validate_schema(json_schema)
except Exception as e: except Exception as e:
print(f"Error loading file {json_schema_file} or validating schema {json_schema}: {e}") print(f"Error loading file {json_schema_file} or validating schema {json_schema}: {e}")
return False return False
return True return True
def validate_schema(json_schema): def validate_schema(json_schema):
"""Validate standalone schema, returns bool (uses Draft202012Validator, alt: Draft7Validator, alt: Draft4Validator, Draft6Validator )""" """Validate standalone schema, returns bool (uses Draft202012Validator, alt: Draft7Validator, alt: Draft4Validator, Draft6Validator )"""
try: try:
jsonschema.validators.Draft202012Validator.check_schema(json_schema) jsonschema.validators.Draft202012Validator.check_schema(json_schema)
# jsonschema.validators.Draft7Validator.check_schema(json_schema) # jsonschema.validators.Draft7Validator.check_schema(json_schema)
return True
except jsonschema.exceptions.SchemaError as e: except jsonschema.exceptions.SchemaError as e:
print(e) print(e)
return False return False
return True
def validate_json_file(json_data_file, json_schema_file):
"""Validate standalone schema from file"""
try:
json_data = json.loads(open(json_data_file).read())
json_schema = json.loads(open(json_schema_file).read())
validate_json(json_data, json_schema)
except Exception as e:
print(f"Error loading file {json_schema_file} or {json_data_file}: {e}")
return False
return True
def validate_json(json_data, json_schema): def validate_json(json_data, json_schema):
"""Validate json string basic (no format) with schema, returns bool""" """Validate json string basic (no format) with schema, returns bool"""
@ -100,8 +119,10 @@ def validate_json(json_data, json_schema):
except jsonschema.exceptions.ValidationError as err: except jsonschema.exceptions.ValidationError as err:
print('Validation error: ', json_data, '\n') print('Validation error: ', json_data, '\n')
return False return False
print("Successful validation")
return True return True
def validate_json_format(json_data, json_schema): def validate_json_format(json_data, json_schema):
"""Validate a json string basic (including format) with schema, returns bool""" """Validate a json string basic (including format) with schema, returns bool"""
try: try:
@ -111,9 +132,29 @@ def validate_json_format(json_data, json_schema):
return False return False
return True return True
def schema_to_csv_file(sch_f, csv_f):
try:
json_schema = json.loads(open(sch_f).read())
except Exception as e:
print(f"Error loading file {sch_f}: {e}\nSchema:\n{json_schema}.")
return False
schema_to_csv(json_schema, csv_f)
return True
def schema_to_csv(schema, csv_file_path): def schema_to_csv(schema, csv_file_path):
"""Extract headers from an schema and write to file, returns bool""" """Extract headers from an schema and write to file, returns bool"""
headers = list(schema['properties'].keys()) jsonpath_expr = parse('$..credentialSubject.properties')
# Use the JSONPath expression to select all properties under 'credentialSubject.properties'
matches = [match.value for match in jsonpath_expr.find(schema)]
# Get the keys of the matched objects
# headers = [match.keys() for match in matches]
# Use the JSONPath expression to select all properties under 'credentialSubject.properties'
# Get the keys of the matched objects
headers = [key for match in matches for key in match.keys()]
# print('\nHeaders: ', headers)
# Create a CSV file with the headers # Create a CSV file with the headers
with open(csv_file_path, 'w', newline='') as csv_file: with open(csv_file_path, 'w', newline='') as csv_file:
@ -121,6 +162,70 @@ def schema_to_csv(schema, csv_file_path):
writer.writerow(headers) writer.writerow(headers)
return True return True
def schema_to_xls_basic(schema, xls_file_path):
"""Extract headers from an schema and write to file, returns bool"""
jsonpath_expr = parse('$..credentialSubject.properties')
# Use the JSONPath expression to select all properties under 'credentialSubject.properties'
matches = [match.value for match in jsonpath_expr.find(schema)]
# Get the keys of the matched objects
# headers = [match.keys() for match in matches]
# Get the keys of the matched objects
headers = [key for match in matches for key in match.keys() if key != 'id']
# Create a DataFrame with the fields as columns
df = pd.DataFrame(columns=headers)
# Save the DataFrame as an Excel file
# df.to_excel(xls_file_path, index=False)
df.to_excel(xls_file_path, index=False, engine='openpyxl') # For .xlsx files, and pip install openpyxl
return True
def schema_to_xls_comment(schema, xls_file_path):
"""Extract headers from an schema and write to file, returns bool"""
jsonpath_expr = parse('$..credentialSubject.properties')
# Use the JSONPath expression to select all properties under 'credentialSubject.properties'
matches = [match.value for match in jsonpath_expr.find(schema)]
# Get the keys of the matched objects
# headers = [match.keys() for match in matches]
# Get the keys of the matched objects
headers = [key for match in matches for key in match.keys() if key != 'id']
jsonpath_expr_req = parse('$..credentialSubject.required')
req = [match.value for match in jsonpath_expr_req.find(schema)][0]
# Create a DataFrame with the fields as columns
df = pd.DataFrame(columns=headers)
writer = pd.ExcelWriter(xls_file_path, engine='xlsxwriter')
# Convert the dataframe to an xlsxwriter Excel object
df.to_excel(writer, sheet_name='Full1', index=False)
# Get the xlsxwriter workbook and worksheet objects
workbook = writer.book
worksheet = writer.sheets['Full1']
# Define a format for the required header cells
req_format = workbook.add_format({'border': 1})
# cell_format = workbook.add_format({'bold': True, 'font_color': 'red'})
# Write comments to the cells
for i, header in enumerate(headers):
if header in req:
worksheet.set_column(i,i, None, req_format)
# Get the description for the current field
if 'description' in matches[0][header]:
description = matches[0][header]['description']
if description is not None:
# Write the description as a comment to the corresponding cell
worksheet.write_comment(0, i, description)
# Close the Pandas Excel writer and output the Excel file
worksheet.autofit()
writer.close()
return True
def csv_to_json(csvFilePath, schema, jsonFilePath): def csv_to_json(csvFilePath, schema, jsonFilePath):
"""Read from a csv file, check schema, write to json file, returns bool""" """Read from a csv file, check schema, write to json file, returns bool"""
@ -144,6 +249,7 @@ def csv_to_json(csvFilePath, schema, jsonFilePath):
jsonf.write(jsonString) jsonf.write(jsonString)
return True return True
def csv_to_json2(csv_file_path, json_file_path): def csv_to_json2(csv_file_path, json_file_path):
"""Read from a csv file, write to json file (assumes a row 'No' is primary key), returns bool EXPERIMENT""" """Read from a csv file, write to json file (assumes a row 'No' is primary key), returns bool EXPERIMENT"""
# Create a dictionary # Create a dictionary
@ -164,11 +270,18 @@ def csv_to_json2(csv_file_path, json_file_path):
jsonf.write(json.dumps(data, indent=4)) jsonf.write(json.dumps(data, indent=4))
return True return True
if __name__ == "__main__": if __name__ == "__main__":
sch_name = sys.argv[1] # sch_name = sys.argv[1]
sch_file = sch_name + '-schema.json' schemas = sys.argv[1:]
sch = json.loads(open(sch_file).read())
if validate_json(d, sch): # credtools.py course-credential device-purchase e-operator-claim federation-membership financial-vulnerability membership-card
generate_csv_from_schema(sch, sch_name + '-template.csv') #sch_name = 'e-operator-claim'
for i, schema in enumerate(schemas):
print(schema)
sch = json.loads(open('vc_schemas/' + schema + '.json').read())
if schema_to_xls_comment(sch,'vc_excel/' + schema + '.xlsx'):
print('Success')
else: else:
print("Validation error: ", sch_name) print("Validation error: ", schema)