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

Integration of Choose Aerospace pre/post-program survey for Aviation Mechanic General. #234

Merged
merged 6 commits into from
Sep 10, 2024
Merged
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
3 changes: 2 additions & 1 deletion .github/actions/unit-tests/action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,9 @@ runs:

- name: save pytest warnings json file
if: success()
uses: actions/upload-artifact@v2
uses: actions/upload-artifact@v4
with:
name: pytest-warnings-json
path: |
test_root/log/pytest_warnings*.json
overwrite: true
3 changes: 2 additions & 1 deletion .github/workflows/js-tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -73,11 +73,12 @@ jobs:
xvfb-run --auto-servernum ./scripts/all-tests.sh

- name: Save Job Artifacts
uses: actions/upload-artifact@v2
uses: actions/upload-artifact@v4
with:
name: Build-Artifacts
path: |
reports/**/*
test_root/log/*.png
test_root/log/*.log
**/TEST-*.xml
overwrite: true
3 changes: 2 additions & 1 deletion .github/workflows/quality-checks.yml
Original file line number Diff line number Diff line change
Expand Up @@ -70,10 +70,11 @@ jobs:
./scripts/all-tests.sh

- name: Save Job Artifacts
uses: actions/upload-artifact@v2
uses: actions/upload-artifact@v4
with:
name: Build-Artifacts
path: |
**/reports/**/*
test_root/log/**/*.log
*.log
overwrite: true
5 changes: 3 additions & 2 deletions .github/workflows/unit-tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ jobs:
run: sudo chown runner:runner -R .*
- uses: actions/checkout@v2
- name: collect pytest warnings files
uses: actions/download-artifact@v2
uses: actions/download-artifact@v4
with:
name: pytest-warnings-json
path: test_root/log
Expand All @@ -91,10 +91,11 @@ jobs:

- name: save warning report
if: success()
uses: actions/upload-artifact@v2
uses: actions/upload-artifact@v4
with:
name: pytest-warning-report-html
path: |
reports/pytest_warnings/warning_report_all.html
overwrite: true


7 changes: 6 additions & 1 deletion cms/djangoapps/contentstore/views/course.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@
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

Expand Down Expand Up @@ -1184,6 +1184,11 @@ 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)
institutions = get_organization_institutions(course_org)
settings_context.update({'possible_organization_institutions': list(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
Expand Down
1 change: 1 addition & 0 deletions cms/static/js/models/settings/course_details.js
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ define(['backbone', 'underscore', 'gettext', 'js/models/validation_helpers', 'js
learning_info: [],
instructor_info: {},
self_paced: null,
course_institution: '',
revision_number: ''
},

Expand Down
14 changes: 14 additions & 0 deletions cms/static/js/spec/views/settings/main_spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ define([
instructors: [{name: '', title: '', organization: '', image: '', bio: ''}]
},
self_paced: false,
course_institution: '',
revision_number: ''
},

Expand Down Expand Up @@ -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
Expand Down
4 changes: 4 additions & 0 deletions cms/static/js/views/settings/main.js
Original file line number Diff line number Diff line change
Expand Up @@ -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();
Expand Down Expand Up @@ -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',
Expand Down Expand Up @@ -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':
Expand Down
11 changes: 11 additions & 0 deletions cms/templates/settings.html
Original file line number Diff line number Diff line change
Expand Up @@ -395,6 +395,17 @@ <h2 class="title-2">${_('Course Details')}</h2>
<input id="course-revision-number" type="text" placeholder="YYYY.MM">
<span class="tip tip-stacked">${_("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.")}</span>
</li>
<li class="field field-select" id="field-course-institution">
<label for="course-institution">${_("Institution Name")}</label>
<select class="input" id="course-institution">
<option value="">${_("None")}</option>
% for institution in sorted(possible_organization_institutions, key=lambda s: s['name'].lower() if s['name'] is not None else ''):
<option value="${institution['short_name']}">${institution['name']}</option>
% endfor
</select>
<span class="tip tip-inline">${_("Institution that is hosting this course run")}</span>
<button type="submit" class="sr" name="submit" value="submit">${_("set course institution")}</button>
</li>
</ol>
</div>
% endif
Expand Down
69 changes: 69 additions & 0 deletions lms/static/sass/multicourse/_dashboard.scss
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
3 changes: 3 additions & 0 deletions lms/templates/dashboard.html
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,9 @@
<main id="main" aria-label="Content" tabindex="-1">
<div class="dashboard" id="dashboard-main">
<div class="main-container">
<%include file='dashboard/_dashboard_program_surveys.html'
args='user=user, course_enrollments=course_enrollments'/>

<div class="my-courses" id="my-courses">
% if display_dashboard_courses:
<%include file="learner_dashboard/_dashboard_navigation_courses.html"/>
Expand Down
83 changes: 83 additions & 0 deletions lms/templates/dashboard/_dashboard_program_surveys.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
<%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'/>

<!-- Ensure that program surveys are only shown to learners who are enrolled in courses from CA organization -->
<%
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 program surveys are being shown to learner, start building strings to pass organization and institution information to qualtrics -->
% 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=" + (course_institution.name or "")
org_institution_shortname_string = "org_institution_short_name=" + (course_institution.short_name or "")
org_institution_city_string = "org_institution_city=" + (course_institution.city or "")
org_institution_state_string = "org_institution_state=" + (course_institution.state or "")
org_institution_zipcode_string = "org_institution_zipcode=" + (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"
%>

<div class="program-survey">
<h2 class="program-survey-header">
Aviation Mechanic General
</h2>
<div class="program-details">
<p>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.</p>
</div>

<div class="survey-details-wrapper">
<div class="survey-wrapper">
<h2 class="survey-title">Pre-Program Survey</h2>
<hr>
<p class="survey-instructions">Answer this survey prior to taking any course content</p>
<p class="survey-details">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.</p>
<a class="provide-feedback-btn" href="https://clemson.qualtrics.com/jfe/form/SV_3C2RY5TuB0uIZ70?${username_string}&${platform_fullname}&${user_email_string}&${platform_anonymous_user_id_string}&${org_institution_name_string}&${org_institution_shortname_string}&${org_institution_city_string}&${org_institution_state_string}&${org_institution_zipcode_string}&${demographic_zipcode}&${demographic_country}&${program_name}">
Provide Feedback</a>
</div>

<div class="survey-wrapper">
<h2 class="survey-title">Post-Program Survey</h2>
<hr>
<p class="survey-instructions">Answer this survey after you have completed most of this program's courses</p>
<p class="survey-details">This will help us understand your completion of FAA General maintenance program, career awareness and interest, kwowledge and skill confidence, and demographic information.</p>
<a class="provide-feedback-btn" href="https://clemson.qualtrics.com/jfe/form/SV_1Al5SpJgWVv6bFI?${username_string}&${platform_fullname}&${user_email_string}&${platform_anonymous_user_id_string}&${org_institution_name_string}&${org_institution_shortname_string}&${org_institution_city_string}&${org_institution_state_string}&${org_institution_zipcode_string}&${demographic_zipcode}&${demographic_country}&${program_name}">
Provide Feedback</a>
</div>
</div>
</div>
% endif
Original file line number Diff line number Diff line change
@@ -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),
),
]
2 changes: 2 additions & 0 deletions openedx/core/djangoapps/content/course_overviews/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,7 @@ class Meta:
display_name = TextField(null=True)
display_number_with_default = TextField()
display_org_with_default = TextField()
course_institution = TextField(null=True)

start = DateTimeField(null=True)
end = DateTimeField(null=True)
Expand Down Expand Up @@ -204,6 +205,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
Expand Down
2 changes: 2 additions & 0 deletions openedx/core/djangoapps/models/course_details.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
'entrance_exam_id',
'entrance_exam_minimum_score_pct',
'about_sidebar_html',
'course_institution',
'revision_number',
]

Expand Down Expand Up @@ -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(
Expand Down
Loading