From 09f5b9cd68bc7db7186e6d7a40899e4735fa588a Mon Sep 17 00:00:00 2001 From: John Baldwin Date: Wed, 23 Sep 2020 17:22:55 +0200 Subject: [PATCH] Added django-environ to support devsite multisite switching modes * Added django-environ to devsite settings.py in order to allow setting multisite versus standalone mode in the devsite/devsite/.env file * Updated the requirements files to add `django-environ` --- .gitignore | 1 + devsite/devsite/.env.example | 8 +++ devsite/devsite/seed.py | 65 +++++++++++++++++++-- devsite/devsite/settings.py | 22 ++++++- devsite/requirements/ginkgo.txt | 1 + devsite/requirements/hawthorn_community.txt | 1 + devsite/requirements/hawthorn_multisite.txt | 1 + 7 files changed, 92 insertions(+), 7 deletions(-) create mode 100644 devsite/devsite/.env.example diff --git a/.gitignore b/.gitignore index fbaf2392..06a54cfb 100644 --- a/.gitignore +++ b/.gitignore @@ -53,6 +53,7 @@ coverage.xml # Django stuff: *.log local_settings.py +devsite/devsite/.env # Flask stuff: instance/ diff --git a/devsite/devsite/.env.example b/devsite/devsite/.env.example new file mode 100644 index 00000000..20c3ed96 --- /dev/null +++ b/devsite/devsite/.env.example @@ -0,0 +1,8 @@ +# Figures devsite environment settings example file + +# Set to true to enable Figures multisite environment in devsite +FIGURES_IS_MULTISITE=true + +# Set synthetic data seed options +SEED_DAYS_BACK=60 +SEED_NUM_LEARNERS_PER_COURSE=25 diff --git a/devsite/devsite/seed.py b/devsite/devsite/seed.py index a70daf33..efff87e0 100644 --- a/devsite/devsite/seed.py +++ b/devsite/devsite/seed.py @@ -10,6 +10,7 @@ import faker import random +from django.conf import settings from django.contrib.auth import get_user_model from django.contrib.sites.models import Site from django.db.utils import IntegrityError @@ -19,28 +20,45 @@ from openedx.core.djangoapps.content.course_overviews.models import CourseOverview from student.models import CourseAccessRole, CourseEnrollment, UserProfile +from organizations.models import Organization, OrganizationCourse + from figures.compat import RELEASE_LINE, GeneratedCertificate from figures.models import ( CourseDailyMetrics, LearnerCourseGradeMetrics, SiteDailyMetrics, ) -from figures.helpers import as_course_key, as_datetime, days_from, prev_day +from figures.helpers import ( + as_course_key, + as_datetime, + days_from, + prev_day, + is_multisite, +) from figures.pipeline import course_daily_metrics as pipeline_cdm from figures.pipeline import site_daily_metrics as pipeline_sdm from devsite import cans +if is_multisite(): + # First trying this without capturing 'ImportError' + from organizations.models import UserOrganizationMapping + + FAKE = faker.Faker() LAST_DAY = days_from(datetime.datetime.now(), -2).replace(tzinfo=utc) -DAYS_BACK = 180 -NO_LEARNERS_PER_COURSE = 50 + +DAYS_BACK = settings.DEVSITE_SEED['DAYS_BACK'] +NUM_LEARNERS_PER_COURSE = settings.DEVSITE_SEED['NUM_LEARNERS_PER_COURSE'] # Quick and dirty debuging VERBOSE = False +FOO_ORG = 'FOO' + + def get_site(): """ In demo mode, we have just one site (for now) @@ -82,7 +100,7 @@ def seed_course_overviews(data=None): if not data: data = cans.COURSE_OVERVIEW_DATA # append with randomly generated course overviews to test pagination - new_courses = [generate_course_overview(i, org='FOO') for i in xrange(20)] + new_courses = [generate_course_overview(i, org=FOO_ORG) for i in xrange(20)] data += new_courses for rec in data: @@ -166,7 +184,7 @@ def seed_course_enrollments(): TODO: make the number of users variable """ for co in CourseOverview.objects.all(): - users = seed_users(cans.users.UserGenerator(NO_LEARNERS_PER_COURSE)) + users = seed_users(cans.users.UserGenerator(NUM_LEARNERS_PER_COURSE)) seed_course_enrollments_for_course(co.id, users, DAYS_BACK) @@ -318,7 +336,35 @@ def seed_lcgm_all(): seed_lcgm_for_course(**seed_args) +def hotwire_multisite(): + """ + This is a quick and dirty implementation of a single site in multisite mode + """ + params = dict( + name='Foo Organization', + short_name='FOO', + description='Foo org description', + logo=None, + active=True, + ) + org = Organization.objects.create(**params) + if is_multisite(): + org.sites = [get_site()] + org.save() + + for course in CourseOverview.objects.all(): + OrganizationCourse.objects.create(course_id=str(course.id), + organization=org, + active=True) + for user in get_user_model().objects.all(): + # For now, not setting is_amc_admin roles + UserOrganizationMapping.objects.create(user=user, + organization=org, + is_active=True) + + def wipe(): + print('Wiping synthetic data...') clear_non_admin_users() CourseEnrollment.objects.all().delete() StudentModule.objects.all().delete() @@ -326,6 +372,10 @@ def wipe(): CourseDailyMetrics.objects.all().delete() SiteDailyMetrics.objects.all().delete() LearnerCourseGradeMetrics.objects.all().delete() + Organization.objects.all().delete() + OrganizationCourse.objects.all().delete() + if is_multisite(): + UserOrganizationMapping.objects.all().delete() def seed_all(): @@ -335,9 +385,14 @@ def seed_all(): seed_course_overviews() print("seeding users...") seed_users() + print("seeding course enrollments...") seed_course_enrollments() + if is_multisite(): + print("Hotwiring multisite...") + hotwire_multisite() + print("- skipping seeding seed_course_access_roles, broken") # print("seeding course enrollments...") # seed_course_access_roles() diff --git a/devsite/devsite/settings.py b/devsite/devsite/settings.py index a5e5c97e..7a08e138 100644 --- a/devsite/devsite/settings.py +++ b/devsite/devsite/settings.py @@ -9,6 +9,8 @@ import os import sys +import environ + from figures.settings.lms_production import ( update_webpack_loader, update_celerybeat_schedule, @@ -16,6 +18,16 @@ OPENEDX_RELEASE = os.environ.get('OPENEDX_RELEASE', 'HAWTHORN').upper() + +env = environ.Env( + FIGURES_IS_MULTISITE=(bool, False), + SEED_DAYS_BACK=(int, 60), + SEED_NUM_LEARNERS_PER_COURSE=(int, 25) +) + +environ.Env.read_env() + + if OPENEDX_RELEASE == 'GINKGO': MOCKS_DIR = 'mocks/ginkgo' else: @@ -199,9 +211,10 @@ # Included here for completeness in having this settings file match behavior in # the LMS settings CELERYBEAT_SCHEDULE = {} -FEATURES = {} +FEATURES = { + 'FIGURES_IS_MULTISITE': env('FIGURES_IS_MULTISITE') +} -FEATURES = {} # The LMS defines ``ENV_TOKENS`` to load settings declared in `lms.env.json` # We have an empty dict here to replicate behavior in the LMS @@ -214,3 +227,8 @@ INTERNAL_IPS = [ '127.0.0.1' ] + +DEVSITE_SEED = { + 'DAYS_BACK': env('SEED_DAYS_BACK'), + 'NUM_LEARNERS_PER_COURSE': env('SEED_NUM_LEARNERS_PER_COURSE') +} diff --git a/devsite/requirements/ginkgo.txt b/devsite/requirements/ginkgo.txt index 9b4950c1..083c734d 100644 --- a/devsite/requirements/ginkgo.txt +++ b/devsite/requirements/ginkgo.txt @@ -35,6 +35,7 @@ django-webpack-loader==0.4.1 # appsembler/gingko/master users 0.4.1 django-model-utils==2.3.1 +django-environ==0.4.5 jsonfield==1.0.3 # Version used in Ginkgo. Hawthorn uses version 2.0.2 diff --git a/devsite/requirements/hawthorn_community.txt b/devsite/requirements/hawthorn_community.txt index 78ab7589..173bbcac 100644 --- a/devsite/requirements/hawthorn_community.txt +++ b/devsite/requirements/hawthorn_community.txt @@ -33,6 +33,7 @@ django-countries==4.6.1 django-filter==1.0.4 django-webpack-loader==0.6.0 django-model-utils==3.0.0 +django-environ==0.4.5 jsonfield==2.0.2 diff --git a/devsite/requirements/hawthorn_multisite.txt b/devsite/requirements/hawthorn_multisite.txt index 9a448b63..396aa350 100644 --- a/devsite/requirements/hawthorn_multisite.txt +++ b/devsite/requirements/hawthorn_multisite.txt @@ -34,6 +34,7 @@ django-countries==4.6.1 django-filter==1.0.4 django-webpack-loader==0.6.0 django-model-utils==3.0.0 +django-environ==0.4.5 jsonfield==2.0.2