Example #1
0
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)
Example #2
0
def get_users_for_site(site):
    if is_multisite():
        users = get_user_model().objects.filter(
            organizations__sites__in=[site])
    else:
        users = get_user_model().objects.all()
    return users
Example #3
0
def seed_all():
    print("\nseeding mock platform models")
    print("----------------------------")
    print("seeding course overviews...")
    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()

    print("seeding student modules...")
    seed_student_modules()
    print("seeding course completions...")
    seed_course_completions()
    print("\nseeding figures metrics models")
    print("------------------------------")
    print(("backfilling course daily metrics for {} days back...".format(
        DAYS_BACK)))
    print("  (this may take serveral minutes)")
    seed_course_daily_metrics()
    print("seeding site daily metrics...")
    seed_site_daily_metrics()
    print('Backfilling Figures EnrollmentData models...')
    backfill_figures_ed()
    def setup(self, db):
        self.date_for = datetime.date(2018, 10, 1)
        self.site = Site.objects.first()
        self.users = [
            UserFactory(date_joined=as_datetime(self.date_for -
                                                datetime.timedelta(days=60)))
            for i in range(0, 3)
        ]
        self.course_overviews = [
            CourseOverviewFactory(
                created=as_datetime(self.date_for -
                                    datetime.timedelta(days=60)))
            for i in range(0, 3)
        ]
        self.cdm_recs = [
            CourseDailyMetricsFactory(site=self.site,
                                      date_for=self.date_for,
                                      **cdm) for cdm in CDM_INPUT_TEST_DATA
        ]
        self.prev_day_sdm = SiteDailyMetricsFactory(site=self.site,
                                                    date_for=prev_day(
                                                        self.date_for),
                                                    **SDM_DATA[1])

        if is_multisite():
            self.organization = OrganizationFactory(sites=[self.site])
            for co in self.course_overviews:
                OrganizationCourseFactory(organization=self.organization,
                                          course_id=str(co.id))
            if organizations_support_sites():
                for user in self.users:
                    UserOrganizationMappingFactory(
                        user=user, organization=self.organization)
Example #5
0
def get_course_enrollments_for_site(site):
    if is_multisite():
        course_enrollments = CourseEnrollment.objects.filter(
            user__organizations__sites__in=[site])
    else:
        course_enrollments = CourseEnrollment.objects.all()
    return course_enrollments
Example #6
0
 def setup(self, db):
     super(TestCoursesIndexViewSet, self).setup(db)
     self.course_overviews = [make_course(**data) for data in COURSE_DATA]
     if is_multisite():
         self.organization = OrganizationFactory(sites=[self.site])
         for co in self.course_overviews:
             OrganizationCourseFactory(organization=self.organization,
                                       course_id=str(co.id))
Example #7
0
def get_student_modules_for_course_in_site(site, course_id):
    if is_multisite():
        site_id = site.id
        check_site = get_site_for_course(course_id)
        if not check_site or site_id != check_site.id:
            CourseNotInSiteError(
                'course "{}"" does not belong to site "{}"'.format(
                    course_id, site_id))
    return StudentModule.objects.filter(course_id=as_course_key(course_id))
Example #8
0
def student_modules_for_course_enrollment(site, course_enrollment):
    """Return a queryset of all `StudentModule` records for a `CourseEnrollment`
    """
    qs = StudentModule.objects.filter(student=course_enrollment.user,
                                      course_id=course_enrollment.course_id)
    if is_multisite():
        # We _could eamake this generic if 'StudentModule' didn't go all snowflake
        # and decided that 'user' had to be 'student'
        qs = qs.filter(student__organizations__sites__in=[site])
    return qs
Example #9
0
def get_organizations_for_site(site):
    """
    TODO: Refactor the functions in this module that make this call
    """
    if is_multisite():
        return organizations.models.Organization.objects.filter(
            sites__in=[site])
    else:

        return organizations.models.Organization.all()
Example #10
0
 def setup(self, db):
     self.date_for = DEFAULT_END_DATE
     self.site = Site.objects.first()
     self.course_count = 4
     self.course_overviews = [CourseOverviewFactory(
         created=self.date_for) for i in range(self.course_count)]
     if is_multisite():
         self.organization = OrganizationFactory(sites=[self.site])
         for co in self.course_overviews:
             OrganizationCourseFactory(organization=self.organization,
                                       course_id=str(co.id))
Example #11
0
def get_courses_for_site(site):
    """Returns the courses accessible by the user on the site

    This function relies on Appsembler's fork of edx-organizations
    """
    if is_multisite():
        course_keys = get_course_keys_for_site(site)
        courses = CourseOverview.objects.filter(id__in=course_keys)
    else:
        courses = CourseOverview.objects.all()
    return courses
Example #12
0
def get_course_keys_for_site(site):
    """

    Developer note: We could improve this function with caching
    Question is which is the most efficient way to know cache expiry

    We may also be able to reduce the queries here to also improve performance
    """
    if is_multisite():
        course_ids = site_course_ids(site)
    else:
        course_ids = CourseOverview.objects.all().values_list('id', flat=True)
    return [as_course_key(cid) for cid in course_ids]
Example #13
0
def site_course_ids(site):
    """Return a list of string course ids for the site
    """
    if is_multisite():
        return organizations.models.OrganizationCourse.objects.filter(
            organization__sites__in=[site]).values_list('course_id', flat=True)
    else:
        # Needs work. See about returning a queryset
        return [
            str(key)
            for key in CourseOverview.objects.all().values_list('id',
                                                                flat=True)
        ]
Example #14
0
def wipe():
    print('Wiping synthetic data...')
    clear_non_admin_users()
    CourseEnrollment.objects.all().delete()
    StudentModule.objects.all().delete()
    CourseOverview.objects.all().delete()
    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 setup(self, db):
     super(TestGeneralCourseDataViewSet, self).setup(db)
     self.users = [make_user(**data) for data in USER_DATA]
     self.course_overviews = [make_course(**data) for data in COURSE_DATA]
     self.expected_result_keys = [
         'course_id', 'course_name', 'course_code','org', 'start_date',
         'end_date', 'self_paced', 'staff', 'metrics',
     ]
     if is_multisite():
         self.organization = OrganizationFactory(sites=[self.site])
         for co in self.course_overviews:
             OrganizationCourseFactory(organization=self.organization,
                                       course_id=str(co.id))
Example #16
0
    def setup(self, db):
        super(TestCourseEnrollmentViewSet, self).setup(db)
        self.special_fields = (
            'create',
            'user',
        )
        self.course_overview = CourseOverviewFactory()
        self.course_enrollments = [
            CourseEnrollmentFactory(course_id=self.course_overview.id)
            for i in range(1, 5)
        ]

        self.sample_course_id = self.course_enrollments[0].course_id

        if is_multisite():
            self.organization = OrganizationFactory(sites=[self.site])
            OrganizationCourseFactory(organization=self.organization,
                                      course_id=str(self.course_overview.id))
Example #17
0
def get_site_for_course(course_id):
    """
    Given a course, return the related site or None

    For standalone mode, will always return the site
    For multisite mode, will return the site if there is a mapping between the
    course and the site. Otherwise `None` is returned

    # Implementation notes

    There should be only one organization per course.
    TODO: Figure out how we want to handle ``DoesNotExist``
    whether to let it raise back up raw or handle with a custom exception

    Figures 0.4.dev7 - This is called in the pipeline and in the serializers
    and views. The pipeline does exception handling. It should only fail for
    sites that have multiple organizations

    For Figures views and serializers, this should only fail when called for
    a specific site that has mulitple orgs
    """
    if is_multisite():
        org_courses = organizations.models.OrganizationCourse.objects.filter(
            course_id=str(course_id))
        if org_courses:
            # Keep until this assumption analyzed
            msg = 'Multiple orgs found for course: {}'
            assert org_courses.count() == 1, msg.format(course_id)
            first_org = org_courses.first().organization
            if hasattr(first_org, 'sites'):
                msg = 'Must have one and only one site. Org is "{}"'
                assert first_org.sites.count() == 1, msg.format(first_org.name)
                site = first_org.sites.first()
            else:
                site = None
        else:
            # We don't want to make assumptions of who our consumers are
            # TODO: handle no organizations found for the course
            site = None
    else:
        # Operating in single site / standalone mode, return the default site
        site = Site.objects.get(id=settings.SITE_ID)
    return site
Example #18
0
def site_certificates(site):
    """
    If we want to be clever, we can abstract a function:
    ```
    def site_user_related(site, model_class):
        if is_multisite():
            return model_class.objects.filter(user__organizations__sites__in=[site])
        else:
            return model_class.objects.all()

    def site_certificates(site):
        return site_user_related(GeneratedCertificate)
    ```
    Then:
    """
    if is_multisite():
        return GeneratedCertificate.objects.filter(
            user__organizations__sites__in=[site])
    else:
        return GeneratedCertificate.objects.all()
 def test_get_search(self, search_term):
     """
     Based on a SEARCH_TERMS data set, we query the endpoint with search
     terms and we compare with the expected results.
     """
     request_path = self.request_path + '?search=' + search_term['term']
     request = APIRequestFactory().get(request_path)
     force_authenticate(request, user=self.staff_user)
     view = self.view_class.as_view({'get': 'list'})
     response = view(request)
     assert response.status_code == 200
     if not is_multisite():
         assert response.data['count'] == search_term['expected_result']
         assert len(response.data['results']) == \
             search_term['expected_result']
     else:
         # the defaul site is example.com so it won't be find users, and
         # that the expected outcome, we should test with different
         # sites expecting different results, but is out of scope for
         # now.
         assert response.data['count'] == 0
         assert len(response.data['results']) == 0
Example #20
0
    def test_get_average_progress(self):
        """
        [John] This test needs work. The function it is testing needs work too
        for testability. We don't want to reproduce the function's behavior, we
        just want to be able to set up the source data with expected output and
        go.
        """
        with mock.patch.dict('figures.helpers.settings.FEATURES',
                             {'FIGURES_IS_MULTISITE': False}):
            assert not is_multisite()
            course_enrollments = CourseEnrollment.objects.filter(
                course_id=self.course_overview.id)
            actual = pipeline_cdm.get_average_progress(
                course_id=self.course_overview.id,
                date_for=self.today,
                course_enrollments=course_enrollments)
            # See tests/mocks/lms/djangoapps/grades/course_grade.py for
            # the source subsection grades that

            # TODO: make the mock data more configurable so we don't have to
            # hardcode the expected value
            assert actual == 0.5
Example #21
0
def test_is_multisite(features, expected):
    """
    Test features work properly for Figures multisite settings
    """
    with mock.patch('figures.helpers.settings.FEATURES', features):
        assert figures_helpers.is_multisite() == expected
Example #22
0
    }

    def mock_metrics(course_enrollment, **_kwargs):
        return mapping[course_enrollment.course_id]

    monkeypatch.setattr(
        'figures.pipeline.enrollment_metrics.get_site_for_course',
        lambda val: SiteFactory())
    monkeypatch.setattr(
        'figures.pipeline.enrollment_metrics.collect_metrics_for_enrollment',
        mock_metrics)
    data = bulk_calculate_course_progress_data(course_overview.id)
    assert data['average_progress'] == 0.5


@pytest.mark.skipif(not is_multisite(),
                    reason='Standalone always returns a site')
@pytest.mark.django_db
def test_bulk_calculate_course_progress_unlinked_course_error(db, monkeypatch):
    """Tests 'bulk_calculate_course_progress_data' function

    The function under test iterates over a set of course enrollment records,
    So we create a couple of records to iterate over and mock the collect
    function
    """
    course_overview = CourseOverviewFactory()
    course_enrollments = [
        CourseEnrollmentFactory(course_id=course_overview.id) for i in range(2)
    ]
    mapping = {
        ce.course_id:
Example #23
0
)
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 figures.sites import get_organizations_for_site

from devsite import cans
from six.moves import range

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 = 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'

Example #24
0
def get_user_ids_for_site(site):
    if is_multisite():
        user_ids = get_users_for_site(site).values_list('id', flat=True)
    else:
        user_ids = get_user_model().objects.all().values_list('id', flat=True)
    return user_ids