diff --git a/cms/djangoapps/contentstore/views/course.py b/cms/djangoapps/contentstore/views/course.py index 5b5347158ee4..792e3ce8999b 100644 --- a/cms/djangoapps/contentstore/views/course.py +++ b/cms/djangoapps/contentstore/views/course.py @@ -30,7 +30,12 @@ from opaque_keys import InvalidKeyError from opaque_keys.edx.keys import CourseKey from opaque_keys.edx.locator import BlockUsageLocator -from organizations.api import add_organization_course, ensure_organization +from organizations.api import ( + add_organization_course, + ensure_organization, + get_course_organization, + get_organization_institutions +) from organizations.exceptions import InvalidOrganizationException from rest_framework.exceptions import ValidationError @@ -1184,6 +1189,14 @@ def settings_handler(request, course_key_string): # lint-amnesty, pylint: disab 'upgrade_deadline': upgrade_deadline, 'mfe_proctored_exam_settings_url': get_proctored_exam_settings_url(course_module.id), } + + course_org = get_course_organization(course_key) + if course_org: + institutions = get_organization_institutions(course_org) + settings_context.update({'possible_organization_institutions': list(institutions)}) + else: + settings_context.update({'possible_organization_institutions': []}) + if is_prerequisite_courses_enabled(): courses, in_process_course_actions = get_courses_accessible_to_user(request) # exclude current course from the list of available courses diff --git a/cms/static/js/models/settings/course_details.js b/cms/static/js/models/settings/course_details.js index 49531192787b..9b637ba92134 100644 --- a/cms/static/js/models/settings/course_details.js +++ b/cms/static/js/models/settings/course_details.js @@ -37,6 +37,7 @@ define(['backbone', 'underscore', 'gettext', 'js/models/validation_helpers', 'js learning_info: [], instructor_info: {}, self_paced: null, + course_institution: '', revision_number: '' }, diff --git a/cms/static/js/spec/views/settings/main_spec.js b/cms/static/js/spec/views/settings/main_spec.js index aa0360672cec..bb47d9eca732 100644 --- a/cms/static/js/spec/views/settings/main_spec.js +++ b/cms/static/js/spec/views/settings/main_spec.js @@ -51,6 +51,7 @@ define([ instructors: [{name: '', title: '', organization: '', image: '', bio: ''}] }, self_paced: false, + course_institution: '', revision_number: '' }, @@ -199,6 +200,19 @@ define([ ); }); + it('should save institution as part of course details', function() { + var requests = AjaxHelpers.requests(this); + var expectedJson = $.extend(true, {}, modelData, { + course_institution: '' + }); + $('#course-institution').val('').trigger('change'); + expect(this.model.get('course_institution')).toEqual(''); + this.view.saveView(); + AjaxHelpers.expectJsonRequest( + requests, 'POST', urlRoot, expectedJson + ); + }); + it('should not error if about_page_editable is False', function() { var requests = AjaxHelpers.requests(this); // if about_page_editable is false, there is no section.course_details diff --git a/cms/static/js/views/settings/main.js b/cms/static/js/views/settings/main.js index 9e795b2de71d..1acc8a9114c5 100644 --- a/cms/static/js/views/settings/main.js +++ b/cms/static/js/views/settings/main.js @@ -134,6 +134,8 @@ define(['js/views/validation', 'codemirror', 'underscore', 'jquery', 'jquery.ui' pre_requisite_courses = pre_requisite_courses.length > 0 ? pre_requisite_courses : ''; this.$el.find('#' + this.fieldToSelectorMap.pre_requisite_courses).val(pre_requisite_courses); + this.$el.find('#' + this.fieldToSelectorMap.course_institution).val(this.model.get('course_institution')); + if (this.model.get('entrance_exam_enabled') == 'true') { this.$('#' + this.fieldToSelectorMap.entrance_exam_enabled).attr('checked', this.model.get('entrance_exam_enabled')); this.$('.div-grade-requirements').show(); @@ -185,6 +187,7 @@ define(['js/views/validation', 'codemirror', 'underscore', 'jquery', 'jquery.ui' banner_image_asset_path: 'banner-image-url', video_thumbnail_image_asset_path: 'video-thumbnail-image-url', pre_requisite_courses: 'pre-requisite-course', + course_institution: 'course-institution', entrance_exam_enabled: 'entrance-exam-enabled', entrance_exam_minimum_score_pct: 'entrance-exam-minimum-score-pct', course_settings_learning_fields: 'course-settings-learning-fields', @@ -318,6 +321,7 @@ define(['js/views/validation', 'codemirror', 'underscore', 'jquery', 'jquery.ui' case 'course-version': case 'course-revision-number': case 'course-title': + case 'course-institution': case 'course-subtitle': case 'course-duration': case 'course-description': diff --git a/cms/templates/settings.html b/cms/templates/settings.html index ca148fca5894..952ec3e0b43a 100644 --- a/cms/templates/settings.html +++ b/cms/templates/settings.html @@ -395,6 +395,17 @@

${_('Course Details')}

${_("Identify the course revision number here. This is used to assist with identifying what changes have been made for a course. Placeholder indicates a date format (YYYY.MM), however, we don't have to explicity tie this to a date for the number identification.")} +
  • + + + ${_("Institution that is hosting this course run")} + +
  • % endif diff --git a/lms/static/sass/multicourse/_dashboard.scss b/lms/static/sass/multicourse/_dashboard.scss index db099914f9d0..36b34acadbf5 100644 --- a/lms/static/sass/multicourse/_dashboard.scss +++ b/lms/static/sass/multicourse/_dashboard.scss @@ -561,6 +561,75 @@ } } + .program-survey { + box-shadow: 3px 3px 10px -3px grey; + + border: 1px solid theme-color("secondary"); + border-radius: 3px; + padding: 30px; + margin-bottom: 30px; + + .program-survey-header { + @extend %t-title4; + + @include padding-right($baseline/2); + } + + .program-details { + color: $gray; + margin-bottom: lh(); + line-height: 1.3em; + } + + .survey-details-wrapper { + margin-top: 30px; + column-count: 2; + column-width: auto; + + .survey-wrapper { + + margin-right: 50px; + + hr { + @extend .faded-hr-divider-medium; + } + + .survey-title { + @extend %t-title5; + + font-weight: 600; + @include padding-right($baseline/2); + } + + .survey-instructions { + font: -apple-system-short-subheadline !important; + color: $gray-d1; + font-weight: 600; + + @extend %t-title7; + + display: inline-block; + } + + .survey-details { + @extend %t-title7; + + color: $gray-d1; + margin-bottom: lh(); + line-height: 1.3em; + } + + .provide-feedback-btn { + font: -apple-system-short-subheadline !important; + + @extend %btn-primary-blue; + + margin-top: $baseline; + } + } + } + } + // Responsive behavior @include media-breakpoint-down(md) { padding: $baseline; diff --git a/lms/templates/dashboard.html b/lms/templates/dashboard.html index 59c5a77e58e5..a09845b0163a 100644 --- a/lms/templates/dashboard.html +++ b/lms/templates/dashboard.html @@ -148,6 +148,9 @@
    + <%include file='dashboard/_dashboard_program_surveys.html' + args='user=user, course_enrollments=course_enrollments'/> +
    % if display_dashboard_courses: <%include file="learner_dashboard/_dashboard_navigation_courses.html"/> diff --git a/lms/templates/dashboard/_dashboard_program_surveys.html b/lms/templates/dashboard/_dashboard_program_surveys.html new file mode 100644 index 000000000000..1f06c0ae64fd --- /dev/null +++ b/lms/templates/dashboard/_dashboard_program_surveys.html @@ -0,0 +1,92 @@ +<%page expression_filter="h"/> +<%page args='user, course_enrollments'/> +<%! +from openedx.core.djangoapps.content.course_overviews.models import CourseOverview +from organizations.models import OrganizationInstitution +from common.djangoapps.student.models import AnonymousUserId +from custom_reg_form.models import ExtraInfo +%> + +<%namespace name='static' file='../static_content.html'/> + + +<% +show_program_survey = False +course_institution = '' + +for enrollment in course_enrollments: + course_overview = CourseOverview.get_from_id(enrollment.course_id) + if course_overview.org == "CA": + show_program_survey = True + + if course_overview.course_institution: + course_institution = course_overview.course_institution + break +%> + + +% if show_program_survey: + <% + course_institution = OrganizationInstitution.get_by_shortname(short_name=course_overview.course_institution) + + if user.is_anonymous: + anonymous_user_id = user.id + else: + anonymous_user_id = AnonymousUserId.objects.filter(user=user, course_id=None).order_by('-id') + anonymous_user_id = anonymous_user_id[0].anonymous_user_id + + platform_anonymous_user_id_string = "platform_anonymous_user_id=" + (anonymous_user_id or "") + username_string = "platform_username=" + (user.username or "") + platform_fullname = "platform_fullname=" + (user.profile.name or "") + user_email_string = "platform_email=" + (user.email or "") + + org_institution_name_string = "org_institution_name=" + org_institution_shortname_string = "org_institution_short_name=" + org_institution_city_string = "org_institution_city=" + org_institution_state_string = "org_institution_state=" + org_institution_zipcode_string = "org_institution_zipcode=" + if course_institution is not None: + org_institution_name_string += (course_institution.name or "") + org_institution_shortname_string += (course_institution.short_name or "") + org_institution_city_string += (course_institution.city or "") + org_institution_state_string += (course_institution.state or "") + org_institution_zipcode_string += (course_institution.zipcode or "") + + try: + demographic_zipcode = "demographic_zipcode=" + (ExtraInfo.objects.get(user_id=user.id).zipcode or "") + except: + demographic_zipcode = "demographic_zipcode=" + + demographic_country = "demographic_country=" + (str(user.profile.country) or "") + program_name = "program_name=" + "Aviation Mechanic General" + %> + +
    +

    + Aviation Mechanic General Surveys +

    +
    +

    This program of courses equips learners for entry into the FAA mechanic pathway. Upon completion, they gain foundational knowledge in mathematics, aircraft drawings, weight and balance, aircraft materials, processes and tools, physics, electricity, inspection, ground operations, and FAA regulations governing maintenance technician certification and work.

    +
    + +
    +
    +

    Pre-Program

    +
    +

    New Learner: Take this survey upon program entry.

    +

    This will help us understand your career awareness and interest, gauge where you are with FAA General maintenance knowledge and skill confidence, career plans, and demographic information.

    + + Provide Input +
    + +
    +

    Post-Program

    +
    +

    Continuing Learner: Take this survey upon program exit.

    +

    This will help us understand your completion of FAA General maintenance program, career awareness and interest, knowledge and skill confidence, and demographic information.

    + + Provide Feedback +
    +
    +
    +% endif diff --git a/openedx/core/djangoapps/content/course_overviews/migrations/0027_auto_20240909_1523.py b/openedx/core/djangoapps/content/course_overviews/migrations/0027_auto_20240909_1523.py new file mode 100644 index 000000000000..9058b4deae71 --- /dev/null +++ b/openedx/core/djangoapps/content/course_overviews/migrations/0027_auto_20240909_1523.py @@ -0,0 +1,23 @@ +# Generated by Django 3.2.13 on 2024-09-09 15:23 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('course_overviews', '0026_auto_20230525_1917'), + ] + + operations = [ + migrations.AddField( + model_name='courseoverview', + name='course_institution', + field=models.TextField(null=True), + ), + migrations.AddField( + model_name='historicalcourseoverview', + name='course_institution', + field=models.TextField(null=True), + ), + ] diff --git a/openedx/core/djangoapps/content/course_overviews/migrations/0028_merge_20241210_1837.py b/openedx/core/djangoapps/content/course_overviews/migrations/0028_merge_20241210_1837.py new file mode 100644 index 000000000000..ef6e63016cc5 --- /dev/null +++ b/openedx/core/djangoapps/content/course_overviews/migrations/0028_merge_20241210_1837.py @@ -0,0 +1,14 @@ +# Generated by Django 3.2.16 on 2024-12-10 18:37 + +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ('course_overviews', '0027_auto_20240909_1523'), + ('course_overviews', '0027_merge_20240123_1603'), + ] + + operations = [ + ] diff --git a/openedx/core/djangoapps/content/course_overviews/models.py b/openedx/core/djangoapps/content/course_overviews/models.py index 6a8d6b7276c3..2e2047802a87 100644 --- a/openedx/core/djangoapps/content/course_overviews/models.py +++ b/openedx/core/djangoapps/content/course_overviews/models.py @@ -74,6 +74,7 @@ class Meta: display_name = models.TextField(null=True) display_number_with_default = models.TextField() display_org_with_default = models.TextField() + course_institution = models.TextField(null=True) start = models.DateTimeField(null=True) end = models.DateTimeField(null=True) @@ -206,6 +207,7 @@ def _create_or_update(cls, course): # lint-amnesty, pylint: disable=too-many-st course_overview.display_name = display_name course_overview.display_number_with_default = course.display_number_with_default course_overview.display_org_with_default = course.display_org_with_default + course_overview.course_institution = CourseDetails.fetch_about_attribute(course.id, 'course_institution') course_overview.start = start course_overview.end = end diff --git a/openedx/core/djangoapps/content/course_overviews/tests/test_course_overviews.py b/openedx/core/djangoapps/content/course_overviews/tests/test_course_overviews.py index e06064f8f142..5e2a7442c2ab 100644 --- a/openedx/core/djangoapps/content/course_overviews/tests/test_course_overviews.py +++ b/openedx/core/djangoapps/content/course_overviews/tests/test_course_overviews.py @@ -380,7 +380,7 @@ def test_malformed_grading_policy(self): course_overview = CourseOverview._create_or_update(course) # pylint: disable=protected-access assert course_overview.lowest_passing_grade is None - @ddt.data((ModuleStoreEnum.Type.mongo, 5, 5), (ModuleStoreEnum.Type.split, 2, 2)) + @ddt.data((ModuleStoreEnum.Type.mongo, 6, 6), (ModuleStoreEnum.Type.split, 2, 2)) @ddt.unpack def test_versioning(self, modulestore_type, min_mongo_calls, max_mongo_calls): """ diff --git a/openedx/core/djangoapps/models/course_details.py b/openedx/core/djangoapps/models/course_details.py index d02cb21201be..e79ea38205a1 100644 --- a/openedx/core/djangoapps/models/course_details.py +++ b/openedx/core/djangoapps/models/course_details.py @@ -31,6 +31,7 @@ 'entrance_exam_id', 'entrance_exam_minimum_score_pct', 'about_sidebar_html', + 'course_institution', 'revision_number', ] @@ -71,6 +72,7 @@ def __init__(self, org, course_id, run): self.video_thumbnail_image_name = "" self.video_thumbnail_image_asset_path = "" self.pre_requisite_courses = [] # pre-requisite courses + self.course_institution = "" # course institution self.entrance_exam_enabled = "" # is entrance exam enabled self.entrance_exam_id = "" # the content location for the entrance exam self.entrance_exam_minimum_score_pct = settings.FEATURES.get( diff --git a/requirements/edx/base.txt b/requirements/edx/base.txt index 1340882baa2e..f5918405c7d4 100644 --- a/requirements/edx/base.txt +++ b/requirements/edx/base.txt @@ -1149,7 +1149,7 @@ zipp==3.8.0 # via -r ./requirements/edx/private.txt -e git+https://github.com/CUCWD/edx-organizations.git@6.11.1.2-cucwd-nutmeg#egg=edx-organizations==6.11.1 # via -r ./requirements/edx/private.txt --e git+https://github.com/CUCWD/social-auth-backend-bigcommerce.git@0.1.0-maple.1#egg=social-auth-backend-bigcommerce==0.1.0 +-e git+https://github.com/CUCWD/social-auth-backend-bigcommerce.git@0.1.0-maple.3#egg=social-auth-backend-bigcommerce==0.1.0 # via -r ./requirements/edx/private.txt # -e git+https://github.com/CUCWD/edx-ora2.git@4.1.2-nutmeg-cucwd#egg=ora2==4.1.2 -e git+https://github.com/CUCWD/custom-form-app.git@0.1-maple.3-cucwd#egg=custom-form-app==0.1 diff --git a/requirements/edx/development.txt b/requirements/edx/development.txt index effede1f42bb..7b3a7fdf79fb 100644 --- a/requirements/edx/development.txt +++ b/requirements/edx/development.txt @@ -1654,7 +1654,7 @@ zipp==3.8.0 # via -r ./requirements/edx/private.txt -e git+https://github.com/CUCWD/edx-organizations.git@6.11.1.2-cucwd-nutmeg#egg=edx-organizations==6.11.1 # via -r ./requirements/edx/private.txt - -e git+https://github.com/CUCWD/social-auth-backend-bigcommerce.git@0.1.0-maple.1#egg=social-auth-backend-bigcommerce==0.1.0 + -e git+https://github.com/CUCWD/social-auth-backend-bigcommerce.git@0.1.0-maple.3#egg=social-auth-backend-bigcommerce==0.1.0 # via -r ./requirements/edx/private.txt -e git+https://github.com/CUCWD/edx-ora2.git@4.1.2-nutmeg-cucwd#egg=ora2==4.1.2 # via -r ./requirements/edx/private.txt diff --git a/requirements/edx/private.in b/requirements/edx/private.in index e350f0ce4616..b65d2a64fec3 100644 --- a/requirements/edx/private.in +++ b/requirements/edx/private.in @@ -1,12 +1,12 @@ # BigCommerce --e git+https://github.com/CUCWD/bigcommerce-api-python.git@bigcommerce-0.22.2-maple.3#egg=bigcommerce==0.22.2 +-e git+https://github.com/CUCWD/bigcommerce-api-python.git@bigcommerce-0.22.2-nutmeg#egg=bigcommerce==0.22.2 -e git+https://github.com/CUCWD/social-auth-backend-bigcommerce.git@0.1.0-maple.3#egg=social-auth-backend-bigcommerce==0.1.0 # Analytics -e git+https://github.com/CUCWD/figures@0.4.dev17-maple.3#egg=Figures==0.4.dev17 # Organizations (reworked for Figures) --e git+https://github.com/CUCWD/edx-organizations.git@6.10.0-maple.3-cucwd#egg=edx-organizations==6.10.0 +-e git+https://github.com/CUCWD/edx-organizations.git@6.11.1.2-cucwd-nutmeg#egg=edx-organizations==6.11.1 # XBlocks -e git+https://github.com/CUCWD/xblock-qualtrics-survey.git@release/v.2.1.0-maple.3-cucwd#egg=xblock_qualtrics_survey==2.1.0 diff --git a/requirements/edx/private.txt b/requirements/edx/private.txt index d951a4a39e83..069fe0952185 100644 --- a/requirements/edx/private.txt +++ b/requirements/edx/private.txt @@ -4,6 +4,11 @@ # # pip-compile ./requirements/edx/private.in # + +--index-url http://edx.devstack.devpi:3141/root/pypi/+simple/ +--extra-index-url https://pypi.python.org/simple +--trusted-host edx.devstack.devpi + -e git+https://github.com/CUCWD/bigcommerce-api-python.git@bigcommerce-0.22.2-nutmeg#egg=bigcommerce==0.22.2 # via -r ./requirements/edx/private.in -e git+https://github.com/CUCWD/custom-form-app.git@0.1-maple.3-cucwd#egg=custom-form-app==0.1 diff --git a/requirements/edx/testing.txt b/requirements/edx/testing.txt index 4bcc39103887..b36bc5da5b26 100644 --- a/requirements/edx/testing.txt +++ b/requirements/edx/testing.txt @@ -1523,5 +1523,5 @@ zipp==3.8.0 # via -r ./requirements/edx/private.txt -e git+https://github.com/CUCWD/bigcommerce-api-python.git@bigcommerce-0.22.2-maple.1#egg=bigcommerce==0.22.2 # via -r ./requirements/edx/private.in --e git+https://github.com/CUCWD/social-auth-backend-bigcommerce.git@0.1.0-maple.1#egg=social-auth-backend-bigcommerce==0.1.0-maple.1 +-e git+https://github.com/CUCWD/social-auth-backend-bigcommerce.git@0.1.0-maple.3#egg=social-auth-backend-bigcommerce==0.1.0 # via -r ./requirements/edx/private.in \ No newline at end of file