Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature/seed richer badges #162

Closed
wants to merge 11 commits into from
Closed
14 changes: 8 additions & 6 deletions apps/mainsite/management/commands/seed.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import traceback
import sys
from os import listdir, environ
from os.path import dirname, basename, isfile, join
from django.utils import timezone
Expand All @@ -20,8 +21,9 @@ def add_arguments(self, parser):

def handle(self, *args, **options):
if settings.ALLOW_SEEDS:
# if options['clean']:
clear_data()
if options['clean']:
clear_data()

run_seeds()
if options['add_assertions']:
nr_of_assertions = options['add_assertions']
Expand Down Expand Up @@ -65,10 +67,10 @@ def run_seeds():
__import__("mainsite.seeds." + seed)
print("\033[92mdone!\033[0m")
except Exception as e:
print("\033[91mFAILED!\033[0m")
print(traceback.format_exc())
print(e)
break
sys.stderr.write("\033[91mFAILED!\033[0m")
sys.stderr.write(traceback.format_exc())
sys.stderr.write(f"{str(e)}\n")
sys.exit(1)


def run_scaled_seed(scale):
Expand Down
8 changes: 5 additions & 3 deletions apps/mainsite/management/commands/setup_seed.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import traceback
import sys

from django.core.management.base import BaseCommand
from django.db import connection
Expand All @@ -24,9 +25,10 @@ def handle(self, *args, **options):
__import__("mainsite.seeds.01_setup")
print("\033[92mdone!\033[0m")
except Exception as e:
print("\033[91mFAILED!\033[0m")
print(traceback.format_exc())
print(e)
sys.stderr.write("\033[91mFAILED!\033[0m")
sys.stderr.write(traceback.format_exc())
sys.stderr.write(f"{str(e)}\n")
sys.exit(1)
else:
print("Skipping setup seeds... ", end="")

Expand Down
3 changes: 3 additions & 0 deletions apps/mainsite/seeds/01_setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,11 @@


setattr(settings, 'SUPPRESS_EMAILS', 1)
badgr_app_id = getattr(settings, 'BADGR_APP_ID')


main_badgr_app, _ = BadgrApp.objects.get_or_create(
id=badgr_app_id,
is_active=1,
cors=settings.UI_URL,
email_confirmation_redirect="{}/login/".format(settings.UI_URL),
Expand Down
34 changes: 26 additions & 8 deletions apps/mainsite/seeds/02_users.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,10 @@
from allauth.account.models import EmailAddress
from allauth.socialaccount.models import SocialAccount

from badgeuser.models import BadgeUser, TermsAgreement
from badgeuser.models import BadgeUser, TermsAgreement, StudentAffiliation
from institution.models import Institution
from mainsite.seeds.constants import ENROLLED_STUDENT_EMAIL, REVOKED_STUDENT_EMAIL, INSTITUTION_UNIVERSITY_EXAMPLE_ORG, \
AWARDED_STUDENT_EMAIL
AWARDED_STUDENT_EMAIL, DEMO_STUDENT_EMAIL, DEMO_STUDENT_EPPN
from staff.models import InstitutionStaff
from .util import add_terms_institution

Expand Down Expand Up @@ -234,19 +234,23 @@ def create_teacher(username, email, first_name, last_name, institution_name, uid
[create_teacher(**t) for t in teachers]

# Users - Students
extra_data = json.dumps({"eduid": str(uuid.uuid4())})
default_extra_data = {"eduid": str(uuid.uuid4())}


def create_student(username, first_name, last_name, email, uid):
def create_student(username, first_name, last_name, email, uid, **kwargs):
user, _ = BadgeUser.objects.get_or_create(username=username, email=email, first_name=first_name,
last_name=last_name, validated_name=f"{first_name} {last_name}")
accept_terms(user)

EmailAddress.objects.get_or_create(verified=1, primary=1, email=email, user=user)
social_account, _ = SocialAccount.objects.get_or_create(provider='edu_id', uid=uid, user=user)
social_account.extra_data = extra_data
social_account.save()

extra_data = default_extra_data | kwargs.get("extra_data", {})
social_account.extra_data = json.dumps(extra_data)

if kwargs and kwargs.get("affiliation"):
StudentAffiliation.objects.get_or_create(user=user, **kwargs["affiliation"])

social_account.save()

students = [
{
Expand Down Expand Up @@ -276,7 +280,21 @@ def create_student(username, first_name, last_name, email, uid):
"last_name": "Doolittle",
"email": AWARDED_STUDENT_EMAIL,
"uid": "78b9ec1bb8731ec04b42137faf6a3c7068c89212"
}
},
{
"username": "petra",
"first_name": "Petra",
"last_name": "Penttilä",
"email": DEMO_STUDENT_EMAIL,
"uid": "fc4f39e6-b8b5-4af0-a5a1-43d9876503ea",
"affiliation": {
"schac_home": "university-example.org",
"eppn": DEMO_STUDENT_EPPN,
},
"extra_data": {
"eduid": "7bf2c4ae-f355-496d-8bc2-db550f1e2d7a"
}
},
]

[create_student(**s) for s in students]
58 changes: 56 additions & 2 deletions apps/mainsite/seeds/03_badgeclasses.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import json
from typing import List
from django.conf import settings
from institution.models import Institution, Faculty
from issuer.models import Issuer, BadgeClass, BadgeClassExtension
Expand Down Expand Up @@ -64,16 +65,33 @@
}
}

badge_class_description = "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat."
# add some markdown to the description, make it multiline.
badge_class_description = '''
# Introduction to Lorem Ipsum
Lorem ipsum dolor **sit amet**, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.

Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.

## Subtitle
Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur.

* Excepteur sint occaecat cupidatat non proident
* Sunt in culpa qui officia deserunt mollit anim id est laborum

### Subsubtitle

1. Lorem ipsum dolor sit amet
2. Consectetur adipiscing elit
3. Sed do eiusmod tempor incididunt ut labore et dolore magna aliqua
'''

def create_badge_class(name, issuer):
badge_class, _ = BadgeClass.objects.get_or_create(
name=name,
issuer=issuer,
description=badge_class_description,
formal=True,
criteria_text="A lot",
criteria_text="In order to earn this badge, you must complete the course and show proficiency in things.",
old_json="{}",
image="uploads/badges/eduid.png",
)
Expand Down Expand Up @@ -102,3 +120,39 @@ def create_badge_class(name, issuer):
for iss in Issuer.objects.filter(name_english="Medicine"):
[create_badge_class(bc, iss) for bc in
['Growth and Development', 'Circulation and Breathing', 'Regulation and Integration', 'Digestion and Defense']]

# Faculty Medicine ## Alignments
for bc in BadgeClass.objects.filter(issuer__name_english="Medicine"):
bc.alignment_items = [
{ "target_name": "EQF", "target_url": "https://ec.europa.eu/ploteus/content/descriptors-page", "target_description": "European Qualifications Framework", "target_framework": "EQF", "target_code": "7" },
{ "target_name": "ECTS", "target_url": "https://ec.europa.eu/education/resources-and-tools/european-credit-transfer-and-accumulation-system-ects_en", "target_description": "European Credit Transfer and Accumulation System", "target_framework": "ECTS", "target_code": "2.5" },
]
bc.save()

# Add quality assurance to half of the badges
for bc in BadgeClass.objects.all()[::2]:
bc.quality_assurance_description = "Quality assurance framework FAKE1.0"
bc.quality_assurance_name = "FAKE1.0"
bc.quality_assurance_url = "https://example.com/qaf/FAKE1.0"
bc.save()

# Add assessment_type to half of the badges
iterator = 0
assessment_types: List[str] = ["testing", "application of a skill", "portfolio", "recognition of prior learning"]
n_types = len(assessment_types)
for bc in BadgeClass.objects.all()[::2]:
bc.assessment_type = assessment_types[iterator % n_types]
bc.save()
iterator += 1

iterator = 0

# For half of the badges with assessment_type "testing", set assessment_supervised to True
for bc in BadgeClass.objects.filter(assessment_type="testing")[::2]:
bc.assessment_supervised = True
bc.save()

# for half of that are supervised, set identity_checked to True
for bc in BadgeClass.objects.exclude(assessment_supervised=False)[::2]:
bc.identity_checked = True
bc.save()
22 changes: 15 additions & 7 deletions apps/mainsite/seeds/04_badgeinstances.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
from mainsite.models import BadgrApp
from mainsite.seeds.constants import ENROLLED_STUDENT_EMAIL, BADGE_CLASS_INTRODUCTION_TO_PSYCHOLOGY, \
BADGE_CLASS_COGNITIVE_PSYCHOLOGY, BADGE_CLASS_GROUP_DYNAMICS, BADGE_CLASS_PSYCHOMETRICS, AWARDED_STUDENT_EMAIL, \
REVOKED_STUDENT_EMAIL
REVOKED_STUDENT_EMAIL, DEMO_STUDENT_EMAIL
from django.conf import settings

from badgeuser.models import BadgeUser
Expand All @@ -18,25 +18,33 @@
REVOKED_STUDENT_EMAIL

super_user = BadgeUser.objects.get(username=settings.SUPERUSER_NAME)
badgr_app = BadgrApp.objects.get(id=1)

badgr_app = BadgrApp.objects.get(id=getattr(settings, 'BADGR_APP_ID'))

def create_badge_instance(user, badge_class, revoked, acceptance="Unaccepted"):
badge_class.issue(recipient=user, created_by=super_user, allow_uppercase=True,
recipient_type=BadgeInstance.RECIPIENT_TYPE_EDUID, acceptance=acceptance, revoked=revoked,
send_email=False)


# Create enrollments


def create_enrollments_badge_instances(user, bc_names, revoked, acceptance="Unaccepted", include_badge_instances=True):
for bc_name in bc_names:
for bc in BadgeClass.objects.filter(name=bc_name):
StudentsEnrolled.objects.get_or_create(badge_class=bc, user=user)
if include_badge_instances:
create_badge_instance(user, bc, revoked, acceptance)

# Create enrollments
demo_user = BadgeUser.objects.filter(email=DEMO_STUDENT_EMAIL).first()
create_enrollments_badge_instances(demo_user,
[BADGE_CLASS_COGNITIVE_PSYCHOLOGY, BADGE_CLASS_INTRODUCTION_TO_PSYCHOLOGY],
False,
acceptance="Accepted",
include_badge_instances=True)
create_enrollments_badge_instances(demo_user,
[BADGE_CLASS_GROUP_DYNAMICS, BADGE_CLASS_PSYCHOMETRICS],
False,
acceptance="Unaccepted",
include_badge_instances=True)
create_badge_instance(demo_user, BadgeClass.objects.get(name=settings.EDUID_BADGE_CLASS_NAME), False, "Unaccepted")

enrolled_user = BadgeUser.objects.get(email=ENROLLED_STUDENT_EMAIL)
create_enrollments_badge_instances(enrolled_user,
Expand Down
2 changes: 2 additions & 0 deletions apps/mainsite/seeds/constants.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@
ENROLLED_STUDENT_EMAIL = "[email protected]"
REVOKED_STUDENT_EMAIL = "[email protected]"
AWARDED_STUDENT_EMAIL = "[email protected]"
DEMO_STUDENT_EMAIL = "[email protected]"
DEMO_STUDENT_EPPN = "[email protected]"
# Password1!

BADGE_CLASS_INTRODUCTION_TO_PSYCHOLOGY = 'Introduction to Psychology'
Expand Down
8 changes: 6 additions & 2 deletions docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,7 @@ services:
- EMAIL_HOST=mailhog
- EMAIL_PORT=1025
- LTI_FRONTEND_URL=localhost
- MEMCACHED_HOST=memcached
- MEMCACHED_PORT=11211
- MEMCACHED=memcached:11211
- OIDC_RS_ENTITY_ID=test.edubadges.rs.nl
- OIDC_RS_SECRET=${OIDC_RS_SECRET}
- ROOT_INFO_SECRET_KEY=secret
Expand Down Expand Up @@ -77,6 +76,8 @@ services:
retries: 5
start_period: 30s
timeout: 10s
volumes:
- db-data:/var/lib/mysql
networks:
- edubadges-server

Expand All @@ -100,3 +101,6 @@ networks:
external: true
edubadges-server:
driver: bridge

volumes:
db-data:
4 changes: 1 addition & 3 deletions docker/entrypoint.sh
Original file line number Diff line number Diff line change
@@ -1,14 +1,12 @@
#!/bin/bash
set -e
set -x

# Run migrations
echo "Running migrations"
python ./manage.py migrate

# Reset (-c) and Seed the database
echo "Seeding the database"
python ./manage.py seed -c
python ./manage.py seed

# Run the server
echo "Starting the server"
Expand Down