Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions examples/Readme.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
# Issuance Preview Example

## Preview

python -m tools.issuance_preview.learning_tokens_issuance.main \
preview \
--payload examples/talent-angels-moodle.json \
--policy examples/policy.json \
--pretty
26 changes: 26 additions & 0 deletions examples/policy.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
{
"courseId": "1001",
"wallets": {
"21": "0x1111111111111111111111111111111111111111"
},
"tokens": [
{
"id": "attendance-submitted",
"tokenType": "attendance",
"amount": 1,
"condition": {
"field": "submission.workflow_state",
"equals": "submitted"
}
},
{
"id": "score-above-80",
"tokenType": "score",
"amount": 10,
"condition": {
"field": "grade.percentage",
"gte": 80
}
}
]
}
79 changes: 79 additions & 0 deletions examples/talent-angels-moodle.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
{
"source": {
"lms": "moodle",
"rawCourseId": "1001",
"fetchedAt": "2025-10-10T12:47:09.057Z"
},
"institution": {
"id": "55"
},
"course": {
"id": "1001",
"name": "Moodle 101",
"startDate": "2025-02-01T00:00:00.000Z",
"endDate": "2025-06-01T00:00:00.000Z",
"metadata": {}
},
"instructors": [
{
"instructor_id": "11",
"instructor_email": "teacher@example.edu",
"instructor_name": "Dr Moodle",
"instructor_username": "teacher@example.edu"
}
],
"learners": [
{
"id": "21",
"email": "studentA@example.edu",
"name": "Student A",
"username": "studentA@example.edu",
"assignments": [
{
"id": "500",
"type": "assign",
"title": "Knowledge graphs pathfinder project",
"maxScore": 50,
"is_quiz_assignment": false,
"subsection_name": "General",
"submissions": [
{
"submitted_at": "2025-03-01T12:00:00.000Z",
"workflow_state": "submitted",
"grades": [
{
"score": 45,
"totalscore": 50,
"percentage": "90.00"
}
]
}
]
}
]
}
],
"chat": [
{
"channel": "forum",
"messages": [
{
"id": "9001",
"from": "21",
"text": "I need help",
"ts": "2025-03-02T08:30:00.000Z"
}
]
}
],
"diagnostics": {
"missingEmailCount": 0,
"notes": [],
"activities": {
"total": 1,
"withSubmissions": 1,
"submissionsTotal": 1
}
},
"transcript": []
}
86 changes: 86 additions & 0 deletions tools/issuance_preview/Readme.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
# Learning Tokens Python tools: issuance preview

This directory contains a dependency-free Python feature for the Learning Tokens repository: an **issuance preview** engine that turns a normalized LMS payload from `npm_package ltsdk` into deterministic Learning Token issuance candidates before any blockchain mint or transfer.

## Package layout

```text
tools/issuance_preview/
├── learning_tokens_issuance/
│ ├── preview.py # issuance preview engine and CLI
│ └── __init__.py
└── tests/
└── test_preview.py
```

## Issuance policy format

A policy contains the target course, optional learner wallet mappings, and token rules. Each rule describes a token type, an amount, optional assignment filters, and a condition over normalized LMS evidence.

```json
{
"courseId": "1001",
"wallets": {
"21": "0x1111111111111111111111111111111111111111"
},
"tokens": [
{
"id": "attendance-submitted",
"tokenType": "attendance",
"amount": 1,
"condition": {
"field": "submission.workflow_state",
"equals": "submitted"
}
},
{
"id": "score-above-80",
"tokenType": "score",
"amount": 10,
"condition": {
"field": "grade.percentage",
"gte": 80
}
}
]
}
```

Conditions support `equals`, `notEquals`, `in`, `gt`, `gte`, `lt`, `lte`, `exists`, and nested `all` / `any` groups. Field paths are evaluated against `course`, `learner`, `assignment`, `submission`, and `grade` records from the normalized payload.

## CLI examples

### Preview Learning Token issuance

```bash
python3 -m tools.issuance_preview.learning_tokens_issuance preview \
--payload npm_package\ ltsdk/tests/fixtures/moodle-normalized.json \
--policy /path/to/policy.json \
--pretty
```

The previous top-level form is still supported for compatibility:

```bash
python3 -m tools.issuance_preview.learning_tokens_issuance \
--payload npm_package\ ltsdk/tests/fixtures/moodle-normalized.json \
--policy /path/to/policy.json \
--pretty
```

## Python API

```python
from tools.issuance_preview.learning_tokens_issuance import build_preview

payload = {...} # normalized LMS payload from LTSDK
policy = {...} # scoring-guide-style token rules

print(build_preview(payload, policy))
```

## Test

```bash
python3 -m unittest discover -s tools/issuance_preview/tests
```
Empty file.
9 changes: 9 additions & 0 deletions tools/issuance_preview/learning_tokens_issuance/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
"""Learning Tokens Python helpers for issuance previews."""

from .preview import build_preview, load_json, main

__all__ = [
"build_preview",
"load_json",
"main",
]
4 changes: 4 additions & 0 deletions tools/issuance_preview/learning_tokens_issuance/main.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
from .preview import main

if __name__ == "__main__":
raise SystemExit(main())
Loading